Saturday, July 11, 2009
Unfortunately, I was only able to attend the first day, which consisted primarily of technical talks on various aspects of forensics, incident response, and live forensics. All the talks were really excellent; Rob Lee and the folks at SANS should be commended for their great work in putting everything together. In this post I'm going to just describe the talks, rather than the panels; unfortunately I forgot to take notes during the panels and so I don't have as much to say about them, other than that they were fun and highly informative.
On to the talks! The first talk of the morning was Richard Bejtlich's keynote, which gave a really great analysis of the current state of the industry and the challenges faced by investigators today. He drew heavily from the Verizon Data Breach Investigations Report, which gave his assertions a nice feel of solidity to them; for example, when he says that we're in bad shape (getting compromised left and right), he can back that up with statistics showing that most intrusions are discovered only through third party notifications. If you're not already reading Richard's posts over at TaoSecurity, I highly encourage it.
After the keynote, Kris Harms got up to talk about live response. He gave a lot of cool tips on how to use some standard tools that most people should be familiar with (pslist, handles, etc.) to quickly triage a system and make a determination on whether it needs deeper analysis. I have to admit that I don't usually think a lot about live analysis--from a standpoint of simply collecting volatile data, I think that memory forensics offers a much better solution. However, from a triage perspective, live analysis makes a lot of sense; you can get a lot of leads very quickly by just knowing how to poke around on the live system.
Nevertheless, I did have one quibble with this talk. It seemed like a lot of the techniques presented, while cool, were a little haphazard. That is, "poking around" isn't necessarily repeatable, which means that as an investigator you could end up missing data by performing a different set of actions on different cases. After all, we're only human, and sometimes we forget things. I personally prefer to make sure that anything I'm going to do more than once is scripted. This allows one to codify an investigative procedure so that it's consistent and repeatable -- think of it as an executable checklist.
For example, in the presentation, Kris Harms described finding hidden processes by using handle.exe and pulling out the PIDs of each handle table it finds (Harlan Carvey now has a nice perl script that automates this). However, there are several rootkit detectors (such as IceSword) that will do this handle table vs. process list cross-view for you. I think we should definitely learn about these techniques and how they work, but I don't see the point in trying to keep them all in your head and do them by hand each time -- put it in a script and let the computer do the work.
After lunch, Harlan Carvey got up to talk about Windows registry analysis, a field that he did a lot of pioneering work in and essentially dominates. Things got a little hectic at the end, as he raced through some information-dense slides on specific kinds of forensic information you could get out of the registry, but overall I really found the talk engaging and illuminating. It also served as a really great motivator for my own talk: he spent a while near the beginning talking about volatile registry data and some of the reasons it's important. This set me up very nicely, since my own presentation was all about extracting registry data from memory. And I didn't even have to bribe him (much)!
Ending out the day (for presentations, at least) was a combined, hour and a half long session on memory analysis with Jamie Butler, Peter Silberman, and me. Peter and Jamie gave a great talk on Memoryze, which is Mandiant's free (as in beer) tool for analyzing volatile memory. Although most of the stuff presented was nothing new if you've been following memory analysis research, it was nice to see their software in action. They also announced the release of a new version of Memoryze, which supports Vista more fully, including the reworked networking code. Peter and Jamie are both very smart, and while I personally prefer Volatility for my own work, I'm glad that people have great options like Memoryze and Volatility to choose from.
Finally, after Jamie and Peter, I gave my own talk on combining registry analysis with memory forensics. There wasn't much new research presented in the talk, but I think it serves as a nice introduction to the toolset for people that haven't seen it before. The slides are available at the bottom of this post (assuming I can get this embedding thing to work), and I'll let them speak for themselves. :)
Once again, a huge thanks to Rob Lee and everyone who organized and attended the SANS Forensics Summit 2009! If you missed it this year, I hope this post has given you a taste of some of the great stuff that goes on there, and will encourage you to go next time!
Wednesday, July 1, 2009
First up, Andreas Schuster has just released a wonderful set of slides on using Volatility to do memory forensics. The slides include:
- Great background material on the how, what, and why of memory acquisition and forensics.
- A refresher on some OS basics you need to really understand memory analysis.
- An amazing and comprehensive walkthrough on how to use a number of Volatility modules plugins in an investigation (including a few of my own tools, like ssdt.py and VolReg).
- Great information on the internals of Volatility, including a tutorial on creating your own plugins.
Second, I wanted to let everyone know once again that I'm going to be speaking at the SANS WhatWorks Summit in Forensics and Incident Response in Washington, DC on how to combine registry analysis and memory forensics for more effective incident response. I'm really looking forward to this event, as it promises to bring together a lot of luminaries from the forensics community, such as Harlan Carvey, Jesse Kornblum, and Chris Pogue, as well some people with a lot of knowledge and experience with offensive techniques like Jamie Butler and Peter Silberman.
If you're planning on attending, or are in the DC area, drop me a note and perhaps we can meet up at the summit!
Monday, June 8, 2009
You can read more about the details of this new way of storing large values in his post, but I wanted to announce the release of a new version of VolReg with experimental support for BIG_DATA values. As always, you can get the latest version of VolReg from my Volatility plugin page. This release also fixes a bug found by AAron Walters where an exception would be raised if the data returned for a value is less than the required amount for that type (e.g., only two bytes being available for a REG_DWORD).
I also updated Volshell, fixing a regression found by J. Hewlett that broke the ability to use the "dt" command to examine a data structure without overlaying it on memory. I also added the ability to pass the "db" and "dd" commands an address space, so that you can now get a hexdump or dword-dump of things like physical memory and registry hive spaces. The syntax for this is "dd(address, space=[addr_space])". More details are available in the online help, which you can read by doing "hh(dd)" or "hh(db)".
Saturday, June 6, 2009
Also, in case you were thinking of being clever, the VM password was "password" ;)
Thursday, May 21, 2009
Anyone who works with registry data for forensics or creates tools to work with the Windows registry would do well to give this a thorough read-through. Thanks to Peter for this excellent contribution!
Monday, March 23, 2009
As part of my research at GT, I've been looking at using Volatility to examine the state of running virtual machines. Using PyXa, a wrapper around Bryan Payne's XenAccess library (available in the tools directory of the latest XenAccess release), you can get access to the memory of Xen guest VMs in Python. From there, it's just a small step to create a new address space that Volatility can use to examine virtual machines just as if they were any other memory image.
One application of this is using introspection to find out the state of windows on screen. This has advanced significantly since the last time I mentioned it, and it's now possible to track windows, including their z-order and some on-screen text, in near-real time. To demo this I used Volatility to examine the internal data structures of Win32k.sys and extract the locations and sizes of all visible windows, and then used PyGame to draw them on screen. The script keeps looping and re-drawing, allowing a near real-time view of what's going on inside the guest VM.
Here's a video of it in action. Notice how the reconstructed view updates to match what's actually going on on screen:
Cool, huh? :D
Thursday, March 12, 2009
From the Guidance mail:
While these utilities [included in the Volatility Framework] can identify running processes, open files and registry handles for running processes and open network sockets and connections, they cannot identify hidden processes, injected DLLs and NIC information.There are three factual inaccuracies in this statement:
- Volatility cannot identify hidden processes.
In fact, Volatility can list processes using multiple methods. The pslist module walks the list of active processess, and will find any processes that have not been hidden with DKOM. The psscan2 module scans memory looking for signatures of process data structures; it will find even those processes that have been hidden using DKOM-like techniques. Together, these can be used to find any hidden processes on the machine.
- Volatility cannot find injected DLLs.
Michael Hale Ligh recently released a plugin called malfind that automates the work of doing exactly this. In fact, it is advanced enough that it can detect many types of generic code injection as well as simple DLL injection. I'm not familiar with Guidance's offering in this area, but I strongly suspect that they do not handle as many types of code injection.
- Volatility cannot get NIC information.
Again, this is false. My own registry tools can examine the registry keys that describe the network interfaces on the machine. If this is too much work for an investigator, the recent integration with RegRipper will make this task even easier. In the example RegRipper log I posted, you can see the network card information has been gathered from the memory image.
Tuesday, March 3, 2009
I've also updated the registry tools yet again, to fix some bugs and add new functionality, and also made some enhancements to volshell. You can read about the changes below:
Changes to VolReg:
- New command hivedump: dump keys and timestamps (and optionally value data) from all hives to a CSV file.
- Many improvements to robustness and error handling when reading key and value data.
- When checking the registry hive names, catch exceptions and try to continue anyway (reported by chris).
- A new command, dis, is available. If distorm is installed, it will disassemble bytes from a given memory address as x86 code.
- db no longer rounds length to a multiple of 4.
- Use a single profile object throughout all commands (speed improvement)
- dt can now overlay an arbitrary structure at an address, for example: dt('_EPROCESS', 0x81234567)
Sunday, March 1, 2009
I'll get to the details of how this works later, but for now let's talk about how you actually use this stuff. First of all, since we depend on Inline::Python to manage the unholy union of Perl and Python, you'll need to get it from CPAN or your distribution's package manager. No need to install Parse::Win32Registry; I've replaced it with my own registry code that will run against memory.
Next, you should download the latest version of the registry tools [tarball, zip] (side note: I updated them yet again, fixing a couple bugs and adding some basic checking to make sure you've got the right hives when using the credential dumping plugins), as well as the VolRip package [tarball, zip]. Unpack both into your Volatility directory.
Finally, you'll need a list of the virtual addresses of each registry hive in the image you want to examine. You can generate this list by first running the hivescan plugin to find the physical address of any hive, and then passing that to the hivelist plugin. You can see the results for the xp-laptop-2005-07-04 image here. For this example, we'll be using the SYSTEM hive, which is at address 0xe1035b60 in that image.
Now, let's run RegRipper! We're going to run the system plugins against the xp-laptop-2005-07-04 image, like so:
perl rip.pl -r xp-laptop-2005-07-04-1430.img@0xe1035b60 -f system
You can see the results here, if you can't follow along directly at home. If you're familiar with RegRipper, you'll notice that where we usually give the path to the registry hive, we've instead given the path to the memory image, and the virtual address of the hive we want to examine (here, the SYSTEM hive).
That's really about all there is to it! You use rip.pl just as you always would, but instead of giving it the hive filename, you instead pass the image and address of the hive, separated by an "@" sign. You can still run individual plugins using -p, use the "hive guessing" feature with -g, or run a whole batch of plugins using -f. Now, if you want to know more about how this works, read on...
The basic idea was to create a set of Python objects that emulated the interface provided by James Macfarlane's Parse::Win32Registry as closely as possible. This is what regwrap.py does: provides a translation layer between my own registry API and the one exposed by Parse::Win32Registry. Once we've done that, we can drop this emulated object into rip.pl, and the Perl code will run happily, thinking it's operating on normal hive files.
I had to make the following changes to rip.pl to get this to work:
- Instead of importing Parse::Win32Registry, use Inline::Python to import my own wrapper class and bind it to the name "Parse::Win32Registry".
- Comment out the lines that check to make sure the hive file exists -- since we're smushing the memory image and hive address into a single "filename", those checks will now fail.
- Minor changes so that rip.pl works on Linux.
However, there was still one small wart that I couldn't get rid of just by emulating the library. See, in Perl, you can call a function in two contexts: "scalar" and "array". This basically means, "is the function result being stored in an array, or in a scalar variable"--and functions can decide to do different things depending on what context they're called from. An example of this is the get_data method of Value objects in Parse::Win32Registry.
The get_data method, when called on a REG_MULTI_SZ value, will return an array of strings if called from array context, but returns a string with all the strings separated by spaces if called in a scalar context. Unfortuantely, the Python code has no way of telling what Perl context it's being called from, so my wrapper always returns a list. This means that a couple of plugins (shares.pl and nic_mst2.pl) would print "ARRAY(0x12345)" instead of the actual data in some cases.
Instead of trying to come up with a convoluted way around this, I opted to just change the two plugins in question to remove any ambiguity as to how the function was called. I'm still not sure I've identified all the plugins that do this (I tried to run them all to check, but may have missed something), but the results look good to me now.
So, to summarize: it's now possible to run RegRipper against memory images! The modifications required were pretty minimal, so it should be easy to keep things updated as new versions of RegRipper come out. In particular, aside from the two plugins I mentioned, upgrading the plugins should be as easy as just dropping them into the rrplugins directory.
Enjoy, and as always, let me know if you find any bugs :)
Thursday, February 12, 2009
Friday, January 23, 2009
The list of fixes is:
- Fix a bug that prevented any volatile subkeys from appearing when using the subkeys() function.
- Add a check for None when using lsadump (reported by Paul Bobby, thanks!)
- Add appropriate license statements at the top of each file (thanks AAron!). For the record, the license is the GNU General Public License (GPL).
One final note: I have seen some crashes when people attempt to use the hash extraction code, but pass the wrong address for the hive in memory. I'd like to fix this, but I don't yet have a good way of checking to make sure that a given hive is the SYSTEM or SAM or SECURITY hive. I'll try to find something that works, though, and release it with the next update.
Friday, January 16, 2009
To use them, grab either the zip or the tarball and extract it to your Volatility directory. You'll get the following new plugins (along with some supporting files):
- hivescan: finds the physical address of CMHIVE structures, which represent a registry hives in memory
- hivelist: takes a physical address of one CMHIVE, returns the virtual address of all hives, and their names
- printkey: takes a virtual address of a hive and a key name (e.g., 'ControlSet001\Control'), and display the key's timestamp, values and subkeys
- hashdump: dump the LanMan and NT hashes from the registry (deobfuscated). See this post for more details on how this is accomplished.
- lsadump: dump the LSA secrets (decrypted) from the registry. See this post for more information.
- cachedump: dump any cached domain password hashes from the registry. This will obviously only work if the memory image comes from a machine that was part of a domain. See this post for more details.
- Use hivescan to find the physical address of a hive.
- Pass one of those (any of them should do) to hivelist using the -o option. This will give you the virtual address of each of the hives in memory.
- With this list in hand, you can now examine individual keys within a hive using printkey, or use hashdump, lsadump, or cachedump to extract credentials from the memory image. The latter three need the virtual addresses of specific hives (SYSTEM and SAM for hashdump, SYSTEM and SECURITY for lsadump and cachedump).
If you're curious how registry access works under the hood, you can read my DFRWS paper or presentation, or check out the blog posts I wrote while doing that research: Enumerating Registry Hives, Reading Open Keys, and Cell Index Translation. And, of course, you can always just look at the source code :)
Some final, closing thoughts. Harlan Carvey's RegRipper has been a huge sucess, and has shown a lot of people how much forensic information is stored in the registry. It would be awesome if this great tool could be applied to memory forensics, but unfortunately I have not yet figured out a way to integrate the two. However, this perl module looks promising; perhaps someone could write a Python wrapper around my registry code that would expose an interface compatible with Parse::Win32Registry, allowing RegRipper to run against a memory image with only slight modifications.
Of course, since RegRipper plugins are all written in Perl, you could also just see what they're doing and reimplement it as a Volatility plugin! To make that easier, here's a quick guide to using the new registry API in Volatility:
- Start by opening a hive and assigning it to an address space. The HiveAddressSpace represents a hive in memory, and takes a virtual address space and offset to a hive as a base. Also, because the registry types are not part of Volatility's standard types, you need to add them in.
from forensics.win32.hive2 import HiveAddressSpace
from forensics.win32.regtypes import regtypes
syshive = HiveAddressSpace(addr_space, types, syshive_address)
- Next, use the get_root() function to find the root key of the hive. You need to pass in the current profile.
from forensics.win32.rawreg import *
from forensics.object2 import Profile
theProfile = Profile()
root = get_root(syshive, theProfile)
- To open a key, use open_key():
key = open_key(root, ["ControlSet001", "Control", "Lsa"])
- To get a list of subkeys of a key, use subkeys():
for sk in subkeys(key):
- To get the values of a key, use values():
for v in values(key):
- To parse the value data and return it in a more meaningful representation, use value_data():
for v in values(key):
val_type, val_data = value_data(v)
print v.Name, val_type, val_data
That's pretty much all you need to know! You can access other attributes of keys and values as members of the Python objects returned. The attributes available can be found in regtypes.py; keys are _CM_KEY_NODE objects and values are _CM_KEY_VALUE objects.
I don't have time to write any more, unfortunately, but I hope these will be useful to people! I'll try to post an example of a RegRipper plugin converted to a Volatility one soon so there's a concrete example to work with. Until then, enjoy and feel free to e-mail me (or leave comments) with any questions!
Tuesday, January 6, 2009
By now, you all probably know that you can dump running programs from memory using the procdump module in Volatility. But not all malware runs as a user-mode process. What about malicious kernel modules?
As it turns out, dumping these is also quite straightforward, and it's easy to write a plugin to do it. In fact, it's downright trivial -- kernel modules are just PE files mapped into kernel memory (in exactly the same way as normal programs are PE files mapped into user memory). So to dump a particular kernel module, we can use Volatility's built-in PE dumper (the source is in forensics/win32/executable.py, and point it at the memory address of a kernel module.
Naturally, I've made a plugin that implements this: grab moddump.py and put it in your memory_plugins directory, and you'll be good to go. Here's what it looks like in action:
$ python volatility moddump --help
Usage: moddump [options] (see --help)
-h, --help show this help message and exit
-f FILENAME, --file=FILENAME
(required) XP SP2 Image file
-b BASE, --base=BASE (optional, otherwise best guess is made)
Physical offset (in hex) of directory
-t TYPE, --type=TYPE (optional, default="auto") Identify the
image type (pae, nopae, auto)
-m MODE, --mode=MODE strategy to use when saving executable.
Use "disk" to save using disk-based section
sizes, "mem" for memory-based sections.
-u, --unsafe do not perform sanity checks on sections
-o OFFSET, --offset=OFFSET
dump module whose base address is OFFSET (hex)
-p REGEX, --pattern=REGEX
dump modules matching REGEX
-i, --ignore-case ignore case in pattern match
The "mode" and "unsafe" options do the same thing as in the procdump module. The other options are new though, so I'll go through them briefly here.
The -p option allows you to give a regular expression to specify which modules to dump. The -i option allows you to make this match case insensitive. If you don't give any way of specifying a module, it will simply dump all modules in the kernel's loaded module list.
Of course, if a driver is being stealthy, it could unlink itself from the kernel's list of loaded modules (just as processes can be hidden by removing from the systemwide process list). Often, these hidden drivers can be found by scanning memory for the data structure that represents a kernel module; Volatility's modscan and modscan2 are good for this. Once you've found the hidden module, you can pass its base address to moddump using the -o option.
Regardless of how you choose the modules to dump, they will be saved in a file called driver.BASE_ADDRESS.sys, where BASE_ADDRESS is the module's address im memory.
Anyway, I hope you'll get some good use out of this. It's also possible to create a similar plugin that dumps DLLs loaded in a process, but I haven't gotten around to writing it yet, so if anyone's looking to get their feet wet with writing plugins for Volatility it could be a fun first project.
Cheers and Happy New Year until next time!