Sabbatical Reading List: Linux x64 Exploits
22 Jan 2017As a software engineer who (presumably) does their homework, one knows that many things that make your program crash can also make your program exploitable, and so naturally a lot of energy goes into avoiding those conditions - don’t use-after-free, don’t leak variables from the stack, yadda yadda.
But of course the other side of the coin - how to exploit mistakes when they happen - is interesting in its own right and a great way to understand how computers really work at a low level. Most probably have a basic idea - change the return address to jump to code that syscalls and gives you a shell - but in reality trivial attacks like this are rarely possible and one must use more more and more sophisticated and quite creative tactics.
Wanting to look into this, I found a great primer for a deep-dive into the real world of Linux exploits, as well as some “real” exploits to read up on.
Of course, there’s much more out there, and looking into some of the above is likely to lead to hours spent reading up on random things. You’ve been warned.
Let’s start with the aptly named:
Linux x86 Exploit Development Tutorial Series1
Starting from the classic stack and heap overflows, this series of blog posts by user @sploitfun quickly becomes more advanced and addresses bypassing, among others, memory-based protection and address randomization.
There really isn’t much else to say; it’s good, I think in parts because it’s written by someone who knows what they’re talking about, but not to the point of thinking everything is trivial.
Having read that, I went on to read up on real exploits which were dissected by capable internet educators. Some favorites follow:
The Linux PI self-requeue bug2, aka towelroot (2014)
This bug in some past versions of the Linux kernel (until fixed in 2014) is in the futex code. Futexes are fast userspace mutexes, and they are tricky3.
The bug is, very roughly, that there is an operation that moves waiters of one futex over to another futex, and that the implementation of this operation didn’t deal properly with being handed the same futex for both.
What it did in this case was allocate a list element which lives on the stack, expecting that this element would be no more on the list by return time, due to the way the code was supposed to work. But in that special, artificial case, an early return meant that the list would now contain an element in memory that was on the stack of that particular method call. Stack memory gets reused, and you can set up function invocations that manipulate this list element’s pointers such that when it’s deleted, a write in your favor occurs.
This and its implications (one way of rooting some versions of android) are very digestibly explained online4 on the tinyhack blog.
Stack Jacking - Your Way To GRSec/Pax Bypass (2011)5
This is a blog post and associated slide deck from Infiltrate 2011 which explicitly attacks Linux in the presence of grsecurity/PaX. What stood out to me is how clearly the ingredients are defined and used; it’s not just a magical chaining of steps that leads to magical outcome.
This is because it’s not a concrete exploit: it’s an exploration of what’s needed to exploit hardened Linux (the answer is that it’s very hard), and the folks at grsecurity immediately reacted, so that all techniques presented are long dead6. Still, it’s very instructive, and teaches you a fair bit about how the kernel bookkeeps its processes along the way.
The basic ingredient they define is an arbitrary kernel write. This isn’t something that happens every day, but does. However, note that during the presentation, they simply compiled a kernel with an intentional bug as a starting point.
This would be home free for a conventional Linux kernel, but under grsecurity/PaX plus self-imposed extra assumptions (zero knowledge of address space, with everything randomized, …), you have no idea where to write, and what.
Where you eventually want to write is the credentials struct of the process (in order to escalate privileges), which is reachable from the base of the process’ kernel stack; you need to be able to leak the base address to userspace and that is often possible and the second ingredient7.
Then, to navigate to the creds struct, you need arbitrary reads, for which they present two techniques (the simpler one simply uses the kwrite near the base of the kernel stack to allow the process to read what it wants). And that is where you write and win, using the first ingredient.
Chrome exploits
Thanks to the Pwnium competition, in recent years some attacks against Google’s Chrome browser have been well-publicized and analyzed. The gold standard here is generally breaking out of the sandbox, and while I don’t think I really learned too much fundamentals from them, they make for excellent competence porn8.
For example, watch Pinkie Pie chain six different bugs to break out of the sandbox or exploit a WebKit use-after-free bug for a coveted 64-bit exploit, awarded a total of $100.000 by Google.
Especially the second one is fascinating because it has to abuse the use-after-free condition by carefully laying out and manipulating memory, taking into account tcmalloc’s bucket sizes and where it will put the next object - and all of that has to be done from JavaScript. It’s a bit like watching a neurosurgeon who’s handed pliers go at it and make it happen.
Then, realize that Pinkie Pie, the author of the two exploits, was a teenager at the time, and nod respectfully.
-
Linux PI futex self-requeue bug, Nicholas Allegra, 2014. ↩
-
Futexes Are Tricky, Ulrich Drepper, 2011. ↩
-
Exploiting the futex bug and uncovering towelroot, @tinyhack, 2014. ↩
-
Stack Jacking - Your Way To GRSec/Pax Bypass, Jon Oberheide and Dan Rosenberg, 2011. ↩
-
Much Ado About Nothing: A Response in Text and Code, @spender, 2011. ↩
-
in the presentation, a suitably old kernel was used that exhibits such a bug, but according to the slides, apparently they are common and considered relatively “harmless” by the Linux maintainers. ↩
-
“Competence porn is a plot with a type of character who is insanely good at something - usually involving some plot-twisting plans.” - urbandictionary. ↩