Blind return-oriented programming

This is an old revision of this page, as edited by Materialscientist (talk | contribs) at 11:34, 14 January 2016 (Reverted 1 edit by Bestbarcodeworld identified as test/vandalism using STiki). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Blind Return Oriented Programming (BROP) is an exploit technique which can successfully create an exploit even if the attacker doesn’t 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 improvements in OS security and hardware security features like the Linux PAX project, code injection became impossible. Security researchers conceived of 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 ret, along with the a certain state of stack. A gadget can perform an operation like loading a word from memory into 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 in get a shellcode executed. One assumption which ROP makes is that attacker possesses the target binaries and hence knows the addresses of the gadgets before hand.

Scenarios for BROP

There are three new scenarios which BROP can be relevant for. They are:
i.) In case of closed binary services, to discover vulnerabilities techniques like fuzz and penetration testing need to be used.
ii.) 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.
iii.) 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 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 provably 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 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 write 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 write 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 big 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 are sleep on crash. This slows down the attack considerably and allows the system administrator to look into any suspicious activity. Apart from these the conventional protection against ROP style control flow hijacking attacks, Control Flow Integrity also can provide provable prevention but at a significant performance overhead.

References

  • Hacking Blind, Andrea Bittau, Adam Belay, Ali Mashtizadeh, David Mazieres, Dan Boneh
  • Return Oriented Programming, Hovav Shacham et al.