Monitoring file system changes with PowerShell

I recently returned from facilitating Lenny Zeltser‘s excellent Reverse Engineering Malware course at SANS Security West.  One of the utilities covered in the course is called CaptureBAT, which is a useful utility for monitoring a system for changes while performing malware analysis.  Of course, given my ongoing interest in PowerShell, I decided to see if I could emulate some of CaptureBAT’s file system monitoring functionality natively in a PS script.

There are several strategies that you can use to monitor the file system in PowerShell and I decided to use the .Net framework to help accomplish this task.  Here’s how I did it:

  1. Create a new System.IO.FileSystemWatcher object, and set appropriate settings:
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $searchPath
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true

    .Path is the path that will be monitored, .IncludeSubdirectories tells the FileSystemWatcher to monitor all subdirectories of .Path

  2. Now we need to define some events that will fire when $watcher detects a filesystem change, I’m going to define an event for Changed, Created, Deleted, and Renamed:
    $changed = Register-ObjectEvent $watcher "Changed" -Action {
       write-host "Changed: $($eventArgs.FullPath)"
    }
    $created = Register-ObjectEvent $watcher "Created" -Action {
       write-host "Created: $($eventArgs.FullPath)"
    }
    $deleted = Register-ObjectEvent $watcher "Deleted" -Action {
       write-host "Deleted: $($eventArgs.FullPath)"
    }
    $renamed = Register-ObjectEvent $watcher "Renamed" -Action {
       write-host "Renamed: $($eventArgs.FullPath)"
    }

    Within each event you can define code for what you want to happen when the event fires.  In this example I’m just directly outputting the type of action and the full path of the changed object on the filesystem.

  3. That’s pretty much it.  These events will hang around until you close your current PowerShell session or manually unregister the events.  You can unregister the events using the Unregister-Event command:
    Unregister-Event $changed.Id
    Unregister-Event $created.Id
    Unregister-Event $deleted.Id
    Unregister-Event $renamed.Id

As you can see – monitoring file system changes is actually quite easy with PowerShell.  You could easily take the output of this script and write it to a file (either using output redirection, or specifying output directly in the script) and with a little more code you could read in a CSV/structured file containing a list of exclusions (i.e. what CaptureBat does) and within each event filter out unwanted “noise.”

The great thing about this method is that it just *works* in Windows systems that have PowerShell.  No need to install any applications or run any third-party utilities – which the malware that you’re looking at may be looking for (i.e. anti-analysis measures built into some malware).  My goal is to build a complete replacement for CaptureBat within PowerShell in my spare time over the next few weeks.  Once done, I’ll post the complete script with explanations on my blog…

But for now, time to spend some quality time with the family.  Have a great weekend.

Dropbox authentication: insecure by design

For the past several days I have been focused on understanding the inner workings of several of the popular file synchronization tools with the purpose of finding useful forensics-related artifacts that may be left on a system as a result of using these tools.  Given the prevalence of Dropbox, I decided that it would be one of the first synchronization tools that I would analyze, and while working to better understand it I came across some interesting security related findings.  The basis for this finding has actually been briefly discussed in a number of forum posts in Dropbox’s official forum (here and here), but it doesn’t quite seem that people understand the significance of the way Dropbox is handling authentication.  So, I’m taking a brief break in my forensics-artifacts research, to try to shed some light about what appears to be going on from an authentication standpoint and the significant security implications that the present implementation of Dropbox brings to the table.

To fully understand the security implications, you need to understand how Dropbox works (for those of you that aren’t familiar with what Dropbox is – a brief feature primer can be found on their official website).  Dropbox’s primary feature is the ability to sync files across systems and devices that you own, automatically.  In order to support this syncing process, a client (the Dropbox client) is installed on a system that you wish to participate in this synchronization.  At the end of the installation process the user is prompted to enter their Dropbox credentials (or create a new account) and then the Dropbox folder on your local system syncs up with the Dropbox “cloud.”  The client runs constantly looking for new changes locally in your designated Dropbox folder and/or in the cloud and syncs as required; there are versions that support a number of operating systems (Windows, Mac, and Linux) as well as a number of portable devices (iOS, Android, etc).  However, given my research is focusing on the use of Dropbox on a Windows system, the information I’ll be providing is Windows specific (but should be applicable on any platform).

Under Windows, Dropbox stores configuration data, file/directory listings, hashes, etc in a number of SQLite database files located in %APPDATA%\Dropbox.  We’re going to focus on the primary database relating to the client configuration: config.db.  Opening config.db with your favorite SQLite DB tool will show you that there is only one table contained in the database (config) with a number of rows, which the Dropbox client references to get its settings.  I’m going to focus on the following rows of interest:

  • email: this is the account holder’s email address.  Surprisingly, this does not appear to be used as part of the authentication process and can be changed to any value (formatted like an email address) without any ill-effects.
  • dropbox_path: defines where the root of Dropbox’s synchronized folder is on the system that the client is running on.
  • host_id: assigned to the system after initial authentication is performed, post-install.  Does not appear to change over time.

After some testing (modification of data within the config table, etc) it became clear that the Dropbox client uses only the host_id to authenticate.  Here’s the problem: the config.db file is completely portable and is *not* tied to the system in any way. This means that if you gain access to a person’s config.db file (or just the host_id), you gain complete access to the person’s Dropbox until such time that the person removes the host from the list of linked devices via the Dropbox web interface.  Taking the config.db file, copying it onto another system (you may need to modify the dropbox_path, to a valid path), and then starting the Dropbox client immediately joins that system into the synchronization group without notifying the authorized user, prompting for credentials, or even getting added to the list of linked devices within your Dropbox account (even though the new system has a completely different name) – this appears to be by design.  Additionally, the host_id is still valid even after the user changes their Dropbox password (thus a standard remediation step of changing credentials does not resolve this issue).

Of course, if an attacker has access to the config.db file (assuming that it wasn’t sent by the user as part of social engineering attack), the assumption is that the attacker most likely also has access to all of the files stored in your Dropbox, so what’s the big deal?  Well, there are a few significant security implications that come to mind:

  • Relatively simple targeted malware could be designed with the specific purpose of exfiltrating the Dropbox config.db files to “interested” parties who then could use the host_id to retrieve files, infect files, etc.
  • If the attacker/malware is detected in the system post-compromise, normal remediation steps (malware removal, system re-image, credential rotation, etc) will not prevent continued access to the user’s Dropbox.  The user would have to remember to purposefully remove the system from the list of authorized devices on the Dropbox website.  This means that access could be maintained without continued access/compromise of a system.
  • Transmitting the host_id/config.db file  is most likely much smaller than exfiltrating all data found within a Dropbox folder and thus most likely not set off any detective alarms.  Review/theft/etc of the data contained within the Dropbox could be done at the attackers leisure from an external attacker-owned system.

So, given that Dropbox appears to utilize only the host_id for authentication by design, what can you do to protect yourself and/or your organization?

  1. Don’t use Dropbox and/or allow your users to use Dropbox.  This is the obvious remediating step, but is not always practical – I do think that Dropbox can be useful, if you take steps to protect your data…
  2. Protect your data: use strong encryption to protect sensitive data stored in your Dropbox and protect your passphrase (do not store your passphrase in your Dropbox or on the same system/device).
  3. Be diligent about removing old systems from your list of authorized systems within Dropbox.  Also, monitor the “Last Activity” time listed on the My Computers list within Dropbox.  If you see a system checking in that shouldn’t be, unlink it immediately.

Hopefully, Dropbox will recognize the need for additional security and add in protection mechanisms that will make it less trivial to gain long-term unauthorized access to a user’s Dropbox as well as provide better means to mitigate and detect an exposure.  Until such time, I’m hoping that this write-up helps brings to light how the authentication method used by Dropbox may not be as secure as previously assumed and that, as always, it is important to take steps to protect your data from compromise.

Update (10/31/2011): Dropbox has release version 1.2.48 that utilizes an encrypted local database and reportedly puts in place security enhancements to prevent theft of the machine credentials.  I have not personally re-tested this release – feel free to comment if you’ve validated that the new protection mechanisms operate as described.

Quick Tip: PowerShell Grep Equivalent

I’ve used searching in my previous PowerShell posts, but I thought that it deserves a dedicated “Quick Tip” posting.  I know that folks coming from a *nix background will be very familiar with using grep to search for pretty much anything and seemingly not having access to this tool can be disappointing for those trying to use Windows as their primary OS (for the one or two of you out there that have decided to come to the “dark side” 😎 ).  But…do not fret!  There are a number of ways to run equivalent searches within Windows out of the box.  Since I’ve been on a PowerShell kick lately, let me introduce you to a decent grep alternative that is built into PowerShell: select-string.

Select-String is a built-in cmdlet in PowerShell that will allow you to search files, piped input, objects, etc for a pattern (which is, by default, a regular expression).  Select-String can take in a number of options, but can be quite simple to use.  For example, if you want to search for the text “evildoer” within all files in the current directory, you can use the following command:

select-string .\*.* -pattern "evildoer"

It is important to note that by default, select-string is case-insensitive; so, if you need a case sensitive search, add in the -CaseSensitive parameter.

Ok, now let’s do something a bit more complex.  I want to look for anything that looks like an email address in all txt files recursively under C:\.  So, to make that happen we need to do a little more work:

get-childitem c:\ -include *.txt -rec | select-string -pattern "\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6}"

First, I need to use get-childitem (think DIR) to recursively go through the drive and return only files matching *.txt.  Then I pipe these returned objects to select-string and search their contents by using a basic regex that will match on things that look like email addresses.

Of course, there are a number of other ways to use select-string but since this is a “quick tip” I’ll keep things brief.  If you’d like more details, you can find additional information in the PowerShell documentation on TechNet.

Searching the Registry using PowerShell

On a cold and rainy Thursday morning, I thought that it would be a good time to write a post on searching the Windows registry using PowerShell.  In an Incident Response scenario you may want or need to do some live analysis on a compromised system, and part of this analysis may be to search the registry for some sort of artifact that is appropriate.  Using PowerShell can help you do this in a relatively efficient manner and is, of course, built in on new version of Windows (i.e. Windows 7, 2008, etc).

For example, let’s say that you know (or have guessed) that you’re dealing with some sort of malware that is probably going to be calling home at some time and you are wanting to look through the registry to see if the malware author decided to store any IPs/URLs in the clear.  In PowerShell you are able to easily browse and search through the registry, just like you were dealing with a filesystem.  There are a number of ways to accomplish this (for example, using -match rather than select-string), so feel free to use whatever method you’re comfortable with.  But, let me show you how I mangled my way through it this morning…

  1. Open up a PowerShell window.
  2. Let’s look for things that appear to be IP addresses under HKEY_CURRENT_USER, so first I need to recursively iterate through everything under that hive.  I do this by using the Get-ChildItem method:
    Get-ChildItem HKCU:\ -rec -ea SilentlyContinue

    This method returns a complete list of all keys (as objects of course) under the HKCU hive.

  3. From there, we’re going to need to dig into each of these returned objects and do our search.  So I’m going to pipe the output of the previous command into a foreach loop and then retrieve the data for each key:
    Get-ChildItem HKCU:\ -rec -ea SilentlyContinue | foreach {
       $CurrentKey = Get-ItemProperty -Path $_.PsPath
  4. Now that we have the contents that we want to search, let’s search for something that looks like an IP address and then print out any matches:
       select-string "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" -input $CurrentKey -AllMatches | foreach {($_.matches)|select-object Value}

    You’ll notice the use of a simple regular expression that will match on things that “look” like IP addresses.  If, for example, you’d prefer to look for URLs, a simple regex that you can use that’ll match most URLs would be: “\b(ht|f)tp(s?)[^ ]*\.[^ ]*(\/[^ ]*)*\b”.

  5. So putting it all together, to perform a simple string search of the registry for possible IP addresses and URLs using a regular expression you can use the following script:
    write-host "Possible IP addresses:`n"
    Get-ChildItem HKCU:\ -rec -ea SilentlyContinue | foreach {
       $CurrentKey = (Get-ItemProperty -Path $_.PsPath)
       select-string "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" -input $CurrentKey -AllMatches | foreach {($_.matches)|select-object Value}
    }
    write-host "`nPossible URLs:`n"
    Get-ChildItem HKCU:\ -rec -ea SilentlyContinue | foreach {
       $CurrentKey = (Get-ItemProperty -Path $_.PsPath)
       select-string "\b(ht|f)tp(s?)[^ ]*\.[^ ]*(\/[^ ]*)*\b" -input $CurrentKey -AllMatches | foreach {($_.matches)|select-object Value}
    }
    

This code will return any hits on the specified regular expressions, but doesn’t actually give you context as to where it was found within the registry.  If you’re just looking for odd URLs/IP addresses, it may be useful for you to just see a simple list of both to run through; but, if you want more context you may want to use a conditional with -match rather than select-string and then just output $CurrentKey:

write-host "Possible IP addresses:`n"
Get-ChildItem HKCU:\ -rec -ea SilentlyContinue | foreach {
   $CurrentKey = (Get-ItemProperty -Path $_.PsPath)
   if ($CurrentKey -match "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b") {
      $CurrentKey
   }
}
write-host "Possible URLs:`n"
Get-ChildItem HKCU:\ -rec -ea SilentlyContinue | foreach {
   $CurrentKey = (Get-ItemProperty -Path $_.PsPath)
   if ($CurrentKey -match "\b(ht|f)tp(s?)[^ ]*\.[^ ]*(\/[^ ]*)*\b") {
      $CurrentKey
   }
}

PowerShell can be a really powerful tool for easily searching the registry and is a good, albeit slightly slower, alternative to using another method that would require an interpreter, etc (i.e. Perl).  Have fun!

Turning off automount in Windows

Along with disabling autoplay/autorun, you may want to consider turning off the automount functionality of Windows systems requiring high security and is a decent secondary protection on a forensics workstation (you are using a hardware write blocker as well….right? :-)).

To disable automount (this has been tested under Windows 7) either:

  • run diskpart and once at the prompt type: automount disable
  • or, execute: mountvol /N
  • or, set HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MountMgr\NoAutoMount to 1 in the registry (you’ll see this entry change appropriately if you use one of the previously mentioned commands).

NOTE: the commands mentioned above will need you to “Run as an Administrator” in Windows 7.

Determining the hostname of a Windows machine

A coworker just asked me this question, and I thought that it would be useful enough to create a quick post.  If you’d like to find out the hostname of a Windows workstation/server and only have a drive image available (and don’t want to boot it), you can find the name within the System registry hive in the key named Hostname located here: SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Happy Monday.

Recycle Bin Forensics in Windows 7 and Vista

Microsoft has significantly changed how files and their corresponding details are represented within the Recycle Bin in Windows 7 and Vista.  In Windows XP, when files were placed into the Recycle Bin they were placed within a hidden directory named \Recycler\%SID% where %SID% is the SID of the user that performed the deletion.  The files were renamed D%drive_letter%%index_number%.%file_extension% where %drive_letter% is the original drive letter of the file, %index_number% is an index number, and %file_extension% is the original file’s extension.  Additionally, a file named INFO2 was placed in the user’s Recycler directory and it container entries, identified by index number, which described the original files size, full path/name, and size.

In Windows 7 and Vista, Microsoft did away with the INFO2 file and completely changed the way files were named and indexed within the Recycle Bin.  Firstly, the new Recycle Bin is located in a hidden directory named \$Recycle.Bin\%SID%, where %SID% is the SID of the user that performed the deletion.  Secondly, when files are moved into the Recycle Bin, the original file is renamed to $R followed by a set of random characters, but maintaining the original file extension.  At the same time a new file beginning with $I followed by the same set of random characters given to the $R file and the same extension, is created; this file contains the the original filename/path, original file size, and the date and time that the file was moved to the Recycle Bin.  You’ll also notice at all of the $I files are exactly 544 bytes long.

The behavior is a bit different when you move a directory to the Recycle Bin.  The directory name itself is renamed to $R followed by a set of random characters, but the files/directories under that directory maintain their original names.  A $I file is created just as when deleting an individual file that contains the original directory name, date/time deleted, and size.  When utilizing the information contained in the $I file for forensic purposes, you can safely report that all files found under the $R directory structure within the Recycle Bin were deleted at the same time (and all at once).  If a file was previously deleted out of the now deleted directory (but not yet removed from the Recycle Bin), it would have it’s own $R and $I files and not be grouped with the files that were deleted as part of the directory deletion action.

Unfortunately, unlike the INFO2 file, the new $I files are not in plain/readable text.  In order to decode a $I files, you could use a forensic tool that has the ability to interpret these files (I belive that Encase and FTK can do this), or you can simply open the file up in a hex editor.  The file is structured as follows:

  • Bytes 0-7: $I File header – always set to 01 followed by seven sets of 00.
  • Bytes 8-15: Original file size – stored in hex, in little-endian.
  • Bytes 16-23: Deleted date/time stamp – represented in number of seconds since Midnight, January 1, 1601.  Use a program such as Decode to assist with figuring out the exact date/time, if you don’t want to do the math :).
  • Bytes 24-543: Original file path/name.

So – break out your hex editors and take a look.  The new Vista/Windows 7 Recycle Bin is just as easy to deal with as the XP one – in fact, when it comes to whole directory deletions, I personally find it easier to work with…sometimes change is a good thing!

Have fun!

PsExec Passes Credentials in Clear Text

PsExec can be a very useful tool during incident response and live forensics work.  For those that don’t know, PsExec is a tool that can be used to execute commands on a remote Windows computer andwas initially developed by Sysinternals, which is now owned by Microsoft (additional details can be found on PsExec’s webpage).

However, it seems that PsExec has one significant shortfall – when utilizing the tool one must provide administrator-level credentials for the remote PC.  These credentials are passed in the clear to the remote workstation (thus exposing the credentials to anyone who happens to be “listening in”).  Thankfully, there is a workaround that can prevent this exposure from occurring, which involves connecting to the $IPC share on the target workstation first (with the admin credentials), prior to executing PsExec. 

To find out more, check out an excellent write up on this issue and the workaround found on SANS Computer Forensics blog titled Protecting Admin Passwords During Remote Response and Forensics.