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