Blind Return Oriented Programming
In 2014 a paper [http://www.scs.stanford.edu/brop/bittau-brop.pdf] which introduces Blind Return Oriented Programming (BROP), a state-of-the-art exploitation technique, was released by researchers from Stanford University. The paper discusses a general approach in which BROP is used to exploit services which are both vulnerable to stack-based buffer overflows and automatically recover after a crash. What is best about the BROP technique is that one does not need to possess the binary and the source code of the target service to be able to successfully exploit it.
I have tried to replicate the research and exploit the Nginx and MySQL vulnerabilities using BROP to better understand the technique; unfortunately, I have found that the tool released by the researchers failed to exploit either bug in my test environment. The idea is brilliant and works in theory, and the code was clearly working for them in their test environments. What could be the difference(s) that resulted in the same vulnerabilities not being exploitable by the tool? In this blog post we will have a look at some important steps of the exploitation technique.
For those not familiar with the BROP technique, it is highly advised that you read the previously linked BROP paper first, as this post assumes the reader is familiar with the idea and the process.
Stack reading is based on the idea that one can read values from the stack by brute-forcing each byte position of the value. If a correct value is found for the given byte position the application will continue to run, otherwise it will crash. This allows reading the stack canary (if it is there), data, code pointers, and so on. This technique heavily relies on the aforementioned requirement that the target service will gracefully recover from crashes – typically this simply involves the service forking a new process to handle each incoming request.
Figure 1: Stack reading
As illustrated in the diagram above, by stack reading we can eventually brute-force the stack canaries, therefore bypassing the mitigation if the canary does not change between crashes; furthermore, we can read the return address which results in an ASLR bypass. However, while developing the exploifor MySQL and Nginx I had to face several difficulties, explained below.
Unusual Buffer Handling
The first difficulty addressed by the proof-of-concept code provided by the researchers was that the MySQL vulnerability involved an overrun buffer that was populated backwards – in the opposite direction from that to which you would typically expect a stack buffer to be written. Because of this quirk, the payload had to be reversed before sending it to MySQL. This backwards copy can best be explained using the diagram below.
Figure 2: MySQL Buffer Overflow
A quick investigation revealed that function B received a pointer to a buffer allocated by its caller. Function B passed this pointer to function C, which started reading data into the buffer starting from the end of the buffer. Function C did not check the size of the buffer and started to overwrite data in stack frame B; this included the return address of function B. In terms of exploitation this makes things quite easy, as neither function B nor function C allocated anything on the stack, therefore the stack frame of these functions did not contain a stack canary. Even if there had been a stack canary, it would have been possible to read it. To summarise: the return address to be overwritten was not after, but before, the buffer. Despite this, it was still possible to read the stack of both Nginx and MySQL with some small modifications.
Return Address Location
The second issue I had to face was more challenging, and probably this is the point where I will contribute something useful to future use of the BROP technique. The BROP paper mentioned that one has to read three values (including the canary) to get the return address. It might have been the case for the authors of the paper, as I’ve illustrated on the left side of the diagram below, but my version of the services, compiled on Ubuntu, proved otherwise.
Published date: 12 June 2015
Written by: Zsolt Imre