This is a quick post about the WanaCryptor ransomware wreaking havoc on many networks across the world this weekend. With all the news coverage, most of you already know the trouble caused by it.
Once executed on a system, it will use the RSA and AES cryptographic algorithms to encrypt files before demanding payment in exchange for a key necessary to recover those files. If you want to understand the RSA cryptosystem, please read here since all the talk about public and private keys might be confusing to some readers at first.
The source code provided along with this post is intended primarily for security researchers who wish to understand the encryption and decryption process, which may help with recovery of files in the event authors of ransomware decide to release their private key.
There’s no discussion here on any behavior of the ransomware except the encryption/decryption process so if you want information about something else, have a look at this file here which was compiled by various security researchers in the #wannadecryptor channel on Freenode IRC servers.
For the source code to wanafork, see sources in C here. It’s only been compiled with MSVC and tested on Windows, although MINGW should compile it ok, provided it’s a recent version.
Each system generates an RSA key pair of 2048-bits using the CryptGenKey API which is part of the Microsoft Crypto API (CAPI).
The public key is stored in 00000000.pky using CryptExportKey
The private key is stored in 00000000.eky using CryptExportKey but is also encrypted before storage using CryptEncrypt API with the master public key embedded inside the DLL responsible for encrypting files on disk.
This encryption of private key is what prevents recovery of files without assistance from the ransomware authors.
For each file encrypted, CryptGenRandom API is used to derive a 16-byte value which is used with AES-128 in CBC mode to encrypt the data.
The AES key is encrypted with the users public key and stored along with AES ciphertext.
The only way to recover this AES key and thus the contents of encrypted files is through decryption using the private key and we need the master private key to do this.
Ransom payment process
Although I haven’t researched this at all, it seems reasonable to make some assumptions based on the encryption model that some component of the ransomware sends the encrypted private key stored in 00000000.eky to a server over the TOR network where it’s decrypted by the ransomware authors using their master private key.
The decrypted private key is then sent back to the victim’s system and stored as 00000000.dky which allows @WanaDecryptor@.exe to recover files.
Open to correction of course. It has been pointed out by some that there’s no way for the ransomware authors to identify who makes a payment.
Because of the algorithm used, it isn’t feasible to recover data from encrypted files without assistance from the ransomware authors.
The rest of post may only be of interest to developers / researchers.
You’ll see these values throughout the source code shown here.
WanaCryptor Archive Structure
Each encrypted file or what I call archive, has a predefined structure necessary for successful decryption.
- Key Length
- Encrypted AES key
- Unknown 32-bit value
- File Length
64-bit signature. Currently set to the string “WANACRY!
Indicates length in bytes of the following encrypted AES key.
128-bit AES key encrypted using the users RSA public key stored in 00000000.pky
This key is generated by CryptGenRandom.
I’m unsure what this is for yet. It’s usually set to 3 or 4
64-bit value obtained from GetFileSizeEx which indicates the original size of file.
Encrypted data using AES-128 in CBC mode. Uses zero padding.
The following is a structured hex dump of encrypted file generated by the malware.
RSA Key Generation
As said, the RSA keys generated are unique to each system.
In the tool, both public + private keys are exported in their plaintext form. The private key is also encrypted for illustrating how the malware does it.
AES Key Generation
The AES keys for each file are generated using CryptGenRandom API which is cryptographically secure and therefore invulnerable to attack.
When decrypting an archive, we need to decrypt the encrypted AES key using the RSA private key blob stored in 00000000.dky
In both scenarios, because I’m using Crypto API for AES, additional steps are required to import the key into a CAPI key object.
I’d guess using a custom AES was probably easier to use than Crypto API, but that’s just speculation on my part.
WanaCryptor uses Zero Padding, but Crypto API doesn’t support it.
Rather than set the bFinalize flag to TRUE when encrypting final block, the buffer should be aligned by 16 bytes and padded with null bytes. The bFinalize flag should remain FALSE in order to be compatible with WanaCryptor.
Here’s an example of creating a WanaCryptor archive and using Crypto API to perform AES-128-CBC encryption of file data.
As with Encryption, the bFinalize flag (if using Crypto API) should always be FALSE. This is because Microsoft Crypto CSPS don’t support zero padding.
Without the master private key generated by the authors, it’s not possible to recover data from encrypted files unless by miracle someone discovers a flaw with either AES or RSA.
Thanks to 0x4d_ for helping with post and all the folks on freenode for researching this malware over the weekend.
This tool will require a lot more testing before it can be considered reliable and the only reason for releasing it early is so that others can study the source and write their own decryption tools.