스택 피보팅이란 특정 영역에 값을 쓸 수 있거나 값이 있는 경우 SFP를 족쳐서 스택을 옮기고 해당 부분의 코드를 실행하는 기법이다.
leave_ret 을 이용한 stack pivoting을 하기 위한 전제 조건
- 페이로드가 저장되어 있는 영역이 존재할 경우 ret까지만 overflow 가 발생
- 페이로드가 저장되어 있는 영역이 없는 경우 입력함수 + leave_ret을 넣을 수 있는 만큼 overflow 발생
일반적으로 stack pivoting을 사용하는 경우
- overflow가 많이 나지 않ㄴ는 경우
- main으로 돌아갈 수 없는 경우(seccomp 등)
익스 시나리오
- SFP 부분에 실행을 원하는 주소 -8을 넣는다. (chain을 할 경우 예제 참고)
- 입력 함수를 RTL로 호출해서 bss영역에 값을 입력 받도록 한다.
- 다음 실행할 명령의 주소에 leave_ret 가젯을 넣는다.
아래 참조
https://jiravvit.tistory.com/entry/Stack-Pivoting-%EC%8A%A4%ED%83%9D-%ED%94%BC%EB%B4%87%ED%8C%85
먼저 SFP에 bss + 0x300을 넣고, read를 호출해서 bss + 0x300에 값을 입력받도록 해준 후에 leave_ret을 실행하는 페이로드를 전송한다.
leave_ret 가젯을 이용하게 되면 변화가 생기는데, leave와 ret의 의미는 다음과 같다.
leave: mov esp, ebp + pop ebp
ret: pop eip + jmp eip
처음에 main 함수에서 leave ret을 진행하면서 pop ebp 명령을 수행하는데 이때 ebp 값이 우리가 설정한 값으로 바뀌게 된다.
근데 ret에 leave ret을 넣음으로서 esp 값이 우리가 설정한 위치로 바뀌게 되며 push pop 명령은 esp 기준으로 실행이 되기 때문에 pop eip + jmp eip 명령을 진행하며 우리가 설정한 영역의 명령이 실행된다.
단 pop ebp 루틴때문에 우리가 설정한 영역의 -8 위치가 실행되는 것인데, chain을 걸려면 ebp 값을 변경하는 것이 핵심이기 때문에 페이로드의 첫 부분엔 다음 실행할 영역의 주소를 넣어준다. (다음 실행할 명령의 주소가 아니라 영역이다!)
파란색 글씨로 작성한 부분의 이해만 된다면 끝이다. 익스플로잇 코드와 연관지어서 보길 권장한다.
아무튼 첫 페이로드에서 sfp를 바꾸고 바꾼 위치에 입력을 받으면서 ret를 leave_ret으로 변경한다면 원하는 위치로 이동하게 되고 그 첫 부분엔 다음 실행할 영역의 주소를 쓰는데 예제 코드에선 bss + 0x400으로 하였다.
그 다음엔 leak을 진행하고, read 함수를 통해 다음 실행할 영역에 입력을 받고 다시 leave ret를 진행하고 마지막엔 system("/bin/sh")를 실행하는 구조이다.
왜 bss 영역을 바로 쓰지 않고 bss+0x300 / bss+0x400과 같은 주소를 쓰는지 궁금한 사람이 있을 꺼라고 생각한다.
그 이유는 라이브러리 함수들이 해당 함수를 호출할 때 영역을 많이 사용하기 때문이다. 해당 바이너리에서 vmmap을 한 결과의 일부는 다음과 같다.
0x400000 0x401000 r-xp 1000
0x600000 0x601000 r--p 1000
0x601000 0x602000 rw-p 1000
이 중 세번째 영역이 bss 영역이고 bss 영역에 w 권한이 있지만 두 번째 영역엔 w 권한이 없는 것을 확인할 수 있다.
라이브러리 함수를 진행하면서 영역을 많이 사용하게 되면 w 권한이 없는 0x600fff 이하의 영역을 사용하면서 함수 진행 도중에 터진다. 그래서 넉넉하게 0x300, 0x400을 사용하는 것이다.
'Pwnable > Tech' 카테고리의 다른 글
_IO_FILE AAR (0) | 2023.02.18 |
---|---|
no longer existing hook (0) | 2023.02.18 |
FSB 란 무엇인가 (0) | 2023.02.18 |
house of lore 간단 설명 (0) | 2023.01.30 |
OOB - Out of Bounds (0) | 2022.02.14 |