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

3 comments:

  1. An aside on yet another method to decode and verify shellcode: Thanks to a pointer from my cube-neighbor here at work, I now have this in my bash aliases file:

    function disasm {
    echo -ne $1 | ndisasm -u -
    }

    So now I can do things like:

    todb@mazikeen:~$ disasm "\xbb\x00\x00\x00\x00\xb8\x01\x00\x00\x00\xcd\x80"
    00000000 BB00000000 mov ebx,0x0
    00000005 B801000000 mov eax,0x1
    0000000A CD80 int 0x80

    This is super-handy for spot-checking shellcode without all that bothersome compiling and objdumping.

    ReplyDelete
  2. The example in the book didn't work for me saying seg fault i realized adding -z execstack to gcc helps because newer versions of linux make parts not executable so the full gcc will look like this below
    gcc -fno-stack-protector -z execstack -static wack.c -o wack

    ReplyDelete