write-up/pwnable

[ftz] level 17: king poetic

여니두 2019. 8. 26.

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에 셸코드를 올렸다.

 

getenv.c

* 페이로드

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

댓글