5

Alright, I've been looking into buffer overflows lately out of curiosity. What I don't understand is when you develop the exploit with a virtual machine or whatever, you find the memory address to overflow the instruction pointer with and bam, your exploit works. What I do not get is how does that exploit work on another machine? Wouldn't that memory address be completely different?

5

Yes and no. The memory addresses that you see from a process do not directly correspond to the physical (or even virtual) memory. One of the tasks of the kernel is to map the memory of each process and give that process the illusion that it is the only process running on a machine.

Therefore all processes start their .text (and other parts of code and static libraries) from memory close to 0x0 and their stack starts from the end of the memory. (That's a actually more complex than that, but it is a decent enough analogy. Moreover, since malloc() is a system call the kernel will tell the process an out of memory issue no matter how much memory the process sees). If you start the same process with the same input two times, its memory shall look the same on both starts.

The final mapping between the memory seen by a process and the physical memory is done by the CPU by the use of mapping tables (of which the CPU is told by means of a register).

On the other hand it isn't that easy. Seeing the problem with the possibility of the overflow using the same memory address stack randomization (ASLR) came into life. Several Operating Systems today enable stack randomization by default, where the kernel do not start the memory of a process from 0x0 but from a random initial value. This makes the memory of the process to be shifted by a handful of bytes even when the same process starts two times.

Example

The following trivial program:

#include <stdio.h>

int main(void) {
    int i;
    printf("%p\n", &i);
    return 0;
}

When run on a machine with stack randomization (ASLR) enabled will print distinct addresses, but when I disable it it starts printing the same addresses (assuming the file with the program is named c.c):

[~]$ gcc -o c c.c
[~]$ ./c
0x7ffd52d0aa3c
[~]$ ./c
0x7ffc27da904c
[~]$ sudo echo 0 > /proc/sys/kernel/randomize_va_space
[~]$ ./c
0x7fffffffe86c
[~]$ ./c
0x7fffffffe86c

Extra Note

After testing this on two very similar machines (x86_64 linux 4.8.13) I got exactly the same output from the last two lines. That is because the program and the kernel are deterministic.

Yet, that may not be the case across very different versions of the kernel. For example, kernel 2.x will likely produce a different address for i. This means that the VM where an exploit is developed must mirror the target machine as much as possible (hence the danger of machine fingerprinting).

  • Thanks :) I've been looking for an answer online but this is much clearer than anything I've found – Genthorn Dec 20 '16 at 1:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.