Wednesday, June 17, 2009

Chapter 3, "Spawning a Shell," pp 51-58

Just a quick note on the assembly listings that start on page 51: I've found this script to be more useful than the stock ASM syntax highlighting that ships with vim.

Also as an aside, the man pages for execve (and other system calls) aren't installed on Ubuntu by default. You'll need to sudo apt-get install manpages-dev to get the goods, then man 2 execve to play along at home.

I'm not quite sure what the purpose is of the "practice" shellcode note on page 54 is useful for; since we're stuck with fixed addresses in the original disassembly, it's pretty pointless to write up the corresponding shellcode without using the JMP + POP ESI tricks discussed on the following page.

And finally, the shellcode invocation method for execve2.c (page 58) will need to be replaced with the phiral version, as discussed for wack.c:

int main()
{
int (*ret)();
ret = (int (*)())shellcode;
(int)(*ret)();
}

With that minor change, the injectable shellcode works perfectly well. And with that, we've come to the end of chapter 3. Next up, format string bugs!

Tuesday, June 16, 2009

Chapter 3, "Injectable Shellcode," page 49

After the run through of wack.c, a couple pages are devoted to the notion of nuking your nulls and shortening your shellcode. However, there's a bit of a problem with the technique described for dropping nulls from the mov statement. The author suggests replacing "mov eax,1" (which has lots of nulls since EAX is a 32-bit register) with "mov al,1", seeing how AL represents only the lower eight bits of EAX.

Although this does achieve the effect of stripping nulls off the shellcode, it also leaves the other three bytes alone. Without some register housekeeping, trouble is afoot:

todb@mazikeen:~/dev/sc/code/ch03$ gcc -static -g -o wack2 wack2.c
todb@mazikeen:~/dev/sc/code/ch03$ ./wack2
Segmentation fault (core dumped)

Ew. Instead, make sure that you zero out not only EBX, but EAX as well:

char shellcode[] =
"\x31\xdb" // xor eax,eax
"\x31\xc0" // xor ebx,ebx
"\xb0\x01" // mov al,1
"\xcd\x80"; // int 0x80
This takes care of whatever was lingering around in both EAX and EBX before you started, and only costs a couple more (non-null) bytes.

Wednesday, June 10, 2009

Chapter 3, "Shellcode," and a slightly buggy wack.c on page 46

On page 46, the question is posed, "how do you really know your shellcode is getting run?" The solution presented is to use strace. The example wack.c in the text is dutifully strace'd to exit(0) at the bottom of the page.

Sadly, this is not the case for me. Behold:

todb@mazikeen:~/dev/sc/ch03$ strace ./wack
execve("./wack", ["./wack"], [/* 45 vars */]) = 0
uname({sys="Linux", node="mazikeen", ...}) = 0
brk(0) = 0x8c85000
brk(0x8c85cb0) = 0x8c85cb0
set_thread_area({entry_number:-1 -> 6, base_addr:0x8c85830, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
brk(0x8ca6cb0) = 0x8ca6cb0
brk(0x8ca7000) = 0x8ca7000
exit_group(135016456) = ?
Process 9231 detached
So, I'm getting an exit_group(some number) getting called instead of my lovingly hand-coded exit(0). At first, I assumed that gcc is doing some kind of compile-time fixup on my shellcode. However, after Googling around for some ideas on what's up with this, I came across Introduction to Writing Shellcode, which is nearly identical to the exercise here in Chapter 3, except the type casting the shellcode[] arry as a function is approached somewhat differently -- and has some very useful comments for a C n00b like myself.

Also, the phiral.net textfile has a handy pointer to the gdb method of verifying shellcode. Here's my screen dump of that:

todb@mazikeen:~/dev/sc/ch03$ gcc -g wack.c -o wack
todb@mazikeen:~/dev/sc/ch03$ gdb wack
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) disas shellcode
Dump of assembler code for function shellcode:
0x0804a010 : mov $0x0,%ebx
0x0804a015 : mov $0x1,%eax
0x0804a01a : int $0x80
0x0804a01c : add %al,(%eax)
End of assembler dump.
(gdb)
This is handy, because I was getting the same results from the disas shellcode as I was with the more broken version -- which isn't surprising, since my shellcode was, in fact, sound, I just wasn't invoking it right.

Here's the fixed wack.c, in case the phiral.net text goes away:

todb@mazikeen:~/dev/sc/ch03$ cat wack.c
char shellcode[] = "\xbb\x00\x00\x00\x00"
"\xb8\x01\x00\x00\x00"
"\xcd\x80";

int main()
{
int (*ret)();
ret = (int (*)())shellcode;
(int)(*ret)();
}
And here's my much more satisfying strace:

todb@mazikeen:~/dev/sc/ch03$ gcc -static wack.c -o wack
todb@mazikeen:~/dev/sc/ch03$ strace ./wack
execve("./wack", ["./wack"], [/* 45 vars */]) = 0
uname({sys="Linux", node="mazikeen", ...}) = 0
brk(0) = 0x919d000
brk(0x919dcb0) = 0x919dcb0
set_thread_area({entry_number:-1 -> 6, base_addr:0x919d830, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
brk(0x91becb0) = 0x91becb0
brk(0x91bf000) = 0x91bf000
_exit(0) = ?
Process 10218 detached