Sign in to follow this  

Smashing the stack

This topic is 4595 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I know it's not the best thing to do, but I'm trying to learn about buffer overflows and how they occur. I'm reading Aleph One's famous article, but his code isn't working. I'm putting the code into a .c, then I'm using cygwin to gcc it. The first example is:
void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   ret = buffer1 + 12;
   (*ret) += 8;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}

What this should do is skip past the 8 bytes in buffer1 (even though it's 5, it's 2 words = 8 bytes) then skip past the 4 bytes of the stack point, to reach the return value. It then adds 8, which should allow us to return past the assignment statement and thus x should be 0. I copy and paste that exact code into a .c file with jEdit, and then I compile with cygwin. $ gcc -o exploit.exe exploitable.c -static $ ./exploit.exe 1 $ What gives??

Share this post


Link to post
Share on other sites
That code makes at least around 5 assumptions about how the compiler has decided to lay out the memory of the stack of the program, none of which are guaranteed to even be consistant within a single program. Let's just say, the official behavior of your program according to the standard is simply "undefined" :-).

Sorry I can't be of more help...

Share this post


Link to post
Share on other sites
Many compilers/OSes do not allocate the memory in bytes, but in chunks. For example, some will give you an entire page (typically 4kb).
Usually the compiler puts all the variables one after another, so if you have something like:

char str[16];
int some_int;

str[16]='a';

then the 'a' character might affect some_int;
However, there are really no rules on how the compiler allocates it's stack. It depends on compiler, version, optimizations, and so on.

Share this post


Link to post
Share on other sites
Hmm... well that sucks =)

Regardless of the compiler, isn't there a general structure to the stack after a function call? If I just declare one local array of characters on the stack, then isn't there any way to flow into the return code pointer?

How would I figure out what format my compiler was using?

Share this post


Link to post
Share on other sites
The compiler is free to optimise out buffer2 since it is never actually used.
You could just do this:
void myNaughtyFunction(int offset1, int offset2) {
int *address;
address = (int*)(&address) + offset1;
*address += offest2;
}
Now you compile it and look at the assembly to see what the compiler did. Without changing the function you now simply pass it the right offsets to do what you want.

Share this post


Link to post
Share on other sites
Quote:
Original post by sirSolarius
Hmm... well that sucks =)

Regardless of the compiler, isn't there a general structure to the stack after a function call? If I just declare one local array of characters on the stack, then isn't there any way to flow into the return code pointer?

How would I figure out what format my compiler was using?


There is general structure, but you're looking for specifics. Depending on the calling convention of the function (cdecl is the default), the stack will have variables on the stack in a particular order upon function entry. Unless the compiler can remove the function call entirely - so you have to do something in the function with the variables passed-in or make a virtual function call to prevent optimizations. The next thing, you probably ought to compile a 'release' build, where you define NDEBUG (-DNDEBUG) and enable basic optimizations (e.g. -O2). NDEBUG is particularily important under Windows using MSVC, but it also affects gcc is less severe ways. MSVC does a lot of additional things for a 'debug' build, I'm not certain how much more gcc does (-O2 will make a difference though).

Share this post


Link to post
Share on other sites
Won't release mode optimize a bunch of stuff for me? I'd think that I want the compiler to read things as literally as possible.

I can't believe that it's so hard to just find a return pointer... isn't there some way to figure it out?

Share this post


Link to post
Share on other sites
Quote:

Won't release mode optimize a bunch of stuff for me? I'd think that I want the compiler to read things as literally as possible.

Well, think of it this way: debug mode will probably add more than release mode will take off. Besides, compiling in release mode ensures the most authentic exploit experience ;)
Quote:

I can't believe that it's so hard to just find a return pointer... isn't there some way to figure it out?

First of all, get rid of that two buffer nonsense--one buffer is hard enough.

Usually, the exact length of an array on the stack is actually greater than the actual array; most of the time it's padded to 4 bytes or something. In a real exploit situation, you could do it in a few ways:
1) experiment with the length of the exploit string until you find the exact position of the return value using the outputted access violation for guidance, or
2) get the compiler to output the source code translated into assembly, in the case of gcc, it would look something like this: gcc -S -o exploit.s exploitable.c. (you could also disassemble the executable, but this is somewhat easier because of the comments left in by the compiler)

Here's a base program you can start with, if you like:


#include <stdio.h>

int main() {
char buffer[1000];
scanf("%s", buffer);
puts(buffer);
return 0;
}



I can't go into much more detail than this, but, basically, what you do is write another program to repeat a distinguishable pair of letters/numbers, e.g. "AB", a given number of times and pipe that to the above program. Once you have the exact location of the return value, it gets a bit more complex. If all you wanted to do was generate an access violation, then the above should suffice. Otherwise, you'll probably want to look into a more in depth guide on the net.

Share this post


Link to post
Share on other sites

This topic is 4595 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this