views:

135

answers:

4

Good day everyone! I’m trying to understand how buffer overflow works. I’m doing this for my project in a computer security course I’m taking. Right now, I’m in the process of determining the address of the function’s return address which I’m supposed to change to perform a buffer overflow attack. I’ve written a simple program based from an example I’ve read in the internet. What this program does is it creates an integer pointer that will be made to point to the address of the function return address in the stack. To do this, (granted I understand how a function/program variables get organized in the stack), I add 8 to the buffer variable’ address and set it as the value of ret. I’m not doing anything here that would change the address contained in the location of func’s return address.

UPDATE: I've modified the program a bit, to it prints the address of func's parameter a in the stack. As you can see, the distance between a nd buffer is about 8 bytes, so that woyuld probably mean, based from the stack layout, that saved FP and old EIP (func return address) is in between.. is that right?

here's the program: (The COMPLETE program In question, WORKING!)

void func( int a){
    char buffer[3];

    int *ret;

    ret = buffer + 11; // this is the configuratio which made the whole program works... This now points to the address containing func's return address

     printf (" address of a is %d\n", &a);

    printf ("address of buffer is %x\n", buffer);

    printf ("address of ret is %x\n", ret);

    printf ("value of ret is %x\n", (*ret));

}

void main(){
    int num;

    num = 0;

    func(num);

    num = 1;

    printf("Num now is %d", num);
}

Output of the program when gets excecuted:

alt text

As you can see, I’m printing the address of the variables buffer and ret. I’ve added an additional statement printing the value of the ret variable (supposed location of func return address, so this should print the address of the next instruction which will get executed after func returns from execution).

Here is the dump which shows the supposed address of the instruction to be executed after func returns. (Underlined in green) As you can see, that value is way different from the value printed contained in the variable ret.

alt text

My question is, why are they different? (of course in the assumption that what I’ve done are all right). Else, what have I done wrong? Is my understanding of the program’s runtime stack wrong? Please, help me understand this. My project is due nextweek and I’ve barely touched it yet. I’m sorry if I’m being demanding, I badly need your help.

UPDATE:

Hi Guys, I've already solved the problem. It turned out that a lousy formatting of my outputs (printf) mwas actually the cause of the confusion on my part.

+1  A: 

First off, notice that the address of buffer is an odd number 0xbffffd51 and then you add 8 to it to get 0xbffffd59. I would be quite surprised if the return address on the stack was not aligned to a four byte address.

Depending on the compiler, exactly how the stack frame is layed out could vary (for example, even though buffer is first in the source code, the compiler could put ret higher in the stack), so you may need to experiment with your values. I would do a couple of things:

  1. Change buffer to be 4 bytes.
  2. Experiment with different offsets. I have a feeling that you may need to look 12 bytes or even 16 bytes up to find your return address.
R Samuel Klatchko
yeah, from what i've understand the layout of stack should like this when func gets called, from higher mem address to lower mem address, |nums value| ret | sfp (ebp) | buffer | , so the distance between buffer and ret in the stack, should be like 8,
ultrajohn
@ultrajohn - and yet it is not 8 so your understanding is incorrect. Did you try the changes I recommended?
R Samuel Klatchko
yeah, i've tried using different offsets, and i was not able to get the correct value of the address, in one case, the retrieved value is correct for its first 7 digits from the left, except the last example: if the correct value is 0808425d, i'ce encountered a value in one particular offset that looks like this, 808425d1, and i don't why?
ultrajohn
+1  A: 

For the following program

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

   return 0;
}

The stack layout is basically the following:

 
       -------------   
           arg n 
       ------------- 
         .........
       -------------   
0x1010     arg 0 
       ------------- 
0x100C  ret address
       =============
0x1008     old fp 
       -------------
0x1004     v[1]
       -------------
0x1000     v[0]
       -------------

You can find out main's return address using v + 3.

Assuming the addresses placed on the left side of the stack, v has address 0x1000 , return adress has the address (v + 3 => 0x1000 + 4 * 3 = 0x100C)

Daniel Băluţă
is that on the assumption that that, v takes 2 bytes, old fp takes 1 byte ?
ultrajohn
v takes 4 bytes, old fd takes 4 bytes.
Daniel Băluţă
but why are you adding only 3? ?? am confused, shouldn't you add 8 instead?
ultrajohn
adding 3 doesn't mean add 3 bytes starting from v. v + 3 means go to the 3rd integer starting from v, which in terms of addresses means go to address v + 3 * sizeof(int) => v + 3 * 4 => v + 12
Daniel Băluţă
oh, i think that's what i've been missing... so does that mean, that in my code, instead of adding 8, i should add only 3 to ret?thanks!
ultrajohn
your ret pointer it is stored exactly where v[1] is stored in my stack drawing. So if you add 2 it should work.
Daniel Băluţă
ok, i'll try that, :) tnx
ultrajohn
A: 

Of course, you can't modify the original num unless you pass the pointer to it; so in the main, num first is 0, then it is 1, and it is never really modified by the func. Address of a (&a) in func is the address of the local copy (by value) of the argument, likely an address on the stack in most cases. And what would ret point to? You have a 3 char buffer, and you get the address beyond it; you must consider it now a pointer to garbage, even though likely your pointing to something "interesting", according to how local variables are "organized" in memory. So you can't be 100% sure it points to the return address indeed. You're assuming the following:

0  4 bytes (for char, assuming 4bytes alignment)
4  4 bytes (for whatever, maybe argument)
8  4 bytes (return address)

And it depends. It depends on the architecture; it depends on how the compiler "translate" the code of the function. Let us imagine x86. The following is a reasonable way of doing func

func:
  push ebp  ; save some regs...
  push eax  ; or with pusha?
  mov ebp, esp
  push 0   ; for char a[3]
  mov eax, ebp
  add eax, 4  ; -4 + 8
  push eax ; for int *ret
  ; -4(ebp) gives a
  ; -8(ebp) gives int *ret
  ; so ebp-4 is the pointer to a, we
  ; add 8, to obtain ebp+4, which points
  ; to saved ebp... missing the ret ptr
  ; (other code...)
  mov esp, ebp
  pop eax ; or with popa?
  pop ebp
  ret

and what if the saved regs are more? what if the order of char a[4] and int *ret is swapped? How do you can know? You can't assume anything, unless, you write the code yourself directly in asm, in this case you can controll exactly what's happening. Otherwise, a working C code to do what you want would work by chance...

ShinTakezou
I wrote a[n], or char *a ... instead of char buffer... mixed up a little bit with a (int arg)/buffer, and int *ret, basically forgot the argument... no matter: the same reasoning still works: i.e. you can't assume the layout of the on-stack stuffs will be exactly that on different compilers (and of course, on different cpus, but this case likely is not of your interest); even though using a frame pointer is a good idea on x86, no one assures you it is used, and not in the same way, by every compilers.
ShinTakezou
i solved it, tnx anyway..
ultrajohn
A: 

i already solved this problem. please read the updates of my post above.

ultrajohn