Friday, March 25, 2016

Proactively Reacting to Ransomware

For our inaugural post, we thought we would share some proof of concept ideas regarding potential reactions and responses to ransomware outbreaks.  We have been tossing around some ideas and scripts, that we think can buy the victim back some time when their machine is being infected by ransomware.  The hope being that this additional time allows the victim time to react to the infection and hopefully provide the victim an opportunity to remedy the situation.

As an incident responder, we all know that ransomware cases can be overly damning to a victim and an organization, so reacting to them as quick as possible is crucial.  Since protections in place, such as AntiVirus are constantly in a rat race, that is usually one step behind, it puts everyone at a disadvantage.  One thing you can say about ransomware is that it isn't hard to spot a successful infection.  Forensically speaking, it is overly noisy and riddles the host with artifacts of its execution.

Knowing that there are numerous artifacts and infection actions you can bank on, things such as file overwrites, an infection order, known extensions targeted and potentially persistence, what would happen if you reacted on those events specifically and not the malware itself.  If we reacted on these events instead of looking for a stage1 or stage2 drop, the majority of ransomware infections could be delayed, buying back some time for the victim and incident responder to react and hopefully stop the infection.

File Canaries:
Take for example the standard scenario where the user receives a malicious email and then unknowingly acts on the attachment, allowing the ransomware to start the initial stages of infections.  Once all the pieces are in play and the ransomware starts the encryption process, it will usually target files of a known type, files such as office docs, audio files, video files, images and in some cases script file extensions.  Besides targeting files of a specific type, it will also start the encryption process by beginning the process down the root of C:\ or beginning by encrypting the files within the running user's profile.  Once the local drive has been encrypted, the malware can then move on to targeting mapped drives and begin encrypting the mounted share's content.

So knowing these elements of the attack, we wondered if we could setup a canary file or a canary directory and then automatically respond when one of these files are written to, aka overwritten by encryption.  Of course, we want to respond in the safest manner possible, so we would need to be careful about creating these canaries.  Knowing that multiple tools and programs comb through your files regularly, you want to ensure your permissions are right.
What type of non-intrusive reactions should we implement
  • Notify a responsible party via email
    • This is likely the lowest level of reaction we thought was appropriate.  It does nothing for protection, just simply alerts someone.
  • Disconnect all mapped drives
    • This action will at least protect any mapped shares or devices, containing the infection to the single endpoint.
  • Slow down the malware and attempt to kill the process
    • Later in the post we will illustrate some interesting techniques that can be performed to slow ransomware down. Some of these techniques are fairly aggressive and could cause problems if triggered by a false positive.

Below is a short Powershell example that could be used as a base to monitor for canary file changes.  The script creates a single canary file, enables monitoring the file for LastWrite changes and responds when the file is written to by sending an email and unmounting any mapped drives.

This is a passive measure aimed at detection and containment. This is a very non-invasive way for companies to confine outbreaks of ransomware within a particular endpoint and prevent network resources from being affected. One of the big down sides of this example is that we aren't actually disrupting the course of the malware and we still have a mess to deal with on the local endpoint.

Example 1:
$DirPath = "C:\Temp\"
$FName = "Redemptio*.docx"
$FilePath = Join-Path -Path $Dirpath -ChildPath $FName

function DriveUnMapper {
$MappedDrives = Get-WmiObject -Class Win32_MappedLogicalDisk
ForEach($Drive in $MappedDrives){
net use $ /delete

function CreateWatcher {
$global:FSWatcherObj = New-Object IO.FileSystemWatcher $DirPath, $FName -Property @{
IncludeSubdirectories = $false;
EnableRaisingEvents = $true;
NotifyFilter = [IO.NotifyFilters]'LastWrite'
function RegisterWatcher {
Register-ObjectEvent $FSWatcherObj Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore red
$logdata = "$(Get-Date), $changeType, $FilePath, was altered! Disconnecting Drives"
Add-content "C:\Users\user\Desktop\Redemptio.bla" -value $logdata
$smtp = New-Object Net.Mail.SmtpClient("smtp.yoursite.notreal")
$smtp.Send("SecurityNerds@yoursite.notreal","Management@yoursite.notreal","Ransomware File Canary has been written to on " + $env:computername,"Information on the Event:" + $logdata + "Disconnecting network drives.")
function CreateCanary {
New-Item C:\Temp\Redemptio-canary.docx -ItemType File -value "Redemptio canary file - do not write to file"

Below is a C# example that works in conjunction with Object Auditing and Audit Rules.  When Object Auditing is enabled to audit Write Data, we can monitor for those security events and then react.  Most applications installed or resident on the system will potentially read or access these file canaries, so you want to ignore those read events and only focus on the writing of the file.  When you create your canary files you want to enable Create Files/Write Data, Create Folders/Append Data NTFS permissions.  Object Auditing can be enabled in your Local Security policy or via GPO or via .Net but given most likely use a Global Policy it may not be worthy of including in your script.  See Example 3 for some code examples for the Audit Rules.

In this example, the script will monitor the event logs for Security-Auditing events that contain the filename or directory name you picked.  Since it will only trigger when data is written to the canary file, this example script will then kill the process that wrote to the canary.  Depending on your needs you can combine actions, so you could also unmount any mapped shares and send an email, or whatever action you feel appropriate.

Example 2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading; 
class Redemptio
   static AutoResetEvent signal;
   public static void Main()
       public static void Main()
        signal = new AutoResetEvent(false);
        EventLog myNewLog = new EventLog("Security", ".", "Microsoft Windows security auditing.");
        myNewLog.EntryWritten += new EntryWrittenEventHandler(MyOnEntryWritten);
        myNewLog.EnableRaisingEvents = true;

    public static void MyOnEntryWritten(object source, EntryWrittenEventArgs e)
        string proc = "spiderham";
        string src = "Microsoft-Windows-Security-Auditing";
        bool a = e.Entry.Source.Contains(src);
        bool b = e.Entry.Message.Contains(proc);
        if ((a) && (b))
            Console.WriteLine("Current message entry is: '"
   + e.Entry.MachineName + e.Entry.TimeWritten + e.Entry.Source + e.Entry.Data[0] + "'");
   string str1 = "Process ID:";
   string str2 = "Process Name:";
   int startindex = e.Entry.Message.IndexOf(str1);
   int endindex = e.Entry.Message.LastIndexOf(str2);
   int length = endindex - startindex;
   string fullLine = e.Entry.Message.Substring(startindex, length).Replace(" ", string.Empty);
   string[] result;
   result = fullLine.Split();
   string strpid = Convert.ToString(result[2]).Remove(0, 2);
   int pid = Convert.ToInt32(strpid, 16);
   Console.WriteLine("Killing Process ID: " + pid);
   Process evilproc = Process.GetProcessById(pid);
   Console.WriteLine("Process ID: " + pid + " killed.");

Below is a Powershell example that sets up your Audit Rules but for a canary directory and all the files within that folder.  In this example, the canary directory is called '$', more on why we named it '$' later.

Example 3:
$AuditUser = "Everyone"
$AuditRules = "WriteData"
$InheritType = "ContainerInherit,ObjectInherit"
$AuditType = "Success"
$AccessRule = New-Object System.Security.AccessControl.FileSystemAuditRule(

$HoneyPot = Get-ChildItem 'C:\$'
ForEach($FileCanary in $HoneyPot){
$ACL = Get-Acl $FileCanary.FullName
$ACL | Set-Acl $FileCanary.FullName

The first few examples create file canaries in our honeypot folder to give us the time to find, alert on, remove mappings and or kill the malicious process. But depending on where you place your canary folder or files and what you name them, the malware might be able to encrypt hundreds files before it hits your canary files.  Most ransomware uses relatively simple cryptographic methods that computationally take almost no time at all and present us with a hefty challenge on reacting quickly. We needed a way to keep the malware busy doing something harmless, before it got to our actually files.

So why did Example 3 use '$' as the canary directory?  Say you create a mountpoint called '$$'.
Example 4:
Powershell example to create a '$$' mount point to C:

#Let's grab the DeviceID for the C volume
$Volume_info_for_C = Get-WMIObject -Class Win32_Volume -Filter "driveletter='c:'"
$Device_ID_of_C = $Volume_info_for_C.DeviceID
#Normally, everything is mounted only to the root (C:\) but we are going to get creative.
$Sinkholes = @('$$')
ForEach($Sinkhole in $Sinkholes){ 
    New-Item c:\$Sinkhole -ItemType directory

So what happens when you browse to that directory?  You'll quickly notice you hit a recursive loop.
Screenshot of the C volume in windows explorer.
Here is the C:\$$ "folder".
Here is C:\$$\$$\$$ "folder".

How does this actually help? If the ransomware iterates from the top of the volume, this seemingly infinite loop of folders infinitely increases the "distance" to get the files we want to protect.

Let's take a look at the difference in ProcMon.
Here is an example of Teslacrypt enumerating through a Windows VM without a sinkhole:
In the picture above, we can see that the C:\* is queried and $Recycle.Bin folder is the first one returned, so it starts recursively searching for files.

So what does it look like when Teslacrypt hits our mount point.
This ransomware is not able to recurse the drive because of the mountpoint we created.  It just goes on and on hitting C:\$$.  You may be wondering "What if it doesn't start recursing at the top of the volume?".

In order to crack that nut, you could create multiple sinkholes, for example putting an additional sinkhole in a user profile.

$Sinkholes = @('$$','Users\$GoToJail','Users\username\Documents\$GoDirectlyToJail')
ForEach($Sinkhole in $Sinkholes){ 
New-Item c:\$Sinkhole -ItemType directory

If the ransomware hits the Users\username\Documents\$GoDirectlyToJail "folder", it will get sent back to the top of the volume where it will be sinkholed by the C:\$$ "folder".

The example below uses the file canaries and the sinkholes concepts together.  The script creates plain text canary files using the extension list, creates the sinkhole mount point.  This script will force the ransomware into a loop, so it perpetually encrypts the same canary files over and over again.

Example 5:
$HoneyPot =  "c:\`$\"
New-Item $HoneyPot -ItemType directory
#Here are a few of the popular extensions for Ransomware to target.
$exts = @(".c",".h",".m",".ai",".cs",".db",".db",".nd",".pl",".ps",".py",

ForEach($ext in $exts){
  #For each extension, this will create a puedorandom number of files between 2 and 5
  #We don't want this ransomware to get bored while we are trying to kill it.
  For($i=1; $i -le $(Get-Random -Minimum 2 -Maximum 5 ); $i++){ 
  #Now we are going to create the file contents.
 $textout = ""
      For($i=1; $i -le $(Get-Random -Minimum 10 -Maximum 1000 ); $i++){ 
          #For puedorandom characters
          #$textout += -join ((65..90) + (97..122)|Get-Random -Count 64| % {[char]$_})
          #For some plaintext easy to read
          $textout += "Completely Plaintext File. "
 #More random filenames because...why not?
 $RandomFileName = -join ((65..90) + (97..122)|Get-Random -Count 8|% {[char]$_})
 #Save random file contents to random file name with our extension
 $RandomFilePath = ($HoneyPot + $RandomFileName + $ext)
 $textout| Out-File -FilePath $RandomFilePath -Force -ErrorAction SilentlyContinue

#Next we create the sinkhole.
#Let's grab the volume info for C
$Volume_info_for_C = Get-WMIObject -Class Win32_Volume -Filter "driveletter='c:'"
#Now lets snag the DeviceID
$Device_ID_of_C = $Volume_info_for_C.DeviceID
#We are going to use the DeviceID to setup some new mountpoints for this volume.
#Normally, everything is mounted only to C:\ but we're going to get creative.
$Sinkholes = @('$$','Users\$GoToJail','Users\username\Documents\$GoDirectlyToJail')
ForEach($Sinkhole in $Sinkholes){ 
    New-Item c:\$Sinkhole -ItemType directory

On Windows x86 systems, it is trivial to review the open handles and find the process that has opened the canary file.  Using something like file handles makes it a hair easier than solely relying on Object Auditing and Event Log monitoring.  Below contains a Python script that will look at the open handles and kill the pid associated with the open handle to the canary directory.  It should be noted that this by itself would trigger on any open handle, so read or access changes would trigger this, so you may want to only use this as an option when you have been alerted to an event via file monitoring or Event Log escalations.

Example 6:
#!/usr/bin/env python
import psutil
#setup a loop
while True:
    #loop through each of the running processes
    for proc in psutil.process_iter():
            #Grab some info
            info = proc.as_dict(attrs=['pid', 'name'])
            for path, fd in proc.open_files():
                if r"C:\$$" in path:
                    #display info about the process
                    print info, path
                    #kill it

Using the handles solution is great for Windows x86 systems but given those aren't in use as much anymore.  This method falls flat on modern PCs, due to Microsoft's Driver signing policy, starting with 64-bit versions of Windows Vista and later.  For this reason, utilities that display open file handles like Handle, Process Hacker, OpenedFilesView load their own signed driver that is used to extract information from Windows Kernel and if you prefer you can utilize the output of these tools.  There are a handful of MS SysInternals Handles.exe scripts that read in handles.exe's output.

Lastly, here is yet another show stopper action that can be taken after a ransomware trigger.  Unfortunately, this one is much more damning than the others and not really mean to be a potential solution, just something fun to experiment with.

The batch script below creates a fork bomb which consumes all resources bringing your system to a halt, thus halting the ransomware.

Example 7:
Fork Bomb
start %~dp0%~n0%~x0

The %~dp0%~n0%~x0 is fancy batchfu for the complete file path of the batch script that is running. Every time this runs it creates another instance of itself and then runs another instance and pipes that output into yet another. This consumes all available memory leaving nothing for the malware or any other process to use. While this was able to stop Teslacrypt and others after approximately encrypting 5 canary files but like we mentioned this might not be the most practical idea because it does introduce a vector for Denial of Service.
Screenshot of Fork Bomb Result
As always, there are a handful of ways to skin a cat but we wanted to lay out a handful of low resource intensive reactionary response solutions.  Knowing some of these might come with a risk for your environment, you should test to see what solution may be a possibility for your environment.


  1. Some nice ideas there. But your DriveUnmapper function will hang your script if there's an open file on a shared drive. You'll need to force it.

  2. Quite like the recursive folder too - just exclude it from your backups; )

  3. Hey Andrew, thanks for replying. Good catch! "net use $drive /delete /YES" or "Remove-PSDrive -force" should correct for that. Thank you.

    As for the backups another good point, we haven't tested against backup solutions. We did test against some AV products and they skip right over the recursive folder, hopefully robust backup solutions do too.

  4. As Andrew has mentioned and just to put it out there for others, I should re-mention:
    That these techniques would need to be tested within your environment and against your installed file system agents. If something like the recursive sinkhole doesn't work for you, perhaps the simple monitoring of the canary files and reacting to them via email alerting, unmounting shares and/or killing the pid would suffice for your needs.

  5. Hi, hopefully there will be a solution for Srv OS...!!! Since 2 of our customer Terminalservers were crypted we installed Malwarebytes Antiransomware. Since that time no Client was infected with ransomware malware. But there are no solutions for Servers :( And the highest threat sits in front of the monitors, opening email attatchments without thinking.... Thanks for your work!!! Keep going

  6. Hi would those hidden shares work on a maped drive too?

    1. You will not be able to set up a recursive mount point (sinkhole) on a remotely mapped drive. You will have to configure this locally on the server. Once configured, it does work when the drive is mapped.

  7. Thanks for posting this, interesting ideas; I looked at the Example 5 script (the file creation line has a typo $RandomFile should be $RandomFilePath) first.

    Couple of questions...first, are you aware of any side-effects to sprinkling these mount points on different volumes? I suppose this could trap other software, too.

    Second, again with respect to the mount points, it seems to be a low-resource idea to implement, but it also seems to be reliant on the bad guys sticking to a rudimentary implementation of how they iterate. My concern would be about its longetivity.

    Thanks again,

    Philip Sloss

    1. Thanks for the heads up on the typo. We corrected. We haven't found any that gets tripped up by these recursive junctions. All of the endpoint solutions we have tested do not scan junctions. They represent an actual location somewhere else so it is inefficient and redundant to waste the cycles. As far as longevity goes, we agree that could be easily dodged but the more steps malware has to do, the easier it is to spot.

  8. Do you know 'AntiRansom' ?

    1. Hadn't seen this before but it looks akin to our efforts. From the description, it looks like it uses monitors for folder for changes, when a change is noticed it runs Handle to find the responsible process, dumps the process with ProcDump, and then terminates the process. Good to know we are all on the same track.

      We wrote a script that did this without the process dumping and we got inconsistent results when trying to get the process to terminate in a useful amount of time. Seemed like it burned through our fake files and on to real files before all of the moving parts would line up to terminate the process. How has your testing faired against different ransomware? Is your source available for review?

    2. Thank you for the reply. As you say, We are on the same way. I have tested with some ransomware with very good results. I choose to no release the source because at the end, Anti Ransom is a Perl script compiled with a commercial license form ActiveState, so few people could compile, try and improve.

  9. Once you identify the offending process, is it worth it to dump memory of that process before killing it to try to recover any crypto keys stored in memory? I assume (but don't know) that most variants use asymmetric crypto and only ever have the public key hit the victim's machine. Are there any that either use symmetric encryption, or generate both keys on the victim's machine and then send one to the author?

    1. some of the cases like Cryptolocker file. have unique keys symmetric keys for each files which is appended to the starting of the file. So the approach of dumping keys might not be effective solution against most of the family

  10. Really nice ideas. I tried to rebuild this but the C# code doesnt seem to work.

    I changed the proc string and removed one of the two "public static void Main()".

    I also removed the check if both strings a+b are matching, so the tools should be triggered by each myNewLog.EntryWritten event - but that doesnt happen. I used NTFS audit and i can see that my file-acces "echo foo >> bar" are creating an event within the security log.

  11. I managed to fix the C# for my situation. I tested the Sinkhole function but it seems not to work. Tried a ransomware sample and it doesnt get caught in the sinkhole but keep on encrypting files withing user directory and desktop. I placed working "$GotoJail" directories in critical paths.