Many people have felt the global impact of WannaCry - from late nights to a heightened sense of awareness, WannaCry has put many people on edge. Unfortunately, WannaCry will not be the last outbreak as assuredly as it wasn’t the first. Complex software systems will always have bugs. However, the knowledge, skill, and time needed to ferret those bugs out and develop them into exploits has increased significantly. With WannaCry, we’ve witnessed what can happen if those weaponized exploits are not safeguarded and handled like the dangerous weapons they are.
We are continuing to track the WannaCry ransomware plague and determine what can be learned from this global crisis. The folks at EndGame did an amazing job of breaking down the WannaCry ransomware worm. If you want a play-by-play analysis of the wormable variation, we highly recommend you dig into their post (after you’re done reading this, of course).
As a team, we’ve primarily been tracking coverage of WannaCry to ensure new variants are covered by our product. As a result, we’ve been slogging through a surprisingly large number of variations.
Here’s what we have discovered.
First, a quick overview of the WannaCry worm for those unfamiliar with the inner workings of this ransomware:
Worm (a.k.a. mssecsvc.exe)
The worm is the first-stage dropper and is responsible for the worming behavior of this ransomware. It is 3.6MB (3723264 bytes) in size, and contains the URL "kill-switch" along with the SMB exploit for MS17-10. It contains the second-stage dropper in the clear as a resource named 'R', Since the dropper is in the clear and not otherwise compressed or obfuscated, string-based detections made for the dropper will always hit on the worm too, unless other conditions are added to those rules.
The propagation works by randomly generating IP addresses and trying to connect and then exploit the remote system. We’ll go into detail later about how the exploit payload is created, but the key thing to know is that the payload is generated in memory and delivered over the network to the exploited process’s memory. Once code execution is passed to the payload, its sole purpose is to drop a copy of the worm to disk and execute it.
This is where most antivirus (AV) vendors, including Cylance®, will have an opportunity to prevent WannaCry. Unless, of course, the vendor hooks functions in kernel processes, which is a risky proposition and can even increase the attack surface.
VIDEO: Cylance vs. WannaCry/ WanaCrypt0r/EternalBlue Ransomware Worm
Dropper (a.k.a. tasksche.exe)
The dropper is the second-stage dropper. The file is 3.4MB (3514368 bytes) in size, with no kill-switch or spreading mechanism. It’s configured to run as a service by the worm or it can run on its own. It contains a password-protected archive in the resource section of the file that is typically named XIA.
Decryptor (a.k.a. @WanaDecryptor@)
The decryptor presents a graphical user interface to the end-user and demands payment. While not malicious, it may present a scary-looking dialog if double-clicked in isolation. This file is harmless without the other components of WannaCry, namely the language files and Tor client, and most importantly, the ransomware.
Ransomware (a.k.a. t.wnry)
Finally, the ransomware. This component presents itself as an encrypted blob while on disk. The ransomware can’t do any harm while in this state and must be loaded and decrypted by the dropper.
If you’re following the WannaCry saga on social media, you might notice the confusion around new variants. As noted by the press early in the outbreak, the worm had a built-in kill switch that attempted a connection to a hardcoded domain. If it succeeded, the malware exited.
Naturally, all one needed to do was to modify this hardcoded string to start things up again and produce a new variant. So, researchers have been watching for new variants like hawks. However, by the end of the day on the Monday following the outbreak, no new significant outbreaks occurred. Security researcher Matt Suiche is registering new domains as they are discovered, but only two new domains appeared over the weekend and into Monday.
So, about those variants… we have roughly 53 worms, 44 droppers and 21 ransomwares at the time of this writing, all unique by hash. What’s going on? These are not true variants in the sense that they provide new functionality or changes to the way the malware works. In fact, the only variable portion of the worms and droppers is the resource section.
As noted last Friday by security researcher Zammis Clark, the malware constructs a DLL payload in memory using embedded x86 and x64 DLLs. That write-up mentions how the original worm is appended to the DLL, then highlights the area of the code in the DLL that extracts and runs the worm.
However, the extraction routine was not discussed in depth. Could there be something creating variability? Using this sample on VirusTotal as an example, we can inspect the payload creation code and discover the size (same as Clark’s analysis) and location of the DLL (Figure 1).
Figure 1. Payload Creation Routine in Worm
We can jump to the virtual offset in the file and IDA will helpfully show us the physical offset we need (Figure 2, note the red box). From there, it is a simple matter of carving out the file using any tool you prefer.
I used Python to do something like this:
with (‘worm.exe’,’rb’) as file_handle1:
with (‘embedded_dll.bin’,’wb’) as file_handle2:
file_handle2.write(file_handle1.read()[0xb020 : 0xb020+0x4060])
Figure 2. Exact Location of Embedded x86 DLL
Once extracted, we can have a look at the layout of the DLL. The resource section in the DLL indicates a much larger size than the physical size of the file (Figure 3). All the functional, non-corrupted worms we’ve seen are 3.6MB in size, so this provides plenty of headroom to append the binary.
Figure 3. Sections of Embedded x86 Payload (Note .rsrc Size of Raw Data)
However, creating the payload in this way would look weird on disk and present some anomalies from executable inspection tools. If the resource was extracted using the size of the resource returned by SizeOfResource, then, at best, you would get junk data from wherever the DLL resides in memory, and you’d probably more likely get an access violation. Remember, this DLL + payload will run inside kernel space on the exploited system. That kind of mistake could lead to a blue screen.
Alas, we are not so lucky. The malware author did their homework and prepended the file size of the worm to the payload. This allows the extraction DLL to read this value and exactly write the correct number of bytes when it runs on a remotely infected system (Figure 4). There appears to be no bug or flaw in this code that would lead to a variation in the worm.
Figure 4. Size Checks and Proper Extraction of Worm Payload
As noted by many researchers, it would be trivial to update the worm’s resource section with any payload you wanted. There is some structure there, but essentially what you have is an embedded executable. The worm indiscriminately extracts the payload and executes it. So! Maybe some bad actors have been creating new worms with different payloads.
Actually, in all the droppers we know about, the .text, .rdata, and .data sections are identical. Meaning, again, the only significant difference is in the resource section, which is different for each unique hash we have.
The resource section for the dropper is an encrypted ZIP archive. The dropper has very set expectations for the contents of this archive, so while it might be possible to repackage the file with updated contents, the name and type of each item would need to stay consistent. Again, the EndGame post provides a great overview of the role for each file.
One component, namely the decryptor, does present some variability in the .text (code) section, which means the binary may have slightly different code flow. Also, there is duplication in the other sections as well, resulting in unique hashes for the decryptor. Ultimately, the changes in the decryptor cascade to create variability in the dropper and the worm. The other components in the embedded archive have remained fairly consistent.
We wanted to get a clearer picture on the hash variance we were finding in the wild. Although there is plenty of opportunity and places to modify the wormable variant of WannaCrypt, we do not see any attempts to replace the payload of the worm or modify the functionality significantly. The repackaged ransomware appears primarily designed to introduce variability into the wild and prevent simple hash blacklists from slowing the spread.
Check out our video, where we show Wannacry in three scenarios:
1) On an unprotected single machine
2) On a single machine protected by CylancePROTECT®
3) Multiple victim machines with Cylance stopping further communication
If you use our endpoint protection product, CylancePROTECT, you were already protected from this attack and all variants. If you don't have CylancePROTECT, contact us to learn how our AI-driven solution can predict and prevent unknown and emerging threats.