Outsmarting Ransomware

Recovering Supposedly-Encrypted Files Without the Key

Introduction

Handling incoming email is the scourge of any small business. Often receiving hundreds of messages per day, a business owner must sift through marketing communications, malware, vendor communications, outright spam, and a dismally small portion of legitimate customer inquiries. As large businesses push “paperless” options aggressively, it is no wonder that personnel face a “Catch-22” of ignoring a legitimate email and allowing financial or logistical situations to snowball and harm customer service, versus opening a phishing email containing malware. It follows that a favorite technique of peddlers of ransomware is to warn of an “important delivery” from FedEx, United Parcel Service or the United States Postal Service about a lost package or other problem. It does not help that UPS’s legitimate delivery problem notifications, like phishing emails, urge the user to click a suspicious-looking “ePackage” link to find out more about the problem.

Recently I was helping an acquaintance who fell for such a phishing email and opened a ransomware Windows executable. The ransomware “encrypted” many files in the user’s user profile directory (Desktop, Documents, Pictures, etc.) and renamed them to have a .crypted file extension. As shown below, the ransomware claimed to have encrypted the files using 1024-bit RSA with a unique key pair, and offered to decrypt the files if the user would send 0.42301 Bitcoin (approximately $2,700 as of this writing) to decrypt the files.

After “encrypting” the user’s files the ransomware displayed its ransom in Notepad.

How Might Ransomware Work?

Interestingly, to implement ransomware in this way is actually plausible. If I were a black-hat hacker (and I’m not!) I might correctly implement this ransomware as follows:

The ransomware would have a public RSA key, preferably 2048 bits or larger and not 1024, baked inside. The ransomware author would hold the corresponding private key. Upon opening, the ransomware would generate an AES (symmetric) key. The ransomware would encrypt that key using the RSA public key, and save that (encrypted) key safely to disk. From then on, the AES key would be kept only in memory. The ransomware would walk through the file system looking for important files. For each file, it would save an encrypted copy using AES-CBC or another suitable mode, then delete the original (using a secure wipe for good measure). To be extra evil, the ransomware would run multi-threaded to maximize the number of files lost before the user notices it running and stops it. If the user attempts to terminate the ransomware, attach a debugger, hibernate the machine, or otherwise interfere, it would immediately wipe the AES key from memory and exit. Once the ransomware is done encrypting files, it would wipe the AES key from memory and display the “README” dialog urging the user to send bitcoin. The ransomware would allow the user to send the RSA-encrypted AES key to the author, and only if the user pays the Bitcoin would the author decrypt the AES key and send it back.

Luckily for users, this ransomware was not so well-written, and I suspect the reason is performance. If the user has 100 GB of documents, then ransomware that attempts to encrypt, write, and wipe 100 GB of data is much more likely to be noticed and stopped than ransomware that subtly but reversibly corrupts files.

Examining the Encrypted Files

Among the “encrypted” documents was one that I will call file1.doc.crypted. First, run the Linux file utility on it and see what it matches:

$ file file1.doc.crypted

file1.doc.crypted: data

Indeed, “data,” which file states when a file does not match any of its known magic numbers, could indicate an encrypted file, which should be indistinguishable from random data. Next, I tried running strings on the file:

$ strings file1.doc.crypted

...

...

Microsoft Word 9.0

...

Title

Microsoft Word Document

MSWordDoc

Word.Document.8

Given these strings in the document, it is definitely not (fully) encrypted. Luckily, file1.doc was an old file and the user had a backup copy. Often, file size will “grow” to a multiple of the block size when a file is encrypted. I decided to compare the size of the original and “encrypted” file:

$ ls -l file1.doc file1.doc.crypted

-rwxr--r-- 1 xxxx xxxx 20992 Oct 15 22:15 file1.doc

-rwxr--r-- 1 xxxx xxxx 20992 Oct 15 22:15 file1.doc.crypted

The file sizes are identical! That means that should this “encryption” incorporate an initialization vector or nonce, it is either stored elsewhere or somehow reconstructed on the fly given the file name or other metadata. Going further, I decided to perform a byte-by-byte comparison on the two files:

$ cmp -l file1.doc file1.doc.crypted

1 320 341

2 317 255

3 21 202

4 340 174

5 241 113

...

1021 0 61

1022 0 142

1023 0 223

1024 0 234

Only the first 1024 bytes of the two files are different at all! Given that I have worked with “handmade” encryption before, I thought of the most straightforward, easy way to “encrypt” the first 1024 bytes of a file — which is to open the file, exclusive-or (XOR) the first 1024 bytes with a constant key, then overwrite them with these “encrypted” values and close the file. Or symbolically:

Plaintext ^ Key = Ciphertext

The problem (for the ransomware author) is that if the victim has a backup copy of the plaintext, he or she can recover the key:

Key = Ciphertext ^ Plaintext

If the same key is reused for different files, this result is devastating to the cryptosystem. If the user has a backup copy of any one file, the user may recover the key and then can use it to decrypt all the files.

Testing the Hypothesis

If my guess is correct that all this ransomware did was XOR the first 1024 bytes of each file with a constant value, I should be able to quickly write a program to take, file1.doc and file1.doc.crypted, XOR their first 1024 bytes together and recover the key:

Next, I run the program and truncate the “decrypted” output (actually the key) to the proper 1024 bytes:

$ ./decrypt file1.doc file1.doc.crypted key

$ truncate -s 1024 key

The real test is to now try decrypting a real “encrypted” file using the obtained key. For testing purposes, I have a PDF:

$ ./decrypt key file2.pdf.crypted file2.pdf

$ file file2.pdf

file2.pdf: PDF document, version 1.3

Looking good. How does it look in Adobe Reader?

And there we have it: any file “encrypted” by this ransomware (or at least this particular execution of it) can be recovered using the key obtained from the backup copy of an encrypted file. It is straightforward to use the find utility to recursively walk a directory tree and replace .crypted files with their unencrypted equivalents through a shell script made to call the decryption utility appropriately.

Lessons Learned

First, just as when assessing real software, don’t assume that if malware claims a file is “encrypted” that it is securely encypted in the sense an engineer might assume, e.g. PGP. Perform a security assessment instead!

Second, after recovering the files, I performed some additional Internet research and found that this was an instance of the “Nemucod” ransomware; a decryption utility is available from Emsisoft. Consider this blog post a writeup of how this ransomware works to complement the publicly-available decryption utilities.