4

At IEEE Security & Privacy, the blind return-oriented programming attack (blind ROP) was just introduced. In some sense, this is just another variation on ROP attacks -- but the blind ROP attack is notable because it does not require any knowledge of the source code or the binary of the program you are attacking; you can attack "blind". Also, their attack is entirely automated, so it is very easy for attackers to use, and it defeats ASLR and DEP. Thus, this seems like a new kind of threat that might become attractive to attackers and is worth defending against.

How should we defend against blind ROP? What are the best available defenses that we can deploy today? How can/should we harden our servers and applications against blind ROP attacks?


References:

  • Hacking Blind, Andrea Bittau, Adam Belay, Ali Mashtizadeh, David Mazieres, Dan Boneh, IEEE Security & Privacy 2014.
5

There appear to be two main defenses:

  1. Detect application crashes. The Blind ROP attack works by repeatedly sending queries to the application-under-attack and observing which ones cause it to crash. It is not at all stealthy: it can easily be detected by the number of application crashes it causes. Therefore, a helpful part of a defense is to monitor application crashes, and if multiple crashes are seen, notify a sysadmin. Sysadmins need to be aware that a high rate of crashes might indicate a potential Blind ROP attack. Unfortunately, this provides only detection, not prevention.

  2. Re-randomize whenever the application crashes. It would be more effective if we could configure our systems so that, whenever an application crashes, it is automatically re-randomized (i.e., so that the layout is re-randomized, using fresh randomness for ASLR). Currently, ASLR re-uses the same randomness for an extended period; depending upon specifics of the operating system, new randomness is generated only after reboot or only periodically. The Blind ROP attack exploits this: it relies upon the fact that it can send multiple requests to the application-under-attack, and each time the application crashes, it will be automatically restarted and will end up with the same address space layout (ASLR randomness won't be refreshed). If we disrupt this assumption, we will disrupt the Blind ROP attack.

    Unfortunately, there appear to be two issues with this defense:

    • Issue: It is not clear to me how to implement this defense on current platforms, or even whether it is possible to do so. It appears that Linux and Mac OS X only re-randomize on each boot.

    • Issue: On Linux and Mac OS X, this defense won't work for server processes that fork worker processes; some extra something is needed to protect them. The problem is that many servers are structured as a parent process, which forks a bunch of worker processes (children) to handle requests, and if a worker process (child) crashes or dies, the parent will fork a new one. Now, suppose that there is a buffer overrun vulnerability in the code that handles requests. The Blind ROP attack will repeatedly send a request that triggers a worker to crash, and the parent will fork a new worker. Since the parent process never dies, it has the same address space layout throughout. And, the way that fork works is that the child inherits the same address space layout as the parent. Thus, no matter what you do, all workers will have the same address space layout, for the lifetime of the parent (e.g., until reboot or until the service is manually restarted by a sysadmin). Thus, re-randomizing on each crash won't help protect this kind of server. Windows doesn't have fork(), so it might get somewhat better protection against Blind ROP -- I'm not entirely clear on that.

    Ultimately, it is not clear to me how to protect or harden forking servers against Blind ROP attacks, at least on platforms other than Windows.

There are some additional possible hardening measures that I wouldn't rely upon as the sole defense, but that might stop Blind ROP attacks in some cases:

  1. Enable stack canaries. If your compiler doesn't automatically turn on stack canaries, set the appropriate compiler flags to make sure applications are compiled with stack canaries. The Blind ROP attack as described in the published paper only works against stack overflows (buffer overrun vulnerabilities in stack-allocated buffers), and can in some cases be stopped by stack canaries.

    If you are using gcc, you might want to enable strong stack protection, i.e., -fstack-protector-strong (details) -- or even -fstack-protector-all if you are paranoid (but this might have performance implications).

    However, stack canaries have a significant limitation: they don't help protect forking server processes, as the canary will remain the same for all worker processes throughout the lifetime of the parent. This is unfortunate.

  2. Use load balancing, if convenient. If your load balancer sends each request to a different random server, and if you have enough back-end servers behind the load balancer that might help make Blind ROP harder. The reason it might help is that each request goes to a different machine and thus a different instance of the application with a different memory layout (assuming you use stack canaries and full ASLR, i.e., PIE). No guarantees, but it might help.

  3. Use standard hardening measures. As always, compile with full ASLR (-fpie on Linux/gcc). This won't stop Blind ROP, but it will prevent simpler attacks (and simpler variants of Blind ROP) from working.

  • Nice explanation. Number 2 seems like a good solution. Possibly a middle layer that just forwards requests ultimately to child processes running in VMs. If a child process in a VM crashes, just trash the parent and reroute to a new instance. This might lead to some next level DDOS attack :p – jarryd Apr 19 '18 at 13:21

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.