Management PowerShell and Ransomware Lead image: Lead Image © Andrea Danti, 123RF.com
Lead Image © Andrea Danti, 123RF.com
 

Discover ransomware with PowerShell

Danger Ahead

Simple backup strategies cannot protect files encrypted by ransomware, because they can be affected as well. A PowerShell script can ensure that your files are okay before sending them to backup. By Ralph Dombach

Backups are not a panacea for all ransomware infections. If a backup overwrites your original files with ransomware encrypted data, your files are gone. Admittedly, this only applies to trivial backup strategies, which you might find in small business environments or in freelancer operations. In mid-sized companies and enterprise environments, this may be not so tragic at first glance, because your archives have backups for the past few weeks.

However, even this is not guaranteed. If the data are outdated, the backups are not much use after a restore. In simple scenarios, the data are only saved to a USB hard drive or online storage, and there is typically only one backup set. An even greater danger is overwriting usable backup data with ransomeware encrypted data. This is especially true if the ransomware does not change the file extensions, which happens in some cases. Of course, there is no alternative to the backup and restore protection concept.

Basic Protection Measures

A reliable process for addressing ransomware is not yet available, even if the security industry has reported initial success here and there. Ideally, you should implement general security recommendations and thus make life difficult for the ransomware. These recommendations include:

Ransomware typically relies on a brutal approach. For example, it reads and encrypts all of a computer's game files or all of your private photos in one fell swoop and writes them back to the disk. Upon completion, a message appears on your screen demanding a ransom payment in return for the code to decrypt the data. As a result, the blackmailer often earns some bitcoins. However, the ransom demand robs the cybercriminal of any chance of the ransomware spreading further because the demand notifies the security industry that the ransomware exists.

As a result, delayed file encryption is a new ransomeware approach. Although it delays the arrival of the first bitcoins, it also increases the possibility of cornering more victims. In any case, ransomware should be detected immediately on critical systems, in order to take fast remedial action such as stopping backups.

Because a virus scanner can be more or less easily tricked by crafty malware authors, one method for ransomware detection is to verify previously deployed bait files and directories before every backup. If these files have been changed, this is an indication that ransomware is active, and the backup run can be stopped before more backup sets are overwritten. Ideally, you should create multiple file folders on the filesystem for this purpose and fill them with different files. Locky, for example, attacks around 180 different file extensions; even Office documents do not escape unpunished. Of course, you need to consider individually which strategy is best suited for your application. However, it is important that the backup run only starts once the integrity of the bait files has been verified.

A tool that supports you in this endeavor and provides fast results is PowerShell. The scripting language can be quickly adapted, even by beginners. PowerShell v4 or newer is required for my _noRansom bait-file tool (see Listing 1 on the following pages), which is a simple script that makes do with a minimal interface. It is available for FTP download [1] and supports the statements: create, convert, and compare.

Listing 1: _noRansom.ps1

001 #
002 # Query own PS Version via: $PSVersionTable.PSVersion --> Required >= V4
003 #
004 # Script start:      powershell -file scriptname /parameter
005 # Script name:       _noRansom.ps1
006 # Function:          Create/compare file list with SHA1 checksums
007 #
008 Clear-Host
009 Write-Output "NoRansom started..."
010
011 # Variable definition with default values     ###########################
012 # "*.log,*.eps"                               Pattern, based on which file extensions to searched for;
013 #                                             see use of Get-ChildItem later on in script in "/create-branch"
014 $StepWidth = 5;#                              Each [stepwidth] file from the set of all files found
015 $FileList = "_noRansom-full.txt";#            Name of output file with ALL files found
016 $MiniFileList = "_noRansom-mini.txt";#        Name of output file with each nth file including SHA1 checksum
017 $ErrorFile = "_noRansom-Error.txt";#          Name of standard error file
018 $AutoWrite = "yes";#                          Defines whether files should be overwritten or canceled (false)
019 $ErrorActionpreference = "silentlycontinue";# No error output on screen
020 # Variable definition with default values     ###########################
021
022 Remove-Item $ErrorFile
023 $error.clear()
024 $ParamFunction = $args[0]
025
026 switch ($ParamFunction)
027  {
028    "/create"
029     {# Create file list with C:\ for the defined file extensions
030       If (Test-Path $FileList)
031        {  if ($AutoWrite -eq "yes")
032           { Remove-Item $FileList }
033          else
034           { $Temp = "The file " + $FileList + " already exists, default is to not overwrite. Please manually delete and call tool again if needed!"
035             write-output $Temp
036             exit 11 }
037        }
038       Get-ChildItem C:\ -recurse -include *.log,*.eps | ForEach { $_.Fullname } > $FileList
039       if ($error)
040        {write-output $error >> $ErrorFile;$error.clear() }
041       $Temp = "File " + $FileList + " created!"
042       write-output $Temp
043       #exit 0
044
045     }
046
047    "/convert"
048     {# Convert and if applicable minimize file list
049
050      # Test whether input file exists for processing
051      if (!(Test-Path $FileList))
052       { $Temp = "The file or file list: " + $FileList + " does not exist. Please first run tool with parameter /create."
053         write-output $Temp
054         exit 11 }
055
056      # Test whether output file exists and if necessary delete
057      If (Test-Path $MiniFileList)
058      {  if ($AutoWrite -eq "yes")
059          { Remove-Item $MiniFileList }
060         else
061          { $Temp = "The file " + $MiniFileList + " [with SHA1 checksum] already exists, default is to not overwrite. Please manually delete and call tool again if needed!"
062            write-output $Temp
063            exit 11 }
064      }
065      $content = Get-Content -Path $FileList
066      $lines = $content.count - 1
067      $Temp = "Lines in input file: " + $lines + " [Convert step width: " + $StepWidth + "]"
068      write-output $Temp
069
070      # Output every nth line including SHA1 checksum
071      $mini=0
072      Remove-Item $MiniFileList
073         for ($i= 0; $i -lt $lines; $i+=$StepWidth)
074         {    $sha1 = ((Get-Filehash $content[$i] -Algorithm SHA1).hash)
075              # Do not output files with access error (no SHA1)
076              if ($sha1)
077              { $Temp = $content[$i] + "," + $sha1
078                Write-Output $Temp >> $MiniFileList
079                $mini++
080              }
081         }
082     $Temp = "Lines in output file (total): " + $mini
083     write-output $Temp
084     exit 0
085     }
086
087    "/compare"
088     {# Compare file list
089      If (!(Test-Path $MiniFileList))
090       { $Temp = "The file " + $MiniFileList + " [with SHA1 checksums] does not exist. Please provide this file first (/create and then /convert)."
091         write-output $Temp
092         exit 11 }
093      $content = Get-Content -Path $MiniFileList
094      $lines = $content.count
095      $splitting = ""; $SHA1OK = 0; $SHA1NOK = 0
096      for ($i= 0; $i -lt $lines; $i+=1)
097      {
098       $Splitting = $content[$i].Split(",")
099       $sha1 = (Get-Filehash $Splitting[0] -Algorithm SHA1).hash
100       if ($error)
101        {write-output $error >> $ErrorFile;$error.clear() }
102
103       if ($sha1 -ne $Splitting[1])
104       {
105        $Temp = "SHA1 checksum deviating for: " + $Splitting[0] + " [Current: " + $sha1 + "  set to: " + $Splitting[1] + "]"
106        write-output $Temp
107        $SHA1NOK +=  1
108       }
109      else
110       { $SHA1OK += 1 }
111      }
112      $Temp =" Verifying SHA1 checksums... OK:" + $SHA1OK + "   NOK:" + $SHA1NOK
113      Write-Output ""
114      Write-Output $Temp
115      if ($SHA1NOK > 0)
116       { exit 11 }
117     }
118
119    default
120    {write-output "Tool Info"
121     write-output " Parameter:"
122     write-output "  /create   Creates a file list for the defined file extensions"
123     write-output "  /convert  computes the SHA1 checksums and reduces the file list (if applicable)"
124     write-output "  /compare  Compares stored checksums with the current actual values"
125     write-output "  "
126     write-output " Start: powershell -file _noRansom.ps1 /parameter"
127     write-output " Exit:  errorlevel 11 on error"
128     write-output " ==> Default tool settings are defined on launching the script."
129     write-output "  " }
130  }

The create statement (lines 28 to 45) creates a file with a list of bait files. The default is to write the entire drive, including all subdirectories and all files with .log and .eps extensions (the extensions are configurable), to the _noRansom-full.txt file.

The convert statement (lines 47 to 85) processes the file list created with create. Only every fifth file is adopted (the step size can be adjusted), and then it generates a SHA1 checksum for the respective files (Figure 1). The output of the reduced file, including the SHA1 checksum, is stored in the text file _noRansom-mini.txt.

Bait files with checksums are found in the _noRansom-mini.txt file.
Figure 1: Bait files with checksums are found in the _noRansom-mini.txt file.

The compare statement (lines 87 to 117) finally compares the actual state of the bait files on the filesystem with the data stored in _noRansom mini.txt. If everything is the same, the errorlevel output is 0, otherwise > 0.

My _noRansom script suppresses all error messages and redirects them by default to _noRansom-Error.txt. The default values used are defined at the beginning of the script (lines 14 to 19) and can be adapted to suit your needs. For example, you can change the increment for selecting the files you wish to examine. This means compromising between performance and the risk of missing encrypted files.

You can adjust the starting directory for the file search and file types to search for in Get-ChildItem (line 28). Now start a test run by initially creating the database. This is done at the command-line level in the Windows environment with:

powershell _noRansom.ps1 /create

Recursive file acquisition is also usually the parameter that takes the most time to complete, as it involves searching against the filesystem (without considering access permissions and the volume of data). After completing file acquisition with create, _noRansom notifies you with a message on the screen.

Now that you have created the file list, you can thin it out for better performance. Whether this is necessary depends on the size of the list and on the time consumed in the final comparison. The parameter increment (default value: 5) can be adjusted individually (1: check each file; 70: check every 70th file). Thinning out and computing the SHA1 test values is then launched with the /convert parameter.

A glance at the _noRansom-mini.txt file shows the filenames included and the calculated test values. This step completes the data acquisition and conversion. The last point is to check the integrity of the captured bait files. This is handled by _noRansom's /compare parameter.

If there are differences at this point, a file may have been incorrectly entered as a bait file. It is advisable to delete this file from the _noRansom-mini.txt file with an editor.

Use in Production Operations

As previously mentioned, different applications for _noRansom spring to mind. You can create individual bait directories, place scattered bait files, or use a combination of both. You can also add important system files that must always be checked to the _noRansom-full.txt file list and generate a checksum to protect your system components. The use cases are diverse. You can expand the _noRansom.ps1 script to suit your own needs and, for example, optimize the output or error handling (access permissions). My backup scenario requires verifying the bait files' integrity before running a backup. The backup run should only start if Errorlevel = 0. If the SHA1 checksums differ, then further analysis is required. The possible causes are:

Checksum deviations are inevitable during the initial _noRansom phase. However, if you rule out the typical error sources, the script can be useful for discovering the activities of the blackmailing software.

Conclusions

_noRansom provides you with a tool that allows you to check the condition of your bait files regularly. If they change unexpectedly, ransomware is probably to blame. The results of the script can then be used for all possible countermeasures: stopping the backup, alerting by email, and forwarding to a security information and event management (SIEM) system.