Windows 8 and Safe Unlinking in NTDLL
I've heard it been said that system allocator based heap exploitation is dead.
Although the "arcane arts" of heap exploitation will never truely die out
(for instance research into kernel and custom allocators has been profitable),
it is generally accepted that "application specific" approaches are the norm
when exploiting heap overflows today*, and that the value of reversing
heap implementations is primarily in understanding allocator policy.
One often overlooked technicality in all of this is that the process default
heap (LocalAlloc and HeapAlloc with a NULL handle) is teeming with activity
from the core system libraries, everything from GDI to cryptographic
services. In effect this means that an overflow in a process default heap
segment has a healthy range of potential target chunks, because you can attack
not only the underlying application but the system dependencies of that
application as well.
The classical example of this was from 2005 when Nicolas Falliere realised that
CRITICAL_SECTION objects were chained together in a doubly-linked list, and
that when the application destroyed the critical section, the chain was
"unlinked" in an unsafe manner. This meant that if an attacker could position
an overflow prior to a critical section, and then trigger the destruction of a
critical section, then an "almost arbitrary" pointer sized overwrite could
occur in a position of the attacker's choosing.
This type of unsafe linked-list removal wasn't unique to critical sections
however, and a number of other library families (and the kernel) were affected.
You may have heard about the Windows 7 kernel "safe unlinking" efforts to
reduce the number of unsafe list removals, particularly as it pertains to kernel
pools. Windows 8 appears to be doing similar work in user-space.
Consider this snippet from NTDLL's RtlRemoveEntryHashTable in Windows 7:
The unchecked unlink is clear in the first four instructions. And now in Windows 8:
We now see a check on the integrity of the forward and back pointers of the
list node. In fact, as best as I can tell, NTDLL in Windows 8 doesn't have any
unsafe unlinks anymore (Windows XP and Windows 7 have at least 30).
So all of this prompted me to ask the question, are there any unsafe
doubly-linked list unlink operations left? The answer may surprise you: there
are 999 of them**. Although the results come back clean for many
core components (NTDLL, KERNEL32, USER32, GDI32 etc.), and the instances of
drivers using unsafe unlinks has dropped significantly from XP, there are
still some isolated pockets of resistance (such as OLE32, MSHTML, JSCRIPT9 and
So is there anything left in here that has some usefulness in exploitation?
That remains to be seen, but for now the moral of the story is that you should
always try to consider what core Windows APIs your target application is using
when searching for good candidate chunks for process default heap overflows.
If you're interested in comparing with the results of the same analysis run
on Windows XP, the data can be found here.
- Ben Hawkes (July 14, 2012)
* And it also has to be said that the term heap overflow is fast becoming
obsolete (with the rapid rise to prominence of client side heap-based
consistency problems, namely uninitialized pointers and use-after-free.) Also,
I do not entirely agree with the general acceptance referred to here.
** Actually a few less than that - due to some duplicate entries. But this
number sure has a nice ring to it, right?