Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Arbitrary Kernel Address Increment via NtQuerySystemInformation- 2028

pwn2nimronPosted 19 Days Ago
  • The author of this post was looking to compete in Pwn2Own this year in the Web Browser category. The target was to escape Chrome's renderer sandbox via a Windows bug, starting from a compromised renderer. The sandbox makes the attack surface very small. It only leaves a handful of NT syscalls: file operations, registry and system information queries.
  • Initially, they didn't want to review NtQuerySystemInformation because it's the most audited syscall. They just kept coming back to it... There's a funny paradox: places where everyone assumes someone else has carefully looked have less scrutiny because of that assumption. They had pulled out bugs from these places before, so they opened up IDA to look for bugs.
  • Info class 253 is SystemProcessInformationExtension. When length is 0 on ProbeForWrite(), it's a NOP, where the body is gated on an if statement of the length. This means that any pointer passed in, including kernel pointers, passes through the write loop without validation. The function stores the buffer pointer into pExtensionOut and increments the value at the address. This creates a direct arbitrary kernel address increment primitive. Classes 5 and 252 have proper bounds checks before writes.
  • This bug is enough to escape the sandbox, after a KASLR bypass via the prefetch side-channel tool. In phase one, they use the bug to create an out-of-bounds read via corrupting a length value on a type. Next, they increment a NULL pointer into the Usermode range with data that we control as a pointer to something else. This works because there's no SMAP on Windows. This creates a user-controlled object that contains pointers and can be rewritten repeatedly because it's in user space. First, they create an arbitrary kernel read primitive of 2 bytes at a time.
  • The _TOKEN structure contains privilege bitmasks. Notably, SeDebugPrivilege is bit 20 of this bitmask. By using the original write primitive, we can set the process flag to contain the debug capabilities. This allows for reading and writing to memory arbitrarily for any process; they chose to write into winlogon.exe because it's always on and has SYSTEM privileges.
  • This is a fantastic post that explains the why as much as the how. There are many subtle things, like how the NULL pointer incrementor works, because there is no SMAP. If you're looking into what real exploit development looks like, this is a great article.