64-Bit Linux Return-Oriented Programming
crypto.stanford.edu
crypto.stanford.edu
> Abstract—We show that it is possible to write remote stack buffer overflow exploits without possessing a copy of the target binary or source code, against services that restart after a crash. This makes it possible to hack proprietary closed-binary services, or open-source servers manually compiled and installed from source where the binary remains unknown to the attacker. Tra- ditional techniques are usually paired against a particular binary and distribution where the hacker knows the location of useful gadgets for Return Oriented Programming (ROP). Our Blind ROP (BROP) attack instead remotely finds enough ROP gadgets to perform a write system call and transfers the vulnerable binary over the network, after which an exploit can be completed using known techniques. This is accomplished by leaking a single bit of information based on whether a process crashed or not when given a particular input string. BROP requires a stack vulnerability and a service that restarts after a crash. We implemented Braille, a fully automated exploit that yielded a shell in under 4,000 requests (20 minutes) against a contemporary nginx vulnerability, yaSSL + MySQL, and a toy proprietary server written by a colleague. The attack works against modern 64-bit Linux with address space layout randomization (ASLR), no-execute page protection (NX) and stack canaries.
The suggested counter measure is to re-exec child processes so their address space is re-randomized. OpenSSH began doing this by default 10 years before the above paper: https://github.com/openbsd/src/commit/5541d005bde289515d9734...
Presumably (hopefully) some other common, multi-process network daemons have been refactored to exec child processes. As explained in the paper, nginx, which utilizes an M:N process model, was susceptible. Anybody know if nginx was refactored to fork+exec its worker processes rather than just fork? (EDIT: AFAICT via a cursory examination of ngx_master_process_cycle, ngx_start_worker_processes, and related the answer is, "no".)
EDIT: See also https://lwn.net/Articles/849531/
"Special hardware" is literally everywhere. It's more accurate to call it "special" if it doesn't support NX.
> Somebody must have thought so, because it is so prevalent now.
FWIW, those people (pippac iirc/ paxteam?) were well aware of ROP when they created it. It's sad how hard it is to find the original sources these days, the docs are all so old - someone can maybe find security.txt?
> We just saw how trivial it is to stitch together shreds of existing code to do our dirty work. We barely scratched the surface: with just a few gadgets, any computation is possible. Furthermore, there are tools that mine libraries for gadgets, and compilers that convert an input language into a series of addresses, ready for use on an unsuspecting non-executable stack. A well-armed attacker may as well forget executable space protection even exists.
> Therefore, I argue executable space protection is worse than nothing. Aside from being high-cost and low-benefit, it segregates code from data. As Rob Pike puts it:
> This flies in the face of the theories of Turing and von Neumann, which define the basic principles of the stored-program computer. Code and data are the same, or at least they can be.
> Executable space protection interferes with self-modifying code, which is invaluable for just-in-time compiling, and for miraculously breathing new life into ancient calling conventions set in stone.
This is an absolutely unnecessary and totally specious line of reasoning. I worked for 6.5 years on V8 and can say with strong confidence that 99.9% of remote execution vulnerabilities that we saw in the field were because of RW executable memory. We did a lot of work to make write-execute exclusion fly in V8 for JavaScript code, without a major performance penalty, and that massively reduced this attack surface. That only works because we could totally quiesce JavaScript code while the JIT modified executable memory and flipped permissions from RW to RX. Yet other attack surfaces remain. In particular, V8 still needs RWX JIT code for Wasm, because tiering and parallel compilation. Guess where attackers learned to get the one remaining source of RWX memory? Yeah, just make an empty Wasm module. And for the record, that doesn't mean they were exploiting bugs in the Wasm engine, just using it to get some memory that is RWX that they can overwrite through some other bug.
This article, though great on specific technical details about ROP, is terrible security advice. It is not theater to reduce attack surfaces. Take away an attack surface and yeah, attackers will find a new one. But it acts like a filter; if you make it 10x harder, you get 10x fewer exploits. It raises the bar.
And for the record, though I didn't look at every single one, I never did, in fact, see a ROP exploit against Chrome except as part of some hackathon or pwn-to-own. Attackers were just walking in the front door when you have RWX!
But I'd argue that Borrowed Code Chunks exploitation technique paper by stealth from 2005 is the original. But maybe I'm just too old.
Here's a recent example : https://googleprojectzero.blogspot.com/2020/12/an-ios-zero-c...