Have you ever locked yourself out of your car? After calling for roadside service, your tow truck driver forces the internal locking mechanism open with a slim-jim. Car thieves quickly discovered this technique and began using it to steal cars. Digital thieves have devised a similar attack called a Blind Return-Oriented Programming (Blind ROP, or just BROP) attack. It’s as quiet as a jackhammer on cement, but an attacker can open a remote shell and gain remote code execution on your server if the conditions are right.
ROP Gadgets and Chains
When building a program, the developer doesn’t write in a language that the CPU natively understands, so we need a compiler or interpreter that’ll turn Ruby, Python, and Rust programs into a language the does CPU understand. Every compiler has basic programs that allow additional functionality, like 'compare these two strings' or 'execute this command'. These programs are called return-oriented programming (ROP) gadgets, getting their name from the RET instruction at the end of the statement, short for RETURN. ROP gadgets are juicy targets for attackers, allowing them to take over argument calls for ANY function within the compiler. For the attacker to succeed, the attacker needs to control these gadgets, which are used to inject and control program flow on a remote system. Since these basic functions already exist within the victim’s system, it’s less code the attacker needs to load onto the system. A compiler translates a program into something the CPU understands and has small, elementary 'functions' that allow it further functionality.
Attackers try and call these gadgets by manually loading up the address space from which they reside and loading them into their script. If they know the version of the operating system, then they can reverse engineer the gadget’s location within their environment. ROP gadgets enable essential functions to work, and when attackers can call them sequentially, that’s called developing an ROP Chain. An attacker can trick a CPU into running their code by chaining ROP gadgets together instead of what’s next in the pipeline. Once they put everything together in a script and run it against your server, they can gain remote shell access to your system to do as they wish.
When an input receives more data than it can handle, this is called an overflow event. Think of trying to push a watermelon through a garden hose. Somewhere along the line, the restrictions will fail, and that hose will split. The idea is to try and cram as much data as you can into one request in the hope that the data at the end will land in an address space, which is typically reserved for system processes like the CPU compiler. Attackers will then try and re-write what is in the address space, as that contains a special value that tells the compiler where to send the flow of the program. When this happens, the compiler’s first line of defense is to halt the execution of the program.
When the CPU reaches a branch in coding logic, for example, 'if X happens, do Y, or else, do Z,' it places a value between the function variables and the branch point, like a breadcrumb called the stack canary. After the CPU finishes the instruction and returns, the compiler compares the value in the returning function with the stack canary, which is intended to be the same. Two different values indicate a buffer overflow situation exists, and halting the execution of the program is the CPUs way to defend against attackers. However, with enough attempts, an attacker can place the correct canary value at the end of the enlarged packet. This is because there’s a finite number of fields that the canary can be, so an attacker will just brute-force all possible values. If the values match, the attacker can control the CPU pipeline remotely. Once they have discovered the overflow size and stack canary, they can begin working on locating the system ROP gadgets.
Blind ROP basics
To conduct a successful BROP attack, the attacker needs to find two properties that exist within the target system:
a vulnerability that impacts the pipeline of the server, and
the vulnerability must exist in a service set to automatically restart if it crashes.
In summary, the attacker will be looking to determine the following:
the buffer overflow size
the stack canary and stop gadget location
the address location of the procedure linking table (PLT)
assembly gadgets accessible within the target system
After sending enough requests, they can increment through all potential values to determine the value of the stack canary. When the attacker sends an overrun condition, they append the stack canary value to the end of their payload. Since the stack canary is the same, it doesn’t cause the program to crash. The attacker uses this information to determine a 'stop ROP gadget' address location, which can be called upon when searching for other gadgets and allows the attacker to halt ROP chains so that more gadgets can be discovered. Once the address of the stop ROP gadget is known, the attacker uses this information to find the procedure linking table (PLT), which links process calls to lower-level gadgets. Armed with address locations of the PLT and stop gadgets, the attacker begins locating the address locations for ROP gadgets.
After the address locations of these gadgets have been discovered, the attacker can begin their main attack. The attacker will send a malicious payload, which includes the buffer overflow, stack canary, and PLT table locations. This payload will have a few calls to ROP gadgets within the system, complete with their precise address locations. The script will overflow an input, discover the gadgets, and use those to inject a remote shell command into a third argument, giving the attacker control over your system.
How to defend yourself against a BROP attack
An average BROP attack takes about 4000 requests. Just like a brute-force attack, BROP attacks should generate a decent number of alerts while the attack occurs. Basic logging and monitoring could detect these requests, along with an appropriate intrusion prevention system (IPS) and other detection means. This attack also requires a specific configuration to be in place within the victim’s environment. The best defense is limiting the information gathered during the attacker’s reconnaissance phase and ensuring your systems are patched and up-to-date. Turn off default banners for services that require port access on your firewall. Banners are the first message you see when pinging a port’s service. These can display important information, such as the version and model of the server you’re running. Running updated versions of your software is also recommended, as newer versions have better memory and heap management.
OS manufacturers have also pondered this question, with the result coming in the form of Address Space Layout Randomization (ASLR). This built-in feature in your operating system will randomize the address spaces within the operating system. So, if the attacker knows your server’s operating system, they’ll already know the location of your write and read ROP gadgets. If they know the location of ROP gadgets ahead of time, they can put together ROP Chains with a smaller number of requests, expediting the attack. This doesn’t protect against exposing the stack canary, but it will make it more difficult for the attacker to know where in your address space specific ROP gadgets exist. This would have a cascading effect of increasing the requests the attacker must make to discover the necessary gadgets. You can enable ASLR in Windows, and here you can enable it on Linux; for MacOS, ASLR is enabled by default.
Attackers use Blind ROP attacks against target systems with an existing vulnerability against the CPUs pipeline and against a service that restarts automatically. They aren’t quiet but can be effective in the right situation. By creating an overflow condition in the environment and determining the address location of specific functions within the victim’s system, an attacker can perform a control hijacking by taking control of the CPU’s instruction pipeline remotely. They can direct program flow to their specially crafted instruction set by taking over control, leading them to a remote shell on the victim’s server. Typical defenses against this include keeping your programs, services, and servers patched and updated. It also includes performing essential log monitoring and examination to ensure attackers aren’t trying to infiltrate the system. With a bit of setup initially, detecting and thwarting BROP attacks can be included in your standard security policy.