[ftz] level 17: king poetic
17_함수 포인터 변조(2)
√ 문제 분석
- lev16과 다른 점: 소스코드 안에 shell() 함수가 없다.
- 키보드 입력을 48byte로 제한하여 BOF를 차단했
- RET까지 덮으려면 60byte까지 덮어야 함.
>> 배시셸을 실행하는 셸코드를 만들어 lev16과 똑같이 함수 포인터가 가리키는 주소를 변조하자
: 메모리에 셸코드를 올린 후 call 함수 포인터가 가리키는 함수의 주소를 셸코드의 주소로 바꾸자.
√ gdb로 소스코드 분석
- stack에 공간을 56byte 확보하였다.
- ebp-16에 0x8048490(printit 함수 주소) 대입
>> fgets(ebp-56, 0x30, 0x804967c)
= fgets(buf, 48, stdin)
>> setreuid(3098, 3098)
>> call() -> printit() 함수 호출
buf[20]: [ebp-56] |
dummy[20] |
*call()[4]: [ebp-16] (0x8048490) |
crap[4] |
dummy[8] |
SFP |
RET |
- 함수 포인터도 포인터이므로, void 타입의 포인터 변수여도 int 타입과 동일한 4byte 구조이다.
- dummy의 사이사이 위치와 각각의 크기는 chk_distance.c 를 이용해 계산하였음.
- *call() 함수 포인터는 printit() 함수의 시작 주소로 초기화 되어있음.
>> BOF 시켜 *call() 함수 포인터에 셸코드의 시작주소를 덮어씌우자.
** 포인터는 포인터일 뿐!
: int, char, double, 함수 포인터 등 다양한 포인터가 있지만, 이것들은 모두 포인터일 뿐이다.
: sizeof() 함수를 이용해 포인터의 크기를 확인하면 모두 4byte 공간을 차지하는 변수일 뿐이다.
√ 공격
방법 1)
buf에 셸코드를 올리고, buf의 시작 주소를 call() 함수 포인터에 덮어씌우자.
- buf의 시작 주소: 0xbfffdb20
* 페이로드
NOP[16] + SHELL CODE[24]+ "buf의 시작 주소"
>> stack 주소가 조금씩 바뀌는 관계로 실패
방법 2)
환경변수에 셸코드를 올리고, 그 환경변수의 주소를 알아내어 call() 함수 포인터가 그 주소를 가리키게 하자.
- 환경변수 SHELL에 셸코드를 올렸다.
* 페이로드
NOP[40] + "환경변수 주소"
Level 18 Password = why did you do it
* 정리
lev15~17은 포인터를 잘못 사용했을 때 우회할 수 있는 방법이다.
'write-up > pwnable' 카테고리의 다른 글
[ftz] level 19: swimming in pink (0) | 2019.08.27 |
---|---|
[ftz] level 18: why did you do it (0) | 2019.08.27 |
[ftz] level 16: about to cause mass (0) | 2019.08.24 |
[ftz] level 15: guess what (0) | 2019.08.24 |
[ftz] level 14: what that nigga want? (0) | 2019.08.23 |
댓글