Monday, September 11, 2017

Windows kernel pool spraying fun - Part 2 - More objects

In the second part I will explore more object sizes. The process to get the actual size is fairly simple as we saw it, however it can be a manually intense process if we need to do it many times, and thus it should be automated, before wasting more time on it. It's good to do it manually a few times, especially for learning, but there is no point repeating when not needed. So how we script WinDBG? With pykd! pykd is an excellent Python extension for WinDBG, it even allows us to script WinDBG if we don't even start it manually.

First thing is to install pykd, which can be a headache sometimes. It's not always as straightforward as it sounds. Probably the easiest if we download the precompiled version, and place pykd.pyd file in the winext directory of WinDBG. It's very important that the architecture of WinDbg, Python, VCRedist and pykd are all the same (x86 or x64). You can also install pykd via PIP, but I didn't find it working when trying to import. Also be sure to have the latest version of Python (2.7.13), with some older versions (like 2.7.9) WinDBG used to exit for me, when starting pykd. With even older version of Python (2.7.1) it used to work. But once it's up, it's a very powerful extension.

So I wrote a short function that gets a name and handle, and will lookup the size of the object. There might be other, more elegant ways to do this, but it worked for me:

def find_object_size(handle,name):
#find windbg.exe process
wp = dbgCommand('!process 0 0 windbg.exe')
#print wp
#extract process "address"
process_tuples = re.findall( r'(PROCESS )([0-9a-f]*)(  SessionId)', wp)
if process_tuples:
process = process_tuples[0][1]
print "Process: " + process

#switch to process context
dbgCommand(".process " + process)
#find object "address"
object_ref = dbgCommand("!handle " + h)
object_tuples = re.findall( r'(Object: )([0-9a-f]*)(  GrantedAccess)', object_ref)
if object_tuples:
obj = object_tuples[0][1]
print "Object: " + obj

#find pool
pools = dbgCommand("!pool " + obj)
#print pools

#find size
size_re = re.findall(r'(\*[0-9a-f]{8} size:[ ]*)([0-9a-f]*)( previous)',pools)
if size_re:
print name + " objects's size in kernel: " + size_re[0][1]

#close handle

This will ease our job finding the pool size allocated. With this I will take a look at the following objects:

Job (named and unnamed)
Semaphore (named and unnamed)

It's quite straightforward from this point, we just need to call the related user mode function, create an object, and check the size. I created a short script for WinDBG that will create the above objects, and then check for their sizes, and print them out. I uploaded the script here:

To use the script:
  1. Start WinDBG
  2. Kernel debug -> Local
  3. Issue the command: .load pykd
  4. !py path_to_the_script

The result:

Not Named Mutex objects's size in kernel: 0x50
Named Mutex objects's size in kernel: 0x60
Job objects's size in kernel: 0x168
Job objects's size in kernel: 0x178
IoCompletionPort objects's size in kernel: 0x98
Event objects's size in kernel: 0x40
IoCompletionReserve objects's size in kernel: 0x60
Not named Semaphore objects's size in kernel: 0x48
Named Semaphore objects's size in kernel: 0x58

This will give us a good set of objects that can be used for pool spraying.

And what is "kex" and what to expect there? Well, you will see more cool kernel stuff. ;-) 

No comments: