alice
alice

Reputation: 59

weird addresses in stack buffer overflow article

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

Answers (2)

Hadi Brais
Hadi Brais

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

zerocool
zerocool

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

Related Questions