Blind return oriented programming

From HandWiki

Blind return oriented programming (BROP) is an exploit technique which can successfully create an exploit even if the attacker does not possess the target binary. BROP attacks shown by Bittau et al. have defeated address space layout randomization (ASLR) and stack canaries on 64-bit systems.

ROP History

With the current improvements in OS security and hardware, security features like the Linux PAX project, code injection is now impossible. Security researchers then conceived a new attack which they named return-oriented programming to defeat NX (non-executable) memory. This attack relies on affecting program flow by controlling the stack, especially return addresses. Gadgets are the fundamental units of this attack. Gadgets are a group of instruction sequences ending in a return instruction, along with a certain state of the stack. A gadget can perform an operation like loading a word from memory into a register, or performing a more complex operation like a conditional jump. With a large enough target binary, a Turing-complete collection of gadgets can be constructed, which is more than enough to get a shellcode executed. One assumption which ROP makes is that the attacker possesses the target binaries and hence knows the addresses of the gadgets beforehand.

Scenarios for BROP

There are three new scenarios which BROP [1] can be relevant for. They are:

  1. In case of closed binary services, to discover vulnerabilities where techniques like fuzz and penetration testing need to be used.
  2. A known vulnerability in an open-source library can be leveraged to carry an exploit, even though the proprietary binary which uses it is closed source.
  3. It can also be used to hack an open-source server for which the binary is unknown.

The attack assumes that there is a service on the server which has a known stack vulnerability and also that the service should restart on crash.

Phases of attack

Stack reading

Return instruction pointers are usually protected by stack canaries. A stack canary causes the program to crash if its value is modified by a buffer overrun. In the BROP model of attack, the buffer overrun is carried byte by byte. Each try at the overrun results either in a program crash or continued execution. A program crash implies that the stack value was incorrectly guessed, therefore in 256 tries (average case is 128 tries), the stack value can be probably estimated. On 64 bit machines, 4 such stack reads would be required to leak the canary. Once the canary is leaked, the return instruction pointer can be perturbed in the same way. It may, however, be noted that though the estimation of the stack canary is exact, the same cannot be said about the return instruction address. The attacker would be satisfied to be able to leak any address within the text segment of the address space.

Blind ROP

This stage is the heart of the attack. The objective in this phase is to initiate a write system call, sending a dump of the binary to the attacker. The write system call has three params: socket, buffer, and length. As x86-64 calling conventions require the parameters to be passed through registers, appropriate pop instructions into rsi, rdi and rdx would be needed to set up the arguments for the write system call. Instruction sequences like pop rdi, ret and the like would be helpful in this regard. A simple ROP version of the write system call would be:

  1. pop rdi; ret (socket)
  2. pop rsi; ret (buffer)
  3. pop rdx; ret (length)
  4. pop rax; ret (write syscall number)
  5. syscall

One problem with this methodology is that even if useful gadgets are found in the address space after they return the address on the stack would lead to non-executable stack with a high probability. To remedy this, BROP proposers conceived stop gadgets. A stop gadget is anything that would cause the program to block, like an infinite loop or a blocking system call (like sleep). This also workers processors affected in the attack to be stuck in an infinite loop and hence allowing the attacker to carry on the attack.

What is mentioned above is the bare-bones methodology of the attack. In reality, a few optimizations can be carried out which help in efficiently carrying out the attack. Primary among them is the use of Procedure Linker Tables (PLTs) to track down the writing system call instead of passing the system call number to the syscall function. Others include using strcmp to populate the RDX register, as pop RDX, ret instruction sequences are extremely rare.

Build the exploit

Once the writing is found in the PLT, the attacker can dump the contents of the target binary to find more gadgets. The attacker can use conventional ROP gadget search techniques to gather enough and create a shellcode. Once they have the shellcode, the exploited system can be taken under full control with root access.

BROP prevention

A huge assumption in the BROP attack is that the server restarts after each crash and when restarting does not re-randomize its address space. So enabling re-randomization of address space at startup can provide almost complete protection against BROP. Another technique used by NetBSD and Linux is sleep on the crash. This slows down the attack considerably and allows the system administrator to look into any suspicious activity. Apart from this the conventional protection against ROP style control flow hijacking attacks, Control Flow Integrity also can provide provable prevention but at a significant performance overhead.

Similar attacks

Another attack that is similar in nature to BROP, is JIT (Just-In-Time)-ROP, or JIT-ROP. It is also another attack that's based on information disclosure, which is able to also defeat Address Space Layout Randomization. Both BROP and JIT-ROP will attempt to locate gadgets on the binary in order to initiate a ROP attack, where the goal is to exploit some type of data leak. However, unlike BROP, JIT-ROP is not an attack which is interactive, and seeks to adapt to no-crash/crash situations, but rather, the attacker will send out a script which will discover gadgets, then subsequently creates an attack for delivery. Also, JIT-ROP must have two different vulnerabilities (Both a heap and stack) known in advance of the attack, while BROP only requires awareness of a stack vulnerability.[2]

References