Buffer overflow attacks bypassing DEP (NX/XD bits) – part 1 : Simple Call

· June 4, 2005

Premise

All you read here (and its sequel posts) is just a concrete implementation of many proposed ways to exploit buffer overflows to execute arbitrary code; in particular this post will focus on bypassing the DEP (Data Execution Prevention) which uses the NX bit on AMD chips and XD bit on Intel chips to prevent code execution from data segments (NX and XD are, as far as I know, the same bit with two different names so that Intel’s pride was satisfied – just like amd64 techology is also called x86-64, x64, aa64 and em64t – wasn’t a name enough ? :|) .

The DEP is really a needed feature which was incredibly missing from x86 (ia32 ;)) processors. It is a good protection which effectively makes harder to write exploits for unchecked buffers bugs. However it doesn’t make them impossible – it just makes them slightly harder to do.

If this post (and its sequels) strikes you down in fear, then remember to update all your applications to the latest versions and check them consistently for bugfixes repairing buffer overflows, and if you are a programmer, triple check your code to look for these bugs.

Please, note also that nothing in these posts is an original idea, since these methods are discussed in theory in many sites around the internet. What was missing was a proof of concept of those exploits, which you can find here.

The false sense of security

There is one mortal sin in computer security (or by the way, in any kind of security) that is feeling safe. It’s just a variation of pride to be true, but it’s very deadly. Blindly trusting a protection technology is an extreme error.

So, the question is : how much should I trust DEP ?
The answer is simple. Think of DEP as the airbag or the ABS in your car. You don’t stop giving precedence at crossroads or respecting speed limits just because you have the airbag. And you don’t drive at 200 km/h in the snow just because you have the ABS.
DEP works just in the same way : it will save your life an incredible number of times, but don’t rely on it for your security. Updates and patches are the way, DEP is just the last chance method to reduce the damage.

How a buffer overflow exploit works

You can find a number of documents on the web about how a buffer overflow exploit works and there is an expecially good one on wikipedia.
Another MSDN article explains it so well. Note that all the tests done here, are on an host compiled without the /GS switch. Take into account, however, that the /GS switch does NOT save you when the buffer overrun is not hitting a ret address (for example when it attacks the vtable of a C++ object allocated on the stack) and, above all, that you don’t know which applications on your computer have been compiled with the /GS switch enabled!
Note, however, that the /GS switch combined with DEP effectively hugely reduce the chances of an attack; with them combined a standard method (like trampling the ret address) cannot be used anymore and the only chance to exploit a buffer is dependent on the running code (for example trampling parameters or a vtable-ptr). [Of course this is what I'm aware of - there is always a chanche that a smarter person will find a way to do that tomorrow, if it isn't alread discovered, of course].

How does DEP work ?

DEP works using a special flag (the famous NX / XD bit) which tags pages of memory dedicated to data as “Non eXecutable” (or to be fair with “eXecution Disabled”). If the processor attempt to execute code from a NX page an access violation exception is raised and usually the program crashes. Note that this means that buffer overflows, even on DEP active systems, result at least in a denyal of service.

So, how can one execute arbitrary code when the only thing he can do is changing the stack and he cannot execute the stack ?
Simple : he can use the stack to execute the code he’s interested to, performing some return address magic.

Target System

The experiments are done on an Athlon64 3000+ Winchester running Windows XP SP2. The reality is that buffer overflows will always be there as long as data and return address are put on the same stack and the stack grows down (note that neither having two stacks nor having the stack growing up really solves 100% the problem, however in both cases it gets really hard to make a working exploit – if I were someone more important I would probably have spent a couple of the registers of an amd64 chip to get a second stack for locals.

Writing the host for our experiments

We don’t want to exploit an existing bug in a common program here, but only demonstrate that DEP doesn’t solve the problem. So we’ll make a very stupid program with a big buffer overflow bug. Also we don’t want to learn how to become professional crackers or whatever, we just want to do some experiments; so we’ll use some “unfair” method to exploit the program, like stepping on its code to know the expected value of ESP in a given line of code, or reading the map file to know the address of system functions.

The host program is simple : it opens a “known” file which should be no greater than 1KB, it reads it all in memory and calculates an useless signed integer average of its bytes (not that it matters, but what it does is kinda wrong). The code is really something terrible (more bugs than instructions) but it does its dirty work and is simple enough to be easily exploited ;)

Here is the code :


void CalcAverage()
{
char buffer[1024];
FILE* F;
int size;

F = fopen(“G:\\prg\\BufferHacker\\Release\\hack1″, “rb”);
fseek(F, 0, SEEK_END);
size = ftell(F);
fseek(F, 0, SEEK_SET);
fread(buffer, 1, size, F);
fclose(F);

int iAverage = 0;
for (int i = 0; i < size; i++)
{
iAverage+=buffer[i];
}
iAverage /= size;

printf(“The average is %d\n”, iAverage);
}

int main(int argc, char* argv[])
{
int wastesomestackspace[1024];
CalcAverage();
return 0;
}
The first exploit – executing an existing code

The first exploit is simple, and it consists in calling an already existing function with arbitrary parameters. Don’t underestimate the power of this exploit – the more complex a program and the APIs it uses, the more powerful this exploits get. Also take into account that your database server needs just a single call to some SqlExec(“DROP TABLE …”) to be deadly :(.

This exploit prints “Success! ; )” on the screen, using the standard printf function.
Here is how the stack changes before and after the overflow :

Let’s walk the steps :

  1. We have to replace the return address of the current function with the entry address of the function we want to call (in this case printf).
  2. We have to invent a return code the cpu will jump to when the printf returns (that is the printf return address). This time we use the return address of the main function, so we’ll jump into the CRT (C runtime library) immediately after the printf call. Note that this will work since the presence of argc, argv and the main return address has created a small buffer (12 bytes) in the stack where we can write without destroying the stack of the CRT (we write 8 bytes under the return code).
  3. In the end we have to place in the stack the address of our string, which incidentally is the address of the buffer[] array.

The exploit is a data file, of course, however here I paste the C code which creates that data file. Here you can look at the data file and the result :)


FILE* F = fopen("G:\\prg\\BufferHacker\\Release\\hack1", "wb");

char buf[1 < < 12];
int _stack = 0x0013FAE4; // esp value at beginning of 1024kb
int aprintf = 0×00401090; // address of printf function
int rettomain = 0×00401633; // address of return to crt

sprintf(buf, “Success! ; )\n”);

fwrite(buf, 1024, 1, F);

fwrite(&aprintf, 4, 1, F);//retaddress
fwrite(&rettomain, 4, 1, F);
fwrite(&_stack, 4, 1, F);

fclose(F);
In the next post we’ll see how to make even more powerful exploits, completely bypassing DEP protections.

links to other posts of this serie
Buffer overflow attacks bypassing DEP (NX/XD bits) – part 1 : Simple Call
Buffer overflow attacks bypassing DEP (NX/XD bits) – part 2 : Code injection