Today is the one-year anniversary of this interesting kernel bug I worked on last year with @bluec0re, and as it turns out I wrote something about it during one of these lockdown weekends so I thought I'd release it. The bug itself was discovered by Jann Horn of Project Zero. While I touch most of the elements required to exploit the bug, I stay superficial here since the exploit itself is not particularly exciting. What makes this bug interesting to me is its lifecycle, in particular how unevenly the patch was applied to the various distributions. I also talk briefly about hardware side-channels since it was the first time I had ever used one.
It’s already well-described in the bug tracker, but here is another summary. The futex syscall's main parameter is a userland address, and this address may belong to a file-backed mapping. In that case, the futex key kernel object held and kept a reference to the inode object, but didn’t hold a reference to the file’s mountpoint. If the mountpoint were to go away, its associated kernel structures would be freed, but the inode wouldn’t. That’s an issue because the inode itself has fields that point to some of these structures, such as its super_block struct.
I know, I know. With every new paper/post/challenge around ptmalloc2 if feels like everything has been said. And yes, one rarely needs to understand the Malloc Maleficarum to exploit a heap bug. Neither does one need to get PC control from wizardly metadata overwrites to exploit applications where function pointers, indexed arrays and the like already live on the heap.
Nowadays exploiting heap structures is often nothing more than finding a way to overwrite interesting structures residing on the heap, by having old chunks overwritten or new chunks allocated within areas under attacker control. Pure heap exploits have been discarded as almost impossible for quite a few years now.
I've recently had the pleasure to stay for a couple of weeks in the gorgeous industrial zone of Belmont, WA. Nearest pub being a ~25 minutes walk, I've put my 5 Kbps Internet connection to good use and downloaded a few challenges from recent CTFs. qwn2own from the latest Boston Key Party CTF definitely stood out, as we don't often see browser exploitation challenges in CTFs. I reckon it very successfully touched the browser exploitation world, as it required players to use techniques close to nowadays client-side exploits, but with the ability to easily debug and look at the underlying source. And so I've decided to use this challenge as a material for my yearly article which will try to cover why corrupted vector/array objects can be (and often are) used to write universal, per platform, browser exploits.
The challenge itself was distributed in this archive, which contained an x64/PIE/Full RELRO binary of a simple QT-based browser with a custom Javascript extension, "BKPDataBase". Basically, a database object can be used to create and manage data stores (vectors) or keyed stores (maps) as I think their example page illustrates well:
PlaidDB is an x64 stripped executable, compiled with full RELRO, PIE and NX support. It's libc was provided, seemingly from Ubuntu LTS 14.04. It manages key-value pairs which one can add, update, retrieve or delete:
The vulnerability lies in the function at 0x1040, used to get the key values from standard input:
The zengarden is an x86 executable, from some mixed C/C++ code. Its libc was provided. As with any basic zen garden, one can add trees and ponds:
"Add" allocates C++ objects, and "perform" calls the first method of each object. Once an object is deleted its slot cannot be refilled, and its actions cannot be performed. As shown above, the pond's action discloses the address of its object, providing us with a free leak.