Sunday, July 13, 2014

Kansa: Passing arguments to collector modules

In my previous post on Kansa's automated analysis, I mentioned there was another improvement I made to the framework that I would cover in a future post. I thought at that time, that Kansa was at a point where I could go into some details about the new feature, but as it turns out, it wasn't quite ready.
 
Previously, some of Kansa's collector modules would need to be edited or customized prior to being run. Disk\Get-File.ps1, for example, was one that could acquire a specific file from target machines, but users would have to edit the collector to specify the file they wanted to acquire. Obviously that was less than ideal, so I did some work that would allow users to specify those kinds of things via command line arguments. In my limited testing, this worked... but, my testing was limited.

This week I had a pull request submitted by @z4ns4tsu for a collector module called Get-FilesByHash.ps1 that would allow investigators to take a cryptographic hash (MD5, SHA1, etc.) of a known suspect file, then search for files with that same hash across many machines in the environment. The module was the first that would take multiple arguments, the search path, the hash and the hash type; this is where Kansa had an issue. It couldn't pass multiple arguments to collectors, but after a couple nights of work, now it can.

I also added a few arguments to Get-FilesByHash.ps1, including a file extension regex so the script doesn't hash every single file looking for matches, instead, it will only hash those files with extensions that match the provided file extension regex, the default regex is \.(dll|exe|ps1|sys)$, this greatly reduces the number of files that will be hashed. I also added two more arguments that limit the files that will be hashed based on minimum and maximum file size in bytes.

Here's a command line example showing how this module can be used:
 
.\Kansa.ps1 -ModulePath ".\Modules\Disk\Get-FilesByHash.ps1 BF93A2F9901E9B3DFCA8A7982F4A9868,MD5,C:\Windows\System32,\.exe$" -target localhost -Verbose
 

Above Get-FilesByHash.ps1 will search for any files with the MD5 hash of BF93A2F9901E9B3DFCA8A7982F4A9868, in or below the C:\Windows\System32 path and ending with an extension of .exe., Notice that the arguments to Get-FilesByHash.ps1 are not named parameters. Named parameters are not supported for remoting, so they must be positional also note that they are comma separated and the whole module and arguments are quoted.
 
As with other modules, you can use the .\Modules\Modules.conf file to pass arguments to Get-FilesByHash.ps1 (or any other module that takes arguments) via the conf file itself. Here's the entry for the module above taken from the conf file:
 
Disk\Get-FilesByHash.ps1 BF93A2F9901E9B3DFCA8A7982F4A9868,MD5,C:\Windows\System32
 
Note the absence of quotes in the configuration file, and I've also omitted the regex extension argument.
 
Adding the ability to pass parameters to modules meant I could remove several collectors from Kansa that were written to acquire specific event logs, each one collecting a specific log file, instead, now Kansa has one collector written to generically collect any Windows event log and the specific log is simply passed as an argument. Here's the relevant section of the .\Modules\Modules.conf file:
 
Log\Get-LogWinEvent.ps1 Security
Log\Get-LogWinEvent.ps1 Microsoft-Windows-Application-Experience/Program-Inventory
Log\Get-LogWinEvent.ps1 Microsoft-Windows-Application-Experience/Program-Telemetry
Log\Get-LogWinEvent.ps1 Microsoft-Windows-AppLocker/EXE and DLL
Log\Get-LogWinEvent.ps1 Microsoft-Windows-AppLocker/MSI and Script
Log\Get-LogWinEvent.ps1 Microsoft-Windows-AppLocker/Packaged app-Deployment
Log\Get-LogWinEvent.ps1 Microsoft-Windows-Shell-Core/Operational
Log\Get-LogWinEvent.ps1 Microsoft-Windows-TerminalServices-LocalSessionManager/Operational
Log\Get-LogWinEvent.ps1 Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational
 
Above we have a single collector, Log\Get-LogWinEvent.ps1, that replaced nine collectors because it accepts an argument specifying which log to collect.
 
As you can see, being able to pass command line arguments to collectors is a big benefit, just be mindful that they are positional, not named parameters and as a result, if you want to accept all the default arguments but the last one, you still have to specify every argument, supplying the default values for every argument except the one you want to modify.

You can find more information about Kansa and the latest release at https://github.com/davehull/Kansa/releases.

Friday, July 4, 2014

Kansa: Automating Analysis

Kansa, the PowerShell based incident response framework, was written from the start to automate acquisition of data from thousands of hosts, but a mountain of collected data is not worth bits without analysis, thus analysis has been part of the framework from almost the beginning as may be seen here in this commit from 2014-04-18.

Data collection has been configurable via the Modules.conf text file since the beginning and the project has been packaged with a default Modules.conf file with the order of volatility applied. Users could edit the file, comment and uncomment lines to disable and enable modules, customizing data collection.

After Kansa completed its collection, users could cd into the newly created output directory and then into the specific module directory and run the analysis script of their choosing to derive some intelligence from the collected data. For example, a user might run Kansa's Get-Autorunsc.ps1 collector to gather Autoruns data from a hundred hosts that should have identical or very similar configurations.

Following the data collection, they could cd into the new output directory's Autorunsc subdirectory, then run

Get-ASEPImagePathLaunchStringMD5Stack.ps1

which would return a listing of Autoruns aggregated by path to executable, command line arguments and MD5 hash of the executable or script all in ascending order, so any outliers would be at the top of the list and these entries may warrant further investigation.

This was all well and good, but with more than 30 analysis scripts, analysis of the collected data was becoming cumbersome. It was begging for automation. So, I added it.

There is now an Analysis.conf file in the Analysis folder that works in much the same way as the Modules\Modules.conf configuration file. Every analysis script has an entry in the configuration file and you can edit the file and comment out the scripts you don't want to run or uncomment the ones you want to run. Then when you run Kansa, simply add the -Analysis flag and after all the data is collected, Kansa will run each analysis script for you and save the output to a new folder under the time stamped output folder called AnalysisReports.

Below is a sample listing:

Click for original size image
In the top directory listing of the output directory, you can see the normal output file structure, one folder per module, this was obviously a very limited data collection with Autorunsc, File, Netstat and PrefetchListing modules being used. Error.Log contains information about errors encountered during runtime. What's new here is the AnalysisReports directory.

The bottom directory listing shows the contents of the AnalysisReports path. Each of these are TSV files containing summary data of the collected data with the file names reflecting the name of the script that produced the data set. And the beauty of this is, it's fully automated when you run Kansa with the -Analysis flag and you've configured the Analysis\Analysis.conf file.

I've made some other improvements to Kansa in the last couple weeks, but I'll save that for the next post. For now, I wanted to share the automated analysis piece. I'm pretty psyched about it because it's a big time-saver and it puts Kansa in a position where it can easily produce alerts based on the presence of a quality or quantity on which an analysis script is written to trigger.

Tuesday, June 17, 2014

Kansa: Get-LogUserAssist.ps1

Tonight I pushed the latest collector to Kansa, Get-LogUserAssist.ps1. This is probably the most complicated collector I've written for Kansa. It has several moving parts and there were some obstacles to overcome.

As with most Kansa modules, you can run it stand-alone on your localhost, or through Kansa to collect data from thousands of hosts via Windows Remote Management. To run it against your local system, you should be able to download it from the above link, unblock it either through Explorer by browsing to it, right-clicking on it and unchecking the unblock checkbox under properties somewhere, I don't GUI enough. Or you can download it, open a Powershell prompt to the location where you've downloaded it and do:

ls Get-LogUserAssist.ps1 | unblock-file

The above may assume you have PS v3, I'm not sure when unblock-file came into being. You should upgrade to PS v3, if you haven't already as it has more whizbang.

Another option is to use Sysinternals Streams.exe -d Get-LogUserAssist.ps1, but I digress.

Here's an example of me running this locally on my laptop:
Click for larger image
When run locally, the script returns Powershell objects. The output directive for this script, tells Kansa to save the output as tab separated values, making for easy import into a database or quick analysis with Logparser. An analysis script for this output is on the Kansa issues list as an enhancement.

If you run this locally and want to massage the output to TSV, at your Powershell prompt, you could do:

PS> Get-LogUserAssist.ps1 | ConvertTo-CSV -Delimiter "`t" -NoTypeInformation

I don't care for quoted TSV, so I'd go a step further adding:

| % { $_ -replace "`"" }

to the above and why not write it out to a file that you can load into Excel or a database or query with Logparser? To do that, simply add the below to the above:

| Set-Content LocalhostUserAssist.tsv

But you don't have to do TSV. You could drop the -Delimiter arg above and default to CSV or instead of using ConvertTo-CSV, use Export-CliXML and you've got XML output for those of you who want a more challenging and slower analysis experience. Zing!

One thing I'm not clear on and may have to research, is why so many of my "counts" are coming up as zero. Did Windows 8 stop incrementing run counts?

This collector starts by enumerating all of the local profiles on the target, then looks in each profile path for an ntuser.dat file. If it finds one, it will try and load that hive. If the hive loads, the script looks for UserAssist and parses it, if found. If UserAssist is not found, it moves on to the next user. If the script was unable to load the hive, it assumes that's because the user is currently logged on and the file is locked, so at that point, it looks in HKEY_USERS for all the loaded hives by SID, resolves those SIDs to usernames and compares them to the username associated with the locked profile. When it finds a match, it looks for UserAssist in the matching HKEY_USERS key by SID. One thing that occurs to me now, based on something I heard @forensic_matt say at this year's SANS DFIR Summit, if the user's account is renamed, this match will likely fail. Something to add to the Kansa issues list. Save for that edge case, this script will pull UserAssist key data for all user accounts on a running system.

And since it's a Kansa module, you can run it across thousands of hosts easily.

I hope someone finds it useful.

[Update] You may be wondering, "Why is this module under Modules\Log, the Registry is not a log file?"

As Harlan Carvey has rightly pointed out, the Registry sometimes is a log file and in the case of UserAssist, it most certainly is. Hence, I placed it under Modules\Log. You're free to move it elsewhere on your own set up.

[Update 20140623] Confirmed for renamed accounts the module was not able to resolve a loaded SID to an account name, but I've fixed this bug. The script now returns the user account name and the user profile path, so spotting renamed accounts is simple. Here's an example where the Local Administrator account has been renamed to Gomer.

Saturday, May 17, 2014

Kansa: Powershell profiles potentially hazardous

On the very day I published my previous post, Kansa: Collecting WMI Event Consumer backdoors, Mark Russinovich announced the release of a new version of Autoruns that collects WMI related ASEPs. I had a chance to play around with it on a machine with a WMI Event Consumer, Event Filter and Filter-to-Consumer Binding configured and indeed, Autoruns now picks up the Event Consumers. I still recommend using Kansa's Get-WMIEvtFilter.ps1 and Get-WMIFltConBind.ps1 collector modules to grab the other two essential pieces that make Event Consumer backdoors possible. The Event Filter is the piece that will tell you what triggers the Event Consumer.

In this post I want to cover another "auto start extension point" or ASEP and it happens to be another that is not covered by Autoruns, yet. It also happens to be specific to Powershell. The Windows Powershell Profile is a script that runs, if present, each time a user or SYSTEM opens a Powershell shell. It's akin to a .bash_profile or similar shell profile on *nix systems.

Adversaries can modify an existing Powershell profile for either a user or the default system profile, planting code enabling them to maintain persistence or perform any task that Powershell is capable of given the context of the script (non-administrator users obviously being less capable than administrators or SYSTEM).

Kansa's Get-PSProfiles.ps1 collector will enumerate local accounts on remote systems and check each of them for Powershell profiles. Where Powershell profiles exist, Get-PSProfiles will collect them all in a zip file (it will also check for and collect the default Powershell profile). The zip file will then be sent back to the host where Kansa was run.

Powershell profiles can be located in a few different locations. For user profiles, they are in:

$env:userprofile\Documents\WindowsPowershell\Microsoft.Powershell_profile.ps1

And the default system profile is in:

$env:windir\System32\WindowsPowershell\v1.0\Microsoft.Powershell_profile.ps1

User Powershell profiles on XP systems are in a slightly different path and Kansa will not acquire them.

Unfortunately, there's no quick way of analyzing the collected profile scripts for malicious capabilities, at least not that I'm aware of. Analysts will have to spend time reviewing profiles for suspect code. This is a good time to mention that any ASEP script, not just Powershell profiles could be modified by adversaries to perform nefarious actions.

This is another painful reminder of the asymmetry of information security. Adversaries have many places to hide malicious bits and may only need one (or none, if they have a big enough key ring of credentials). Incident responders, depending on the nature of the incident, may have to review every known ASEP.

Enjoy the code review and happy hunting!

Tuesday, May 13, 2014

Kansa: Collecting WMI Event Consumer backdoors

In my previous post, Kansa: Service related collectors and analysis, I discussed the Windows Service related collectors and analysis capabilities in Kansa and noted that some of the collected data is not currently collected by Sysinternals' Autoruns.

Today I'll cover another persistence mechanism that Kansa collects, which is not currently collected by Autoruns; namely WMI Event Consumers. That link tells us "Event consumers are applications or scripts that request notification of events, and then perform tasks when specific events occur."
[Update: 2014-05-13] Mark Russinovich released a new version of Autoruns today that reports WMI information. I have not tested it yet. It will be interesting to see if it only reports data form Event Consumers and not the Event Filter, which tells what the trigger is.

For an event consumer to work, three elements are required:
  • An Event Consumer -- this is the piece that performs some action
  • An Event Filter -- an event query watching for defined activity -- this triggers the consumer
  • A Filter-to-Consumer Binding -- this links the filter to the consumer
In my experience, WMI Event Consumers are not commonly used. So in many situations collecting the data and simply reviewing file sizes can tell you if something is worth investigating further. For example, I recently collected event consumer data from a few thousand hosts. Running the following Powershell command was enough to find which host contained a backdoor running from an event consumer:

ls *wmievtconsmr.xml | sort length -Descending | more

The output of that command follows, see if you can determine which host had the backdoor installed:
If you guessed DFWBOSSWEE01, congratulations, you may have the skills necessary to find WMI Event Consumer backdoors.

So what's in this file? Since it was collected with Kansa's Get-WMIEvtConsumer collector, which specifies its output should be written to an XML file, we can either open the XML file in a suitable editor or use the Powershell cmdlet Import-Clixml to read the file into a variable and examine the contents via the following commands:

$data = Import-Clixml .\DFWBOSSWEE01_wmievtconsmr.xml
$data | more

This command returns output like the following:
The most interesting bits above are those in the "CommandLineTemplate" property, which I've redacted a bit, but you can see there's a call to Powershell.exe and a long base 64 encoded string, which in this case was a Powershell encoded command, in essence, a script. We can decode that script via

[Convert]::ToBase64String()

Doing so would reveal that when this WMI Event Consumer is triggered, it connects to a remote site and downloads another script and runs it.

So how often is it triggered? What triggers it? To answer those questions, you'll have to review the data Kansa collected via Get-WMIEvtFilter.ps1. A consumer by itself is harmless, but if there's an Event Filter and a Filter-to-Consumer binding, then you've got all the ingredients needed for a WMI Event Consumer based backdoor.

Saturday, May 3, 2014

Kansa: Service related collectors and analysis

In my previous post on Kansa's Autoruns collectors and analysis scripts, I mentioned that the Get-Aurounsc.ps1 collector relies on Sysinternals' Autorunsc.exe to collect data on all of the Autostart Extension Points (ASEPs) that it has catalogued. Autorunsc and its GUI sibling, Autoruns, are great tools, but they are not comprehensive, there are other ASEPs that they don't catch, so Kansa includes a few additional modules that aim to collect additional ASEPs and additional data about ASEPs.

Get-SvcAll.ps1
Runs Get-WMIObject win32_service to collect details about all services. Output is saved as XML. Some of this same data is collected by Get-Autorunsc.ps1 above, however, this will pull additional properties for each service with some of them being specific to the type of service. If a service is running, you'll get its process id and the context it runs under (Local System, Local Service, etc.). There's even an InstallDate property, which is awesome, however, in my experience, it's never populated, which sucks.

For analysis of the data collected by Get-SvcAll.ps1, there are two very basic frequency analysis or stacking scripts as of this writing. They are Get-SvcAllStack.ps1 and Get-SvcStartNameStack.ps1. The former does its frequency analysis based on Service "Captions" and Pathnames. The Captions are the short friendly names you see when you look at the Services running on your system while the Pathnames include the path to the binary and any arguments. Here's an example from two systems where the Application Identity service has two different sets of command line arguments:

Click for larger image
Stacking by these properties across many hosts shows investigators services that may have the same Caption, but different binaries and arguments. This same kind of analysis is available in the Autoruns stacking scripts with the added benefit of stacking by file hash (e.g. MD5).

Get-SvcStartNameStack.ps1 stacks by Caption and StartName, the latter of which turns out to be the name of the account the service runs under.

Another Service analysis script, but not a stacker, is Get-SvcAllRunningAuto.ps1, which pulls the list of Services that were in a running state or set to start automatically when the Get-SvcAll.ps1 collector ran on the targets.

ASEPs not collected by Autorunsc:

As I mentioned above, Sysinternals' Autoruns and Autorunsc executables collect all the ASEPs they know to collect, but that is not the universe of ASEPs.

Windows Services can be configured to recover from failures. In my experience, restarting the service is the most common recovery option, but one option that adversaries can use is the "Run a Program" option as shown below:
Click for larger image
 
In the screen shot above, the Application Identity service is configured with a failure recovery response that will run a program called ServiceRecovery.exe from C:\ProgramData\Microsoft\ with the command line argument -L 443. This is a persistence mechanism that Autorunsc won't capture.

Kansa's Get-SvcFail.ps1 collector will collect service failure recovery information from all services. Kansa includes a few analysis scripts that will stack the service failure recovery data, but the most useful one is Get-SvcFailCmdLine.ps1, which returns the frequency count of the program and command line parameters from all the collected service failure information. The image below shows this data from a few thousand systems:
Click for larger image
In the example there are 129769 Service Failure entries, 75088 of them have the same program and command line arguments configured as a recovery option. Seems unlikely this is malicious.

In another smaller data set, the following data was returned:
Click for larger image
I include this screen shot because I've run into the customscript.cmd entry in multiple data sets and in all the cases I've investigated, I've not yet found a service that referenced customscript.cmd anywhere in the Services GUI, but you will see services reference it in the data of their Registry key values, like the following:

I've also searched file systems on hosts where I've seen this, but I've not found a file on disk called customScript.cmd. I wanted to mention it here in case you run across it. If you do see a reference to customscript.cmd that includes a path, you may have an adversary attempting to blend in with a common value.

The last Service related collector in Kansa, as of this writing, is Get-SvcTrigs.ps1, which collects another set of ASEPs that Autoruns does not collect, yet -- Service Triggers. Service Triggers are new with Windows 7 and later versions of Windows. They allow Windows Services to have more startup flexibility than the old Manual and Automatic startup modes. Now services can respond to the presence of specific hardware, group policy changes, networking events, etc. More information about Service Triggers can be found at the following links:
Kansa includes a basic stacker for Service Triggers. Interpreting the data to determine what's normal and what's suspicious can be daunting and tedious. Searching on GUIDs can be of some help. Below is a frequency listing of Service Triggers from a relatively small sample, two systems.
Click for larger image
I have Service Trigger data from a few thousand machines, but I'm not at liberty to share it here, trust me when I say finding outliers is easier with a larger data set, but keep in mind, just because something is an outlier doesn't mean it's bad and the inverse is also true, just because something is common, it's not necessarily good.

There is one more ASEP that I know of that Autoruns won't catch, but that Kansa collects, but I'll save that for another post.

Tuesday, April 29, 2014

Kansa: Autoruns data and analysis

I want your input.

With the "Trailer Park" release of Kansa marking a milestone for the core framework, I'm turning my focus to analysis scripts for data collected by the current set of modules. As of this writing there are 18 modules, with some overlap between them. I'm seeking more ideas for analysis scripts to package with Kansa and am hopeful that you will submit comments with novel, implementable ideas.

Existing modules can be divided into three categories:

  1. Auto Start Extension Points or ASEP data (persistence mechanisms)
  2. Network data (netstat, dns cache)
  3. Process data
In the interest of keeping posts to reasonable lengths, I'll limit the scope of each post to a small number of modules or collectors.

ASEP collectors and analysis scripts

Get-Autorunsc.ps1

Runs Sysinternals Autorunsc.exe with arguments to collect all ASEPs (that Autoruns knows about) across all user profiles, includes ASEP hashes, code signing information (Publisher) and command line arguments (LaunchString).

Current analysis scripts for Get-Autoruns.ps1 data:
Get-ASEPImagePathLaunchStringMD5Stack.ps1
Returns a frequency count of ASEPs aggregating on ImagePath, LaunchString and MD5 hash.

Get-ASEPImagePathLaunchStringMD5UnsignedStack.ps1
Same as previous stacker, but filters out signed ASEPs.

Get-ASEPImagePathLaunchStringPublisherStack.ps1
Returns frequency count of ASEPs aggregated on ImagePath, LaunchString and code signer.

Get-ASEPImagePathLuanchStringStack.ps1
Returns frequency count of ASEPs aggregated on ImagePath and LaunchString.

Get-ASEPImagePathLaunchStringUnsignedStack.ps1
Same as previous, but filters out signed code.

A picture is worth a few words, here's a sample of output for the previous analysis script for data from a couple systems:

Click for full size image
The image above shows the unsigned ASEPs on the two hosts, aggregated by ImagePath and LaunchString. You may want to know which host a given ASEP came from, however, including the host in the output above would break the aggregation. If you want to trace the 7-zip ASEP back to the host it was found on, copy the ImagePath or LaunchString value to the clipboard and from within this Output\Autorunsc\ path where the script was run, use the Powershell commandlet:

Select-String -SimpleMatch -Pattern "c:\program files (x86)\7-zip\7-zip.dll" *autoruns.tsv

The result will show the files and lines in those files, that match that pattern, each filename contains the hostname where the data came from, and the hostname is also in the file in the PSComputerName field.

Get-Autorunsc.ps1 returns the following fields:
Time: Last modification time from the Registry or file system for the EntryLocation
EntryLocation: Registry or file system location for the Entry
Entry: The entry itself
Enabled: Enabled or disabled status
Category: Autorun category
Description: A description of the Autorun
Publisher: The publisher from the code signing certificate, if present
ImagePath: File system path to the Autorun
Version: PE version info
LaunchString: Command line arguments or class id from the Registry
MD5: MD5 hash of the ImagePath file
SHA1: SHA1 hash of the ImagePath file
PESHA1: SHA1 Authenticode hash of the ImagePath file
PESHA256: SHA256 Authenticode hash of the Image Path file
SHA256: SHA256 hash of the ImagePath file
PSComputerName: The host where the entry came from
RunspaceId: The runspaceid for the Powershell job that collected the data
PSShowComputerName: A Boolean flag about whether or not the PSComputerName is included

These last three fields are artifacts of Powershell remoting.

Given the available data and the currently available analysis scripts, what other analysis capabilities make sense for the Get-Autorunsc.ps1 output?

One idea I have, is to take the idea explored in a previous post of mine, "Finding Evil: Automating Autoruns Analysis." This would be a script that takes an external dependency on a database of file hashes that are categorized as good, bad and unknown. The script would match hashes in the Get-Autorunsc.ps1 output, discarding the good, alerting on the bad and submitting unknowns to VirusTotal to see what, if anything is known about them. If VT says they are bad, insert them into the database and alert. If VT says they are good, insert them into the database and ignore them in future runs. If VT has no information on them, mark them for follow up and send them to Cuckoo sandbox or similar for analysis.

What ideas do you have? What would be helpful to you during IR?

Thanks for taking the time to read and comment with your thoughts and ideas.

If you found this information useful, please check out the SANS DFIR Summit where I'll be speaking about Kansa, IR and analysis in June.

Grand Canyon Rim to Rim: New Gear and Best Intentions

I pulled my late 1980s backpack out of storage. My first thought was that it was heavier than I remembered, just over seven pounds empty. Ba...