Monday, March 30, 2015

Kansa: Get-LogparserStack.ps1

Kansa is an incident response framework written in PowerShell, useful for data collection and analysis. Most of the analysis capabilities in Kansa require Logparser, which is a very handy tool for creating SQL-like queries over data sets that may be comprised of a single file or many files.

Because adversaries usually want to leave a small footprint, one technique for finding them is frequency analysis -- looking for outliers across many systems. This technique has been written about before. As such, most of the analysis tools in Kansa are scripts that stack-rank or perform frequency analysis of specific fields in a given data set. Some examples include:
  • Get-ASEPImagePathMD5Stack.ps1
  • Get-ASEPImagePathLaunchStringMD5UnsignedStack.ps1
  • Get-ASEPImagePathLaunchStringMD5UnsignedTimeStack.ps1
  • ...
And the list goes on. These script names are fairly descriptive, but they are a mouthful and they are not very flexible as they contain hardcoded Logparser queries with set field names.

Kansa needed a more flexible stack-ranking solution and now it has one.

Get-LogparserStack.ps1 can be used to perform frequency analysis against any delimited file or set of files, so long as the set all has the same schema and the same header row across each file. Unlike all other Kansa utilities, Get-LogparserStack.ps1 is interactive. After reading the first two lines of each input file and confirming that they all have the same header row, the script prompts the user for the field she wishes to pass to Logparser's COUNT() function, then the script prompts the user for the fields she wishes to GROUP BY.

Below is a screen shot of the script in action against a small set of Autorunsc data from five systems. The frequency analysis is against the "Image Path" field with both "Image Path" and MD5 being added to the GROUP BY clause. As you can see in the screen shot, the resulting query quickly bubbles up an outlier, a dll from one system does not match the same dll from the other four systems.
Figure 1: Get-Logparser.ps1 quickly shows that one dll is not like the others.
Get-LogparserStack.ps1 is a new utility and as such, may mature a bit in time. One potential feature would be to make it non-interactive, so it can be scripted.

As with nearly all of the scripts that make up Kansa, Get-LogparserStack.ps1 can be used in conjunction with Logparser.exe outside the framework to perform frequency analysis of any data set, providing the schemas match and each file in the set has a header row.

If you use it and encounter any bugs, please open an issue in Kansa's GitHub page.

Wednesday, March 25, 2015

Kansa: Get-AutorunscDeep.ps1 -- Taking Autorunsc to 11

I wanted to put up a quick post about a new Kansa collector I recently added -- Get-AutorunscDeep.ps1. Sysinternals' Autoruns is a great utility for finding auto-start extension points in Windows and one I've blogged about a number of times.

Kansa has had a collector that wraps around Autorunsc.exe from Sysinternals almost since I began writing Kansa in March of 2014. It's such a great little utility for enumerating so many persistence mechanisms in Windows, though by no means, does it cover all of them.

Get-AutorunscDeep.ps1 goes to 11. How so? There are two ways that Get-AutorunscDeep.ps1 improves on Autorunsc.exe alone.
  1. Get-AutorunscDeep.ps1 includes code written by my friend @z4ns4tsu (who will be speaking at the SANS 2015 DFIR Summit) that calculates the Shannon Entropy of Autorunsc's Image Path property. As many of you well know, packed binaries are common in malware families and those binaries have higher entropy than many legit binaries, so knowing a file's entropy can be a useful lead generation tool when dealing with large amounts of data.
  2. Get-AutorunscDeep.ps1 goes a step further than Autorunsc.exe alone for common interpreters that execute scripts such as cmd.exe, PowerShell.exe or wscript.exe that may call .bat, .ps1 or .vbs files repsectively. Below in Figure 1, I've run the latest version of Autorunsc.exe and saved the output to a csv file, then loaded that csv file into a PowerShell variable called $data, then I'm dumping the contents of $data for any entry that calls a PowerShell script:
Figure 1: Output of Autorunsc.exe for a PowerShell ASEP (Click to enlarge)
Note that in Figure 1, Autorunsc.exe provides hashes of the PowerShell.exe binary itself. I've worked investigations where adversaries have taken existing ASEP entries and modified the scripts that are called, planting their own malicious code in those scripts. If you've got an ASEP that runs via PowerShell, cmd.exe or wscript.exe on hundreds or thousands of hosts and you use Autorunsc.exe to collect that data, a few of the scripts called by that interpreter could have been modified by an attacker and you'd have no visibility into it via Autorunsc.exe alone.

Get-AutorunscDeep.ps1 solves this problem, in most cases, by adding a hash of the script called by the interpreter. So for ASEPs like cmd.exe, PowerShell.exe and wscript.exe that call scripts, you'll see the hash of the binary itself as Autorunsc.exe calculates it, and you'll get the hash of the script because Get-AutorunscDeep.ps1 will calculate it for you, assuming it can find and read the script. Below in Figure 2, is an example of what this looks like, the data was collected from the same host as above, but remotely using Kansa:

Figure 2: Output of Get-AutorunscDeep.ps1 for the same PowerShell ASEP (Click to enlarge)
Note the red marks in Figure 2 and apologies, I'm not a graphic artist. Get-AutorunscDeep.ps1 has added an MD5 hash for the Get-AutorunscDeep.ps1 script that the PowerShell executable in the above Scheduled Task is calling. You can also see the ShannonEntropy value for PowerShell.exe, another feature of Get-AutorunscDeep.ps1's output. Now consider the visibility this gives you if you have the same ASEP script deployed across thousands of hosts. Use Kansa's Get-AutorunscDeep.ps1 collector, in conjunction with Sysinternal's Autorunsc.exe, and you'll quickly be able to find versions of scripts that have been modified.

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.

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...