Saturday, February 18, 2012

Adventures in the Windows NT Registry: A step into the world of Forensics and Information Gathering

Adventures in the Windows NT Registry: A step into the world of Forensics and Information Gathering:

As of a few days ago, the Metasploit Framework has full read-only access to offline registry hives. Within Rex you will now find a Rex::Registry namespace that will allow you to load and parse offline NT registry hives (includes Windows 2000 and up), implemented in pure Ruby. This is a great addition to the framework because it allows you to be sneakier and more stealthy while gathering information on a remote computer. You no longer need to rely on arcane Windows APIs with silly data structures and you can interact with the registry hives in an object-oriented manner. Combined with the recent ShadowCopy additions from TheLightCosine, you have a very powerful forensics suite at your fingertips.

Before I get ahead of myself, I should explain exactly what the registry is and why it matters.

When you open up regedit on a Windows computer, regedit is actually opening many different registry hives. A registry hive is a binary file that is stored either in C:\Windows\System32\config (SYSTEM, SOFTWARE, SAM, SECURITY) or in a user's profile (NTUSER.dat). These hives store system information and configurations, user information, and all sorts of just interesting information (group policy settings for instance). These files are locked while Windows is running. In the past, we have used methods like exporting specific hives in order to get around this lock, and this still works well enough. We now have the option of using the Volume Snapshot Service, or VSS, to create a copy of a hive while locked. However, there has been no good way to analyse and parse these hives on a system that wasn't running Windows after copying them.

The easiest way is to create copies of the hives, and pull them down to your local machine in a centralised place. I used 'reg SAVE HKLM\$HIVE $HIVE.hive', substituting $HIVE for the actual hive name, then download'ed the copied hive in meterpreter.

root@w00den-pickle:/home/bperry/Projects/new_hives# file ./* 
./sam.hive: MS Windows registry file, NT/2000 or above
./security.hive: MS Windows registry file, NT/2000 or above
./software.hive: MS Windows registry file, NT/2000 or above
./system.hive: MS Windows registry file, NT/2000 or above
root@w00den-pickle:/home/bperry/Projects/new_hives#

You will find a new tool within the source tree called reg.rb (tools/reg.rb). This script consumes the Rex::Registry library and has many predefined methods to help speed up IG. Work is still being done on reg.rb, it has a lot of potential. Ideas or functionality requests are appreciated. Patches too.

A small primer on how the registry stores data is in order. WIthin a registry hive, you have 5 value types:

0x01 -- "Unicode character string"

0x02 -- "Unicode string with %VAR% expanding"

0x03 -- "Raw binary value"

0x04 -- "Dword"

0x07 -- "Multiple unicode strings separated with '\\x00'"

Types 1, 2, and 7 can be printed to a screen in a readable form without much issue. Types 3 and 4, however, are binary types and will be printed out in their base16 representations (\xde\xad\xbe\xef). Keep this in mind when querying values from a registry hive.

For instance, let's say we need to find out the Default Control Set in order to query correct values pertaining to drivers or the boot key. Your query would look similar to this:

root@w00den-pickle:~/tools/metasploit-framework/tools# ./reg.rb query_value '\Select\Default' /home/bperry/Projects/new_hives/system.hive
Hive name: SYSTEM
Value Name: Default
Value Data: "\x01\x00\x00\x00"
root@w00den-pickle:~/tools/metasploit-framework/tools#

This tells us that the Default Control Set is ControlSet001. When we query the root key ('', "", '\', or "\\") of the SYSTEM hive, we will see the available ControlSets:

root@w00den-pickle:~/tools/metasploit-framework/tools# ./reg.rb query_key '' /home/bperry/Projects/new_hives/system

Hive name: SYSTEM

Child Keys for

===============

Name Last Edited Subkey Count Value Count

---- ----------- ------------ -----------

ControlSet001 2010-08-21 08:56:36 -0500 4 0

ControlSet002 2010-08-21 16:05:32 -0500 4 0

LastKnownGoodRecovery 2011-12-13 21:22:55 -0600 1 0

MountedDevices 2010-08-21 08:56:18 -0500 0 4

Select 2010-08-21 16:05:32 -0500 0 4

Setup 2010-08-21 16:05:33 -0500 4 6

WPA 2010-08-21 16:08:33 -0500 4 0

Values in key

==============

Name Value Type Value

---- ---------- -----

root@w00den-pickle:~/tools/metasploit-framework/tools#

When querying the hives, the library queries relatively from the root key. On XP machines, the root key is always named $$PROTO.HIV. On Vista+, the root key is always named along the lines of CMI-CreateHive{F10156BE-0E87-4EFB-969E-5DA29D131144}. The guid will be variable. This is important to note because many times a key will be given to you in this form:

HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\

In the above example, there are actually three parts. HKLM stands for HKEY_LOCAL_MACHINE. This tells regedit to load the local registry hives. The second part, Software, tells regedit the key is in the SOFTWARE hive. The third part, Microsoft\Windows\CurrentVersion\Uninstall, is the actual key path relative to the root key in the hive. Since reg.rb only looks at arbitrary hives, the first two parts aren't needed.

If you were to query the above key with reg.rb, the command would look like this:

reg.rb query_key '\Microsoft\Windows\CurrentVersion\Uninstall' /path/to/hive/SOFTWARE

This would enumerate the installed programs on the computer along with the date and time the key was created. Generally, the keys in the above key are created when the program is installed, so you can see how long a program has been installed on a computer as well.

The library also allows you to query for data that would otherwise be hidden. Each nodekey has the ability to have a classname. This classname isn't shown in regedit, and some very important information can be held in this container. For instance, the boot key is stored in 4 separate key classnames that would otherwise not be accessible. reg.rb allows you to query for the boot key easily:

root@w00den-pickle:~/tools/metasploit-framework/tools# ./reg.rb get_boot_key /home/bperry/tmo/hives/SYSTEM
Getting boot key
Root key: CMI-CreateHive{F10156BE-0E87-4EFB-969E-5DA29D131144}
Default ControlSet: ControlSet001
3b53e09758c0f142a1771c47798b0b01
root@w00den-pickle:~/tools/metasploit-framework/tools#

Accessing the hives programmatically

You may find yourself wanting to work with the hives programmatically, via a resource script with ERB, or straight from irb. The main class you will be working with is Rex::Registry::Hive. You perform queries directly off of the hive object.

msf > irb
[*] Starting IRB shell...

>> require 'rex/registry'
=> true
>> hive = Rex::Registry::Hive.new('/home/bperry/tmo/hives/SYSTEM'); nil
=> nil
>> hive.hive_regf.hive_name
=> "SYSTEM"
>> hive.root_key.name
=> "CMI-CreateHive{F10156BE-0E87-4EFB-969E-5DA29D131144}"

In the above example, we create a new hive object. Every hive has a root key, and begins with a regf block(which tells you what the name of the hive is, among other things). A root key is simply a nodekey with a special flag.

>> hive.root_key.lf_record.children.each { |k| p k.name }; nil

"ControlSet001"

"ControlSet002"

"MountedDevices"

"RNG"

"Select"

"Setup"

"WPA"

=> nil

Every nodekey will have either an lf_record or a valuelist (or both!). The lf_record contains the child nodekeys. The valuelist contains the child values.

>> valuekey = hive.value_query('\Select\Default'); nil

=> nil

>> nodekey = hive.relative_query('\ControlSet001\Control\Lsa'); nil

The value_query method of the hive returns a ValueKey. The relative_query method returns a NodeKey. Performing a relative_query on a value's path rather than a node's path will return the value's parent node.

As you can see, the library is quite powerful. It gives you a lot of control over your offline hives when performing forensics or IG. There is a lot of work to be done, with write support in the future very possible. I look forward to seeing what cool modules the community can cook up that utilizes the library. Be sure to update the framework to its latest version to ensure you have the most up to date library to play with.