Windows 10 Pool Party
1.1
BAYET Corentin
2017
Windows 10 Pool Party
- Exploitation in the NonPagedPool
- Exploitation at medium integrity level
- Attacking drivers and IOCTLs
- Tools and methods to attack pool
What we WILL talk about
What we WONT talk about
- Win32k.sys, GDI / USER objects
- Exploitation at low integrity level
1.2
First crash
2.1
What is the kernel pool ?
-
Place for every allocation in the windows kernel
-
Common for every drivers
-
Specific allocator and structures
-
Several types:
-
NonPagedPool
-
PagedPool
-
....
-
Basically, a list of pages fragmented in chunks !
2.2
A pool chunk
2.3
First crash
IOCTL: Input/Ouput Control
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
I/O Control Code
2.4
First crash
METHOD_BUFFERED:
- The I/O Manager allocates a buffer in the NonPaged Pool with the biggest size provided: it's the SystemBuffer
- The I/O Manager copies the InputBuffer in the SystemBuffer and pass it to the driver
- The driver handles the IOCTL, and writes the return in the SystemBuffer by overwriting the input. The driver must also tell to the I/O Manager how much he has written.
- The I/O Manager copies the content of the SystemBuffer in the OutputBuffer using the size provided by the driver.
So we control the size of the buffer used for input and ouput in drivers... Great Attack Vector !
2.5
The vulnerability
About CVE-2017-6008
A memcpy is called with following arguments:
- Dest: The SystemBuffer (we control the size)
- Src: A full controlled buffer (from our Input Buffer)
- Size: the size of src
Classic Buffer Overflow... But in the NonPagedPool !
2.6
Pool History
- Deobfuscate Pool Internals
- Presents severals generic attacks
2.7
Points to data controlled by attacker
- Using a pool buffer overflow to overwrite Process pointer
- Craft a fake EPROCESS structure
- Triggers an arbitrary decrementation when the overflowed chunk is free
Quota Process Pointer Overflow
2.8
DEMO
History of the Pool
- REAL safe linking/unlinking
- Pool Index validation
- SMEP
- MIN_MAP_ADDR (reverted on windows 7 and vista x64)
- NonPagedPoolNx (DEP)
Windows 8 Introduced a lot of mitigations:
About the attack we used:
- Process Billed encoded with a cookie
- The free algorithms checks if the pointer is in kernel-land
3.1
Nowadays Pool Chunk
Process Billed encoded:
PoolCookie XOR Chunk Address XOR Pointer
Checked before use
3.2
Today
- Exploiting vulnerabilities in the Pool is pretty hard
- No generic attacks
Goal: exploit the very same pool buffer overflow on Windows 10
3.3
What do we need
Quota Process Pointer Overwrite:
- The Pool Cookie
- The address of the overflowed chunk
- Arbitrary data in kernel-land at known address
Seems impossible...
3.4
Pool Spraying
- Spraying is the art of making the further allocations predictible using the allocator behavior
- Provides you knowledge and control
4.1
Allocator Behavior
- Lookaside list (for chunks with a size <= 0x200)
- ListHeads list
Two lists of free chunks :
4.2
Lookaside List
- Contains chunk with a size ≤ 0x200 bytes
- Can contains only 255 chunks of the same size
4.3
Allocator behavior
Allocation algorithm
4.4
Allocator behavior
Allocation of a new page
4.5
Allocator behavior
Free algorithm
4.6
Windows API tools
- A lot of different objects:
- Reserved Objects
- Semaphores
- Processes
- Register keys
- Files
- …
- With various size
- Allocated in differents pools (Paged, NonPaged...)
Windows named objects :
5.1
Windows API tools
In userland, use a handle to interact with the object !
5.2
Basic Pool Spraying
Step 1: Derandomize the pool
- Empty the Lookaside List
- Empty the ListHead List
- Create pages filled of our object
AKA : Massively allocate chunks
6.1
Basic Pool Spraying
User-land
Kernel-land
Step 2: Create Gaps
CloseHandle()
Chunks are freed and coalesced
6.2
Basic Pool Spraying
Problems:
- We can't predict allocations with a size <= 0x200 bytes
- Or we need an object with the exact same size of the gap we want...
- Even if it's very likely, we're not sure the gaps we created actually exists
- We don't know the kernel addresses of our gaps
We can fix this
6.3
Another windows tool
NtQuerySystemInformation
SystemExtendedHandleInformation
Retrieve any object's kernel address using its handle
Well known leak
6.4
Advanced Pool Spraying
Step 1 : Derandomize the Pool
Step 2 : Find the perfect gap
7.1
Leak addresses
Check if offsets are correct
Step 2 : Find the perfect gap
Advanced Pool Spraying
7.2
Step 3 : Enjoy your gaps !
Advanced Pool Spraying
- We can predict a future allocation at 100%
- And we know its kernel address
- Just Windows, only Windows
Time to start having fun !
7.3
What do we need
Quota Process Pointer Overwrite:
- The Pool Cookie
- The address of the overflowed chunk
- Arbitrary data in kernel-land at known address
8.1
Arbitrary data in kernel-land at known address
CreatePrivateNamespace() Function:
In paged pool, in the chunk of the object allocated
8.2
Arbitrary data in kernel-land at known address
8.3
What do we need
Quota Process Pointer Overwrite:
- The Pool Cookie
- The address of the overflowed chunk
- Arbitrary data in kernel-land
8.4
The Pool Cookie
- Symbol: nt!ExpPoolQuotaCookie
- Generated at boot
- Good enthropy
8.5
Process Billed encoded:
PoolCookie XOR Chunk Address XOR Pointer
The Pool Cookie
Allocated chunk
Free chunk
Process Billed encoded:
PoolCookie XOR Chunk Address
8.6
The Pool Cookie
- Spray the pool in order to have controllable chunks
- Free a chunk
- Free the chunk just before
- Reallocate a chunk with the size of the gap
- The data is not overwritten... With a correct IOCTL, you might be able to read the old headers... containing the PoolCookie XORED with old chunk address
8.7
About CVE-2017-7441
The Pool Cookie
- Use our input to call the function RtlLookupElementGenericTableAvl
- Write the result in the SystemBuffer for return but doesn't wipe the whole buffer
- Because of unicode and bad calculation, specify a wrong number to the IOManager: the driver write n bytes and tell n+2 to the driver
- 2 bytes Out-Of-Bounds read
- It's enough to leak the PoolCookie !
8.8
What do we need
Quota Process Pointer Overwrite:
- The Pool Cookie
- The address of the overflowed chunk
- Arbitrary data in kernel-land at known address
Let's exploit !
9.1
DEMO
Conclusion
Drivers are still a great attack vector:
- A buffer is used for input/output and we control its size...
- A buffer overflow is exploitable !
Be careful when writing a driver...
- You're dealing with user input in kernel land...
- The tyniest mistake becomes a critical vulnerability
Completely remediate the NtQuerySystemInformation leak !
10.1
QUESTIONS ?
10.2
Thanks for listening !
- A library for Pool Spraying : https://github.com/cbayet/PoolSprayer
- Source code of the exploits : https://github.com/cbayet/Exploit-CVE-2017-6008
- Full paper on Pool Spraying : https://trackwatch.com/windows-kernel-pool-spraying
- Full paper on exploits : https://trackwatch.com
- My twitter: https://twitter.com/OnlyTheDuck
I'm interested in job offers !
deck
By theduck
deck
- 3,440