PowerShell: Detect files infected/encrypted by virus

By | 2014-09-30

So the other day we got hit by a virus at work – well actually it was the 2nd time in four months we got hit by this particular type of virus.

The virus arrived in the form of an email with an attached ZIP file. The mail itself claimed to be a Fax Report and the ZIP file contained an SCR file. The virus was not detected by our virus scanners, nor by our mail scanning … and unfortunately the SCR file was opened by one of our users.

The virus was one of those CryptoWall/RansomWare type vira that starts encrypting files on the fileshares and place DECRYPT_INSTRUCTION txt and html files in the folders, explaining how you can buy a decrypt tool to get your files back. Needless to say we did not go down that route.

By looking at the ownership of one of the encrypted files we found the user who had set the virus free, and where able to stop it from encrypting further files. But now the problem remained to determine the encrypted files.

Fortunately all encrypted files from one invokation of the virus share the same header, so with a couple of samples it is possible to determine a header to check for. But how do you get a HexHeader from a file? PowerShell to the rescue (once again).

function Get-FileHexHeader
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$True,
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True,
        HelpMessage='FileInfo object you want to get header from')]
        [System.IO.FileInfo[]]$Files,
        [Parameter(HelpMessage='Number of bytes to read from file')]
        [int]$Bytes=10
    )
    Begin {}
    Process {
        $Files | ForEach-Object {
            if ($HeaderHexString) { Remove-Variable HeaderHexString }
            Get-Content -Path $_.FullName -TotalCount $Bytes -Encoding Byte -ErrorAction SilentlyContinue | %{
                if ( ( '{0:X}' -f $_ ).Length -eq 1 ) {
                    $HeaderHexString += '0{0:X}' -f $_
                }
                else {
                    $HeaderHexString += '{0:X}' -f $_
                }
            }
            $HeaderHexString
        }
    }
    End {}
}

With the above function you can do things such as …

Get-ChildItem <FilePath> | Get-FileHexHeader

… which will show the HexHeader of files within a path. You can adjust the amount of bytes you want to read from each file – it defaults to 10 bytes. The first time we got hit by this virus we found the first 13 bytes to be identical on all infected files. This time round it was the first 16 bytes.

Lets say you find that “FEDE700C7B7623130001000000” is the header of all infected/encrypted files. That would allow you to check for infected files like this …

Get-ChildItem <FilePath> -Recurse | Where { ($_ | Get-FileHexHeader -Bytes 13) -eq 'FEDE700C7B7623130001000000' }

… or if you have more than one header to check for (perhaps several users opened an attachment) you could check for it like this (just ensure all headers are the same lenght)

$Signatures = @(
    '23545950452053797374656D2E',
    '504B03040A0000000000A56433',
    'FEDE700C7B7623130001000000'
)
Get-ChildItem <FilePath> -Recurse | Where { $Signatures -contains ($_ | Get-FileHexHeader -Bytes 13) }

Now while this does not recover your files it will help you identify the files you need to restore from backup.

Should you find a way to actually recover your files please post it in the comments

5 thoughts on “PowerShell: Detect files infected/encrypted by virus

  1. Christian Post author

    Slight change to the Get-FileHexHeader function today, due to problems when running with PowerShell version 2.0 (get-content would not accept file object from the pipeline). Original post has been updated.

    Reply
    1. bucd

      Christian,
      Trying to run this on PowerShell 2.0 and still getting error at Get-Content.
      Get-Content : A parameter cannot be found that matches parameter name ‘Encoding’.
      Works find in 3.0.
      Any help is appreciated.
      thank you,
      -D

      Reply
      1. Christian Post author

        It complains about the Get-Content Cmdlet not accepting the Encoding parameter.

        I just (re)tested on a Windows Server 2008 R2 box with PowerShell 2.0, and it works a treat there.
        The Encoding parameter is a dynamic parameter, provided by the FileSystem provider. I’m wondering if it may be, that depending on the OS the FileSystem provider can provide different dynamic parameters?

        Try running this to list the dynamic parameters for the Get-Content Cmdlet:

        (Get-Command Get-Content).Parameters.Values | Where { $_.IsDynamic } | Select-Object -ExpandProperty Name

        On the box I tested on, it returned the following:
        Delimiter
        Wait
        Encoding

        If yours does not return “Encoding”, I guess you’re out of luck. What you might want to do though is run it from another machine over the network. That’s what we have done from time to time, when dealing with files residing on an old server with no PowerShell.

        Best of luck 🙂

        Reply
        1. bucd

          It returns the same thing as what you see. Encoding at the end. So very odd. I was trying to run it from another box that had PS 4.0 but I was trying to run it on a mapped drive. That doesn’t seem to work, can you specify UNC path to scan for this script?

          thank you,

          -D

          Reply
          1. Christian Post author

            Yes … both Get-ChildItem and Get-Content support mapped drives as well as UNC paths. The Get-FileHexHeader function just expect one or more fileinfo objects.

            So you should be able to simply do:

            Get-ChildItem \\youserver\yourshare\your\path | Get-FileHexHeader

Leave a Reply

Your email address will not be published. Required fields are marked *