Reputation: 59
while reading this article which is about bypassing some protection; if you start reading that article, you will find that the author did a really strange calculation that I didn't understand:
RET2RET
the demo code ( containing the vulnerable function strcpy
)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
char buf[256];
strcpy(buf, argv[1]);
return 1;
}
after disassembling the code above with GDB you get something like this ( disassembling main function ) :
(gdb) disassemble main
Dump of assembler code for function main:
0x08048384 <main+0>: push %ebp
0x08048385 <main+1>: mov %esp,%ebp
0x08048387 <main+3>: sub $0x108,%esp
0x0804838d <main+9>: and $0xfffffff0,%esp
0x08048390 <main+12>: mov $0x0,%eax
0x08048395 <main+17>: sub %eax,%esp
0x08048397 <main+19>: sub $0x8,%esp
0x0804839a <main+22>: mov 0xc(%ebp),%eax
0x0804839d <main+25>: add $0x4,%eax
0x080483a0 <main+28>: pushl (%eax)
0x080483a2 <main+30>: lea 0xfffffef8(%ebp),%eax
0x080483a8 <main+36>: push %eax
0x080483a9 <main+37>: call 0x80482b0 <_init+56>
0x080483ae <main+42>: add $0x10,%esp
0x080483b1 <main+45>: mov $0x1,%eax
0x080483b6 <main+50>: leave
0x080483b7 <main+51>: ret
End of assembler dump.
(gdb)
after that we set a break point on strcpy because it's a vulnerable function:
(gdb) break *main+37
Breakpoint 1 at 0x80483a9
now we run our program and give it a big chunk of A
char to overflow the buffer
(gdb) run `perl -e 'print "A"x272'`
Starting program: /tmp/vuln `perl -e 'print "A"x272'`
after that we print the content of eax
register (I'm thinking that eax
holding the buf
address, correct me if I was wrong)
(gdb) print (void *) $eax
$1 = (void *) 0xbffff5d0
okay after that the author of the article say this statement down below
Simple calculation gives 'buf' variable range [
0xbffff6d8
-0xbffff5d0
] / (264 bytes
;0x108h
)
which I couldn't figure out what it mean and also where he came up with that 0xbffff6d8
address
Upvotes: 2
Views: 777
Reputation: 23659
The basic idea of ret2ret exploits to is to find a value on the stack that can be slightly changed so that it points into a buffer that can be overflowed. By executing as many ret
instructions as needed to get to that value, you will be able to eventually execute code in the buffer (the exploit).
The stack from the example just before executing call 0x80482b0 <_init+56>
looks like this:
--------------------
| 0xbffff6f0 | ebp+28
--------------------
| 0xb7fdb000 | ebp+24
--------------------
| 0xb800167c | ebp+20
--------------------
| 0xbffff770 | ebp+16 (previous stack frame)
--------------------
| 0xbffff764 | ebp+12 (points to the argv array)
--------------------
| 0x2 | ebp+8 (holds the value of argc)
--------------------
| main ret addr | ebp+4
--------------------
|previous ebp value| ebp
--------------------
| appears to be |
| unused | ebp-8
--------------------
| |
| 256-byte |
| buf |
| |
| |
| | ebp-264
--------------------
| | ebp-268 (holds the second argument to strcpy)
--------------------
| | ebp-272 = esp (holds the first argument to strcpy)
--------------------
So how to perform a successful ret2ret attack on this stack? We know that the last instruction in main
is ret
. We need to find a way to execute this instruction a number of times so that eventually whatever code we decide to put in buf
will get executed. Remember that every time ret
is executed in 32-bit x86 mode, it will pop a 4-byte value from the stack. So the first thing we need to figure out is how many 4-byte values that need to be popped from the stack to get to a value that happens to represent a pointer into buf
. The author of the article shows that the first such value is at ebp+28
. The range 0xbffff6d8 - 0xbffff5d0 contains the 256-byte buffer. However, the value at ebp+28
is 0xbffff6f0, which is actually outside the buffer. But since strcpy
will append a NULL byte at the end, we can make it overwrite the first byte of ebp+28
with NULL so that it contains 0xbffff600, which points inside the buffer. Starting from ebp+4
, there are 7 4-byte values. So we need to execute ret
7 times, and then execution will continue from somewhere in buf
.
To achieve this, the value at ebp+4
needs to be set to the address of ret
in main
, which is 0x080483b7. Similarly, all 4-byte locations up to and including ebp+24
need to be set to 0x080483b7. In this way, the first 6 executions of ret
will just jump to ret
to be executed again and again. But the last time ret
is executed, control will be transferred to 0xbffff6f0, which is in the buffer that will be overwritten.
Now consider what happen when evilbuf
from the exploit code is passed as argv[1]
. The buffer contains 261 single-byte NOP instructions. The next 7 bytes are instructions that perform the exit system call (although a real exploit would do something more interesting). These 268 bytes will overwrite all the bytes from ebp-264
to ebp+3
. Then there are 6 copies of the address of ret
. At the end, strcpy
will generously append a NULL for us, thereby overwriting the byte at ebp+28
.
After strcpy
returns and ret
in main
gets executed for the first time, it will be executed 6 more times and then the instruction at 0xbffff600 will be executed. This is one of our NOPs. Then the rest of the NOP sled will be executed until reaches the designed sequence of instructions (The payload), which in this case just performs the exit system call.
Ret2ret does not require prior knowledge of the buffer address. Therefore, it can work even if the OS randomizes the base address of the stack. But it requires knowing the address of the ret
instruction.
Upvotes: 3
Reputation: 3502
correct me if i was wrong
First you are correct about eax
it contain the address of buf
(there are many way). To be sure about that: first and the most simple is that args
of functions, get pushed onto the stack in reversed order, so the last one pushed will be the first args
as you can see from your disassembly window above that the last one before calling the function is push eax
so the value in eax
must be the buf
address.
which i couldn't figure out what it mean and also where he came up with that
0xbffff6d8
address
0xbffff6d8
it's the ebp
value and the idea behind 0xbffff6d8 - 0xbffff5d0
is one of many way to know your max buf size before it start throwing segfault
Another way to know this information without doing this calculation is from disassembly window above you see 0x08048387 <main+3>: sub $0x108,%esp
which it allocate a space for the local buf
array, but it's not true in all cases: depends on the number of local variables (if there one local variables/array this will work every time, otherwise you have to be clever to using this method) but the author's method works every time .
Upvotes: 1