Discover ransomware with PowerShell
Danger Ahead
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:
- Patching in good time.
- Working without administrative permissions.
- Hardening the web browser and preventing (JavaScript) scripts, where feasible.
- Disabling macro functionality, where reasonably possible.
- Analyzing email attachments critically.
- Verifying system-wide access permissions.
- Operating multilevel backups.
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
.
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:
- Active ransomware.
- Files modified by a user.
- File has been modified by the system or an application.
- An I/O error has occurred.
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.