Tuesday, April 5, 2016

A Deeper Explanation of How Ransomware Sinkholes Work

In our previous article, one of the proactive methods we discussed was a method that used a recursive mountpoint to create a loop forcing the ransomware to perpetually encrypt the same files over and over.  We appreciate all of the feedback and based on some of the discussion, we would like to explain in greater detail what is going on with the recursive sinkhole.  On the surface, it is very understandable to see this as a bad idea because using an "infinite" loop of directories is going to break stuff.  We want clear up some misunderstandings about how it actually works and why it might not impact you as much as you think.  That being said, some things will likely need some adjustments and every environment is unique and any system configuration should be vetted for stability before being established in production.

To help frame this post, let's establish what exactly our ransomware sinkhole is.  The sinkhole is simply a recursive NTFS junction.  An NTFS junction point is a symbolic link to a directory that acts as an alias of that directory. These are not new. In fact, odds are good that you have tons of them on your system right now.
Ever since early 2007, when Vista came out, Microsoft has included an NTFS junction from C:\Documents and Settings to C:\Users to support legacy software. Profile folders are full of them as well.

Recursive junctions are not new either. In 2005, David Solomon and Mark Russinovich included a recursive mountpoint exercise on page 641 of Microsoft Windows Internals 4th Edition. With that understanding, let's get down to business.

Sinkholes do not create an "infinite" loop.

Windows has very specific limits on file path length that prevent an infinitely long recursive path. For the nitty gritty details, this is a pretty good reference. There are many rules but here are the most relevant:
  • In the Windows API (with some exceptions for unicode), the maximum length for a path is MAX_PATH, which is defined as 260 characters

    • The maximum path on drive X is "X:\some 256-character path string<NUL>" 
    • If you speak Python: len('X:\\' + str('a') * 256 + str('\x00'))
    • This length includes slashes, which means the number of possible subfolders is (260 - 4)/2 = 128, assuming you use single character folder name.
    • This works fine for mapped drives:
  • To further complicate things on local drives, to prevent buffer overflows and "infinite" loops, both command prompt and Windows Explorer halt their recursion when the directory depth reaches 32 or the pathname exceeds 256 characters, whichever comes first. (Microsoft Windows Internals, Fourth Edition, pg. 642)

How does this affect Ransomware? Ransomware needs a listing of your files in order to open, encrypt, and ransom. We are using the a recursive mountpoint to keep the ransomware busy with our canary files while we try to detect and kill the process. To illustrate the point, in the example below we are going to create a folder called "F:\!" and put one document inside that folder, "F:\!\super_important.docx". Then we create a junction named "$" and point that to our F: drive.
You can see in the example that getting a directory listing through this configuration makes it appear like there are many directories and files.

With this simple configuration, we see 32 instances of the same file. Though there are numerous ways to circumvent this and many variants of ransomware, in theory, the ransomware should encrypt this one file 32 times. This is not in and of itself all that impressive but we are only using one file and one sinkhole. If we add just one more single character recursive mount point, we see exponential increases in the instances of files. Since this example is working relatively short paths, given two single character folder names, we are looking at a perceived 2**32 or 4,294,967,296 super_important.docx files.

The recursive junctions should not disrupt AV products.

All of the endpoint solutions we have tested do not scan junctions. Why not? It's fairly simple, junctions represent an actual location somewhere else on the volume so from a security scanning standpoint it is inefficient and redundant to waste the cycles. How do they do it? Endpoint solutions should be scanning the attributes of folder objects and ignoring those that have the "Reparse Point" flag set.  Our testing shows that ransomware is ignorant of the fact the folder is really a reparse point, much less a recursive one.  As mentioned previously, your installation of Windows likely has a multiple reparse points but Windows is also using permissions to deny access when you try to list the contents within the junction, in our examples we are not blocking access with permissions.

Here is an example of how this works:

What will break?  Windows Indexing

We would be misleading if we didn't mention the need to adjust Windows Search Indexing to exclude your sinkhole folders.  Windows uses an index to perform very fast searches of the most commonly accessed files but this service will recursively index your sinkhole as well.  To fix this, you will need to exclude your sinkholes from indexing.  

The best way we have found is to exclude this folder in the Control Panel > Indexing Options.

This is not ideal and we are still looking into a more programmatic method of implementing this.  When we find a clean one, we will update.

What else will break?

With all of the countless scripts that get put into production environments, it is hard to definitely predict what a recursive mountpoint would impact.  That is a big reason why we aren't swearing this is practical for everyone and the technique should be tested in your environment prior to implementation.