49 lines
No EOL
2.2 KiB
Text
49 lines
No EOL
2.2 KiB
Text
Source: https://code.google.com/p/google-security-research/issues/detail?id=620
|
|
|
|
I wanted to demonstrate that these iOS/OS X kernel race condition really are exploitable so here's a PoC
|
|
which gets RIP on OS X. The same techniques should transfer smoothly to iOS :)
|
|
|
|
The bug is here:
|
|
|
|
void IORegistryIterator::reset( void )
|
|
{
|
|
while( exitEntry())
|
|
{}
|
|
|
|
if( done) {
|
|
done->release();
|
|
done = 0;
|
|
}
|
|
|
|
where->current = root;
|
|
options &= ~kIORegistryIteratorInvalidFlag;
|
|
}
|
|
|
|
We can call this from userspace via the IOIteratorReset method.
|
|
|
|
done is an OSOrderedSet* and we only hold one reference on it; therefore we can race two threads
|
|
to both see the same value of done, one will free it but before it sets done to NULL the other will
|
|
call ->release on the now free'd OSOrderedSet.
|
|
|
|
How to get instruction pointer control?
|
|
|
|
The XNU kernel heap seems to have been designed to make this super easy :) When the first thread frees
|
|
done zalloc will overwrite the first qword of the allocation with the freelist next pointer (and the last qword
|
|
with that pointer xor'd with a secret.) This means that what used to be the vtable pointer gets overwritten
|
|
with a valid pointer pointing to the last object freed to this zone. If we can control that object then
|
|
the qword at +0x28 will be called (release is at offset +0x28 in the OSObject vtable which is the base
|
|
of all IOKit objects including OSOrderedSet.)
|
|
|
|
This PoC uses OSUnserializeXML to unserialize an OSData object with controlled contents then free it, which
|
|
puts a controlled heap allocation at the head of the kalloc.80 freelist giving us pretty easy instruction pointer control.
|
|
|
|
I've attached a panic log showing kernel RIP at 0xffffff8041414141. You will probably have to fiddle with the
|
|
PoC a bit to get it to work, it's only a PoC but it does work! (I have marked the value to fiddle with :) )
|
|
|
|
As a hardening measure I would strongly suggest at the very least flipping the location of the obfuscated and
|
|
unobfuscate freelist pointers such that the valid freelist pointer doesn't overlap with the location of the
|
|
vtable pointer.
|
|
|
|
|
|
Proof of Concept:
|
|
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39357.zip |