size the stack buffers - the static way

Here I'm going to explain with examples how to calculate stack buffer sizes using the static way which is the way. 

Many people uses cyclic or several dynamic trial and error but in the disassembly we have all we need.

 

I'm going to put 3 examples:

1. with 1 stack buffer

2. with more than 1 stack buffers

3. targeting a function pointer instead of the return_address 

 



In this binary main function just call sym.bug function, let's check it.

 

We face a stack buffer of 0x20 - 8 - 8 = 16 bytes, it's a strcpy based stack overflow. This way of calculating becomes confusing when there is more than one stack variables, we will see other ways.

 

Let's see it in asm to be more accurate.

despite the cool features of pwndbg, peda etc, i prefer a classic GDB :) 

 

So,  we start writing at -0x10 and we want to arrive to 0x08 (relative to rbp)

We have to write: 0x08 - -0x10 = 24bytes

 

Other way to see it probably more simple: 

16 buffer + 8 saved ebp  = 24 bytes

 

We will write 24 bytes and then the 8 bytes to overwrite the return address. 

Stack Structure: 

 

    ↑ lower address
─────────────────────────────────
rbp-0x20  → padding
rbp-0x18  → arg1
rbp-0x10  → buffer (regarding the lea its here) 
─────────────────────────────────
rbp+0x00  → saved RBP
rbp+0x08  → return address (RIP)
─────────────────────────────────
   ↓ bigger address
 

If you use IDA will see this:

 

After the compilation the size of variables is lost, we just have the pointer to the begining, in this case -0x10 

 

Trigger: 

>>> print("A"*24+"BBBBBBBB")
AAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB 

 

 

 Triggered in one try, follow the static analysis way, don't do trial&error!

 

What if there is more than one variable?

 

 

There is no code using this buffers (above and below) but this other buffers incremented the stack to 0x40.

 

Formula: 

      padding = 0x08 - buff_offset 

 

0x08 -  -0x20 = 40

 

We add 40 A's of padding next 8 bytes will be the return address. 

 

Let's see a third scenario, the target now is not return address, it's fptr.

  

In this case the buffer offset is -0x20 and the target is call rdx, the function pointer is stored in var_8 in offset -8

 

 

-8 - -0x20  = 24

so 24 A and then 8 B to overwrite the function pointer.

 

Quick Recap:

distance is always:  dest_off - src_off 

If the target is return address then dest_off is 0x08 

If the target is stack variable get it's offset.

If the target is saved RBP  then dest_off is 0x00

 

 

Comentarios