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!