Thursday, February 6, 2014

Forensics Quickie: Pinpointing Recent File Activity - RecentDocs

FORENSICS QUICKIES! These posts will consist of small tidbits of useful information that can be explained very succinctly.

[UPDATE #02 06/09/2016]: Juan Aranda (@jharanda1) wrote a more portable Python script to automate the process detailed in this post. It uses Willi Ballenthin's (@williballenthin) python-registry. The script by Eric (below) used a module that could only be run on Windows (and left some clutter when run against an NTUSER hive). Being able to run Juan's script on OS X, Windows, and Linux is helpful. I really like the output format and that it doesn't leave any extra clutter after parsing, so this is my go-to script for this kind of analysis now. You can find more info about the script at Juan's blog (RaptIR) here.

Note that Phill Moore (@phillmoore) also has a RegRipper plugin built for this technique, as well. There are many options out there, so test which one you like best. You can find Phill's plugin here.

[UPDATE #01 05/01/2015]: A Python script has been created to automate the process detailed in this post. You can download Eric Opdyke's (@EricOpdyke) script here.

Let's revisit the basics...

Scenario
A suspicious employee left your company on January 28, 2014. You'd like to know which files were most recently used (opened, saved) on the employee's system right before he/she left.

The Solution
Pull the user's NTUSER.DAT. Run RegRipper to easily output the the values within the Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs subkey.

To give some background, the RecentDocs subkey will contain a few things:
  • Subkeys named after every file extension used on the system (e.g. a subkey for .zip, .doc, .mp4, etc.). 
    • Each of these subkeys will contain its own MRUListEx value that keeps track of the order in which files were opened. (Sound familiar? We also saw use of the MRUListEx value upon analyzing shellbags artifacts). 
    • Each subkey will store up to 10 numbered values; each numbered value represents a recently opened file with the extension found in the subkey's name.

     
    The .gif subkey showing the 10 most recently opened .gif files for a specific user. The order is stored in MRUListEx.

  • A subkey for folders most recently opened.
    • Can store up to 30 numbered values (i.e. the 30 most recently opened folders).
  • A root MRUListEx value
    • Stores the 149 most recently opened documents and folders across all file extensions.

With that, take note that MRU times are powerful; here's why:

Since every extension has its own subkey, we will have quite a few registry key LastWrite times with which to work. But so what? When dealing with RecentDocs, the LastWrite time only applies to the most recently opened file within that subkey. While this is certainly the case, we mustn't forget that we also have an all-encompassing MRUListEx in the root of the RecentDocs subkey.

So what does this mean? By using the LastWrite times of each subkey and the root MRUListEx list, we can more accurately determine when certain files were last opened. While we won't be able to get an EXACT time for non-MRU (i.e. files that are not the first entry in the MRUListEx value), we may be able to determine a time range in which these files were opened. Consider the following example:



Our root MRUListEx shows:

RecentDocs
**All values printed in MRUList\MRUListEx order.
Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs
LastWrite Time Thu Feb  6 14:08:49 2014 (UTC)


  26 = smiley.gif
  99 = strange_bird.jpg
  42 = books_to_read.csv
  130 = secret_clients.csv
  55 = zip_passwords.rtf
  87 =
my_diet.csv
  3 = contacts.csv
  74 = phillip.csv
  72 = notes.txt

  ...

At this point, if we look at the first few entries of the root MRUListEx, we can really only tell that smiley.gif was last opened on Feb 6, 2014. So let's mark it:

  26 = smiley.gif ............................Feb  6 14:08:49 2014
  99 = strange_bird.jpg
  42 = books_to_read.csv
  130 = secret_clients.csv
  55 = zip_passwords.rtf
  87 =
my_diet.csv
  3 = contacts.csv
  74 = phillip.csv
  72 =
notes.txt
  ...

That secret_clients.csv looks pretty interesting. Let's look at the .csv subkey to see if we can find out when it was opened.

The .csv subkey's MRUListEx shows:

Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\.csv
LastWrite Time Sat Jan 18 19:19:22 2014 (UTC)
MRUListEx = 6,2,1,7,3,5,4
  

  6 = books_to_read.csv  
  2 = secret_clients.csv
  1 =
my_diet.csv
  7 = contacts.csv
  3 = phillip.csv
  ...

Dang. Looks like the books_to_read.csv file is the most recently opened .csv, which means that the Jan 18 19:19:22 2014 LastWrite time of the .csv subkey is going to represent the last time that that file was opened -- not secret_clients.csv. I guess we can give up on this one...

...or...we could look at the surrounding files to glean some more information. First, let's mark the known LastWrite time in our root MRUListEx list.

  26 = smiley.gif ............................Feb  6 14:08:49 2014
  99 = strange_bird.jpg
  42 = books_to_read.csv...............Jan 18 19:19:22 2014
  130 = secret_clients.csv
  55 = zip_passwords.rtf
  87 = my_diet.csv
  3 = contacts.csv
  74 = phillip.csv
  72 =
notes.txt
  ...

Looking at our list, we can see that there are two open times that we know for sure. We can also see that there is another file that was opened between these times. It looks like strange_bird.jpg was opened after smiley.gif, but before books_to_read.csv. Since this list is an all-encompassing list, it would be safe to say that between January 18 and Feb 6, strange_bird.jpg was opened. But let's go ahead and confirm that.

The .jpg subkey's MRUListEx shows:

Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\.jpg
LastWrite Time Sat Jan 18 21:54:57 2014 (UTC)
MRUListEx = 4,2,3,1
  

  4 = strange_bird.jpg 
  2 = stone_tanooki.jpg
  3 = camel.jpg

  1 = fighting_frogs.jpg

It looks like strange_bird.jpg is the most recently opened .jpg on the system. That means that the Jan 18 21:54:57 2014 LastWrite time of the .jpg subkey represents the the time at which strange_bird.jpg was opened. Again, let's mark it in our root MRUListEx list:

  26 = smiley.gif ............................Feb  6 14:08:49 2014
  99 = strange_bird.jpg...................Jan 18 21:54:57 2014
  42 = books_to_read.csv...............Jan 18 19:19:22 2014
  130 = secret_clients.csv
  55 = zip_passwords.rtf
  87 =
my_diet.csv
  3 = contacts.csv
  74 = phillip.csv
  72 =
notes.txt
  ...

At this point, we still don't know when secret_clients.csv was last opened. Upon finding its LNK file, we note that it had been first opened in late 2013 (LNK creation time). If this machine was running XP, we would be able to grab the access time of this LNK file to see when it *might* have been last opened. Alas, we are using Windows 7 (disclaimer: there are tons of other things you should be looking at anyway; this is merely one example of why we would want to look at RecentDocs). Let's keep moving.

Taking a second look at our root MRUListEx list, we notice that the next item after secret_clients.csv is zip_password.rtf. That also looks interesting, so let's see when that was opened.

The .rtf subkey's MRUListEx shows:

Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\.rtf
LastWrite Time Sat Jan 17 14:15:31 2014 (UTC)
MRUListEx = 2,1
  

  2 = zip_passwords.rtf 
  1 = fiction_novel.rtf

It looks to be the first one, so we can use the LastWrite time to mark it in our list.

  26 = smiley.gif ............................Feb  6 14:08:49 2014
  99 = strange_bird.jpg...................Jan 18 21:54:57 2014
  42 = books_to_read.csv...............Jan 18 19:19:22 2014
  130 = secret_clients.csv
  55 = zip_passwords.rtf.................
Jan 17 14:15:31 2014
  87 = my_diet.csv
  3 = contacts.csv
  74 = phillip.csv
  72 =
notes.txt
  ...

With that, we have found a pretty tight time frame as to when secret_clients.csv was last opened. We don't have the exact date and time, but we can now say that is was last opened somewhere between Jan 17 and Jan 18.

It looks as though there are some more .csv files that were recently opened, and by the looks of it, that .txt file might be able to help us hone in on a time frame.

The .txt subkey's MRUListEx shows:

Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\.txt
LastWrite Time Sat Jan 10 18:23:08 2014 (UTC)
MRUListEx = 4,5,2,1,3
  

  4 = notes.txt 
  5 = groceries.txt
  2 = how_to_make_toast.txt
  1 = my_novel.txt
  3 = address.txt
  ...

Just as before, let's mark the LastWrite time in our root MRUListEx list.

  26 = smiley.gif ............................Feb  6 14:08:49 2014
  99 = strange_bird.jpg...................Jan 18 21:54:57 2014
  42 = books_to_read.csv...............Jan 18 19:19:22 2014
  130 = secret_clients.csv
  55 = zip_passwords.rtf.................
Jan 17 14:15:31 2014
  87 = my_diet.csv
  3 = contacts.csv
  74 = phillip.csv
  72 =
notes.txt...............................Jan 10 18:23:08 2014
  ...

Again, we don't have an exact date and time as to when the my_diet.csv, contacts.csv, and phillip.csv files were last opened. But, based on the LastWrite time of the .txt subkey, we do know the time frame in which these files were opened.

Now imagine that a USB device was also plugged in at some point within this time frame. It is possible that the suspicious employee may have done a "Save As..." on contacts.csv and saved it to the external device. It is also possible that the employee opened the file and copy/pasted the information into an email. Of course, the possibilities are endless, but you get the point.

And it goes without saying that other artifacts, such as LNK files, jump lists, ComDlg32, OfficeDocs, and more should also be used to complement RecentDocs analysis. In particular, ComDlg32 would be of interest in this scenario, as it will show you files recently opened/saved. It offers more information (e.g. the executable used to open the file, the file's path, etc.) and stores saves/opens by extension, as well. As such, we can use this same technique to pinpoint file open/save times (though, it is a bit limited, as the * extension subkey will only show up to 20 entries).

This post quickly became longer than expected, but it's still a quickie. I'll end with this:

This is nothing new. All of this data is available to you in the Windows registry. This is a fairly basic technique, but it is also one that shouldn't be overlooked. And as always, use more than one artifact to make your case.

-Dan Pullega (@4n6k)

11 comments:

Harlan Carvey said...

Dan,

Yet another excellent post, thanks!

There are a couple of other locations that are new to some versions of Office, specifically the TrustRecords, and the Reading Locations (new to Office 2013), that may be of value, as well.

Again, thanks for sharing this info.

Harlan Carvey said...

By illustrating multiple locations to for corresponding/corroborating artifacts, you're helping analysts how to identify and overcome the use of anti-forensics techniques.

4n6k said...

Thanks, Harlan.

This one is quick and easy. I agree with you on the Office items; the reading locations finding was definitely interesting. For anyone interested, more on that can be found here: http://dfstream.blogspot.com/2014/01/ms-word-2013-reading-locations.html

Ken Pryor said...

Excellent post, Dan! Posts like this are so helpful to everyone, especially people who don't do forensic analysis every day. Great job and thanks for sharing!

KP

davnads said...

Fascinating. Love it!

Craig McGannon said...

This is nicely laid out. Thank you!

Randomaccess said...

ive written a rough regripper plugin to do this. will have to clean up the code a bit later buts worked in testing so far
https://github.com/randomaccess3/4n6_stuff/blob/master/Recentdocs_tln.pl

4n6k said...

Randomaccess: I really like the idea here. The concept is good and you've got a nice prototype there. But as I mentioned on Twitter, there's an issue.

I tested this against my own NTUSER.DAT. I ran both Harlan's and your plugin on the same data set. I then looked at any extension that had more than 1 value in it. Here's an example:

The original plugin outputs this for the .docx key:

Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\.docx
LastWrite Time Wed Feb 5 19:45:44 2014 (UTC)
MRUListEx = 4,0,2
4 = some_document.docx
0 = apples_oranges.docx
2 = forensics.docx

In your plugin, I'm seeing the "apples_oranges.docx" show up with the MRU time. This is not right, as it should be the "some_document.docx" that is assigned the MRU time. It looks like your plugin is always pulling the filename of the entry with the lowest number (which is 0).

This is an important thing to remember when working with MRUs: the lowest number does not always mean it is the most recently used. In the above example, we see that the MRUListEx stores the values in this order: 4,0,2. So the "4" value is actually the MRU and should be assigned the key's LastWrite time.

To fix it, you can pull the first entry (first 4 bytes) of MRUListEx in every one of the extension keys, then assign the LastWrite time of that extension key to THAT number. So if the first entry in MRUListEx is 4, pull the filename for 4 instead of the filename for 0 (it looks like your code is hitting the 0 value every time). Then output the unix time next to the filename for 4.

Again, this looks good, but it's assigning the LastWrite times to the wrong filenames. Make sure they are being assigned to the MRU document for each extension and you've got a nice plugin.

Please keep me updated.

-Dan (@4n6k)

randomaccess said...

Fixed now.
Dont write plugins in a rush and make silly mistakes. I was aware of the last write times and the way they're meant to be attributed but I didn't check that I'd changed the value from 0 to the element 0 in the list.
Fixed now, can be found at https://github.com/randomaccess3/4n6_stuff/blob/master/regripper_plugins/Recentdocs_tln.pl

Over the next few days I'll try create some test ntuser.dat's in vms and test it again to make sure it works

randomaccess said...

i broke your link to my regripper plugin by renaming the file
correct link is now https://github.com/randomaccess3/4n6_stuff/blob/master/regripper_plugins/Recentdocs_timeline.pl to avoid clashing with the other recentdocs_tln plugin

4n6k said...

Thanks, Phill. I updated the link.

Post a Comment