A typical strategy for defeating ASLR is to find both a buffer overflow bug and an information disclosure bug. But when attacking servers that are automatically restarted whenever they crash/die, is a buffer overflow bug enough? Can we use that buffer overflow bug to also give us the information disclosure capability?
Let me flesh out the scenario. Suppose I have a server program that processes a request from the network and will be automatically restarted on a crash, and suppose I have found a buffer overrun vulnerability (of a heap-allocated buffer B
) in the server that I can reliably exploit by sending an appropriately crafted request to the server. Suppose also that I can detect when the server crashes (e.g., it might crash because I sent it a request that corrupted its memory and caused it to segfault; in any case, assume I can send it a request of my choice and determine whether it crashed or not while trying to handle that request). The server is using ASLR, and I want to derandomize ASLR so I can mount a code injection attack, but I don't know of a separate information disclosure bug -- the buffer overrun vulnerability is all I've got to work with.
Can I use this buffer overrun vulnerability for information disclosure, to learn the contents of memory after B
?
Here's an example of the sort of attack I am imagining:
Suppose that the overflowable buffer
B
is 512 bytes long, and suppose there is a secret 8-byte pointerP
stored immediately afterB
. Suppose field F of the request is copied byte-for-byte overB
without any length check.If I send a request with a 513-byte value for F, that'll be copied over
B
. If the 513th byte of my value differs from the first byte ofP
, then the value ofP
will be corrupted, and (assuming the program later dereferencesP
) then program will probably crash during processing of this request. On the other hand, if the 513 byte of my value matches the first byte ofP
, thenP
will remain unchanged, and the program will probably not crash.So, I can imagine sending 256 requests, each with a different value for the 513th byte of field F; if 255 of them cause the server to crash and one does not, then I immediately know the value of the first byte of
P
. Now I can continue until I learn each of the bytes ofP
. This might be useful if the program is using ASLR: by learning the value of the pointerP
, I can derandomize part of memory.
This is just a simple example. In practice, I would imagine there might be unused space after the end of B
and before the next object stored in the heap, but you can imagine ways to adapt these techniques to deal with that situation as well (e.g., if the byte after B
is unused, then you can overwrite it with anything and the server won't crash, so it's easy to detect locations that are unused, and continue the attack until you find the next object after B
).
Does this attack work in practice? Does it provide an effective way to defeat ASLR, when you have a heap overflow in a server that's automatically restarted and when you have a way to detect crashes?
Are there any hurdles that I've overlooked that prevent this from working? For instance, I can imagine that if memory allocation for objects in the heap were non-deterministic and random, the attack would fail; but do platforms do that? Are the relative offsets between objects in the heap deterministic in practice, if you run the same program twice on the same inputs?
I am assuming that the buffer overflow allows overwriting B
with arbitrary binary data that's totally under the attacker's control. (The attack won't work with a strcpy()
or string-related overflow, since then the data is forced to be nul-terminated.) Also, let's assume that either the server is re-started using fork(), or for some other reason, part of the memory layout is the same each time the server is restarted. (For instance, this automatically holds on on Windows and Mac, since libraries are at the same base address every time you restart the server, and it holds for non-PIE processes on Linux.)
Credit: I am inspired by a method I recently read about for exploiting a buffer overflow bug of a stack-allocated buffer for information disclosure purposes. This was described in the Blind ROP paper recently published at IEEE Security & Privacy 2014. They show how to do it when the buffer B
is allocated on the stack. In this question, I am asking whether their technique can be generalized to the case where the buffer B
is on the heap.