The security research group at Cisco known as Talos wrote a fantastic article on their research of Cryptowall4. They explain what is new and how it works with detailed examples. The original post can be found HERE.
EXECUTIVE SUMMARY
Over the past year, Talos has devoted a significant amount of time to better understanding how ransomware operates, its relation to other malware, and its economic impact. This research has proven valuable for Talos and led the development of better detection methods within the products we support along with the disruption of adversarial operations. CryptoWall is one ransomware variant that has shown gradual evolution over the past year with CryptoWall 2 and Cryptowall 3. Despite global efforts to detect and disrupt the distribution of CryptoWall, adversaries have continued to innovate and evolve their craft, leading to the release of CryptoWall 4. In order to ensure we have the most effective detection possible, Talos reverse engineered CryptoWall 4 to better understand its execution, behavior, deltas from previous versions and share our research and findings with the community.
One interesting observation with CryptoWall 4 is if it cannot retrieve the public RSA encryption key from the C2 server it will enter a loop constantly attempting to download the public key. As long as the key cannot be obtained, CryptoWall will not “harm” the victim’s computer. Talos also observed that this sample exhibited some additional safety checks, such as terminating the infection process if the local language is not supported. The following is a non-exhaustive list of some of the unsupported languages:
Russian, Kazakh, Ukrainian, Uzbek, Belarusian, Azeri, Armenian, Kyrgyz, Georgian.
This clearly shows the adversaries want to exclude certain regions from infection.
All functions starting from “Delete all shadow copies” in the above diagram are executed from the CryptoWall 4 code injected in the svchost host process. Injection into this process is increasing the privileged level of access to the compromised machine; this allows the deletion of all available shadow copies without the end user being prompted with the UAC (User Account Control) dialog to ‘Approve’ the deletion if the user has administrator level access rights.
CryptoWall 4 is using a new file name generation algorithm which is used for the encrypted files, which works as follows:
- Scan hard drive for directories, skip excluded directories
- Get original file from directory, skip excluded filename and extensions
- Generate random value for the filename string size between 5 and 10
- Build a filename string with the length of this random size out of the character set ‘a-z’
(Get random value between 0-1000, do a MOD 26 and convert it to an ASCII character) - Null terminate the filename string
- Get a random number between the half of the string and the string size
- Get a random number between 1 and this random number from Step 6
(This number is used as value for how many random numbers are inserted into the string in the next step) - Generate a random ASCII number (char) between 0-9 and insert it at a random position in the string
- Do step 8 as many times as the random value in step 7 says
- Use the same algorithm to generate the extension, but with a min. size of 2 characters and max.size of 5
- Append the extension to the file name string
CryptoWall 4 is using CRC32 checksums to exclude some directories, filenames and extensions. The following is a list of what is excluded from encryption.
Extensions:
exe, dll, pif, scr, sys, msi, msp, com, hta, cpl, msc, bat, cmd, scf
Directories:
windows, temp, cache, sample pictures, default pictures, Sample Music, program files, program files (x86), games, sample videos, user account pictures, packages
Files:
help_your_files.txt, help_your_files.html, help_your_files.png, thumbs.db
The full exclusion table can be found in Appendix A.
We believe these directories, files and file extensions are avoided to ensure stability of the operating system, this means the compromised user can still use their machine to pay the ransom. Any infected user should remember that if persistence is successful the encryption function will run again on the next reboot to encrypt any files the user created after the initial infection.
After generating the names for the new files, it starts the encryption algorithm shown in Figure F. This also clearly shows there is no way back after CryptoWall 4 has encrypted the files, without having the private key to decrypt the temporary AES encryption key. Unfortunately, for the victim, this only exists on the attacker side and is never transmitted to the victim’s computer. In other words, there will be no viable way to recover the files without paying the ransom or getting the private key from the adversaries in some other way, such as law enforcement seizing their infrastructure. Users are encouraged to have backups of important files to ensure they can sufficiently recover from these types of attacks without having to pay any ransom
THE DROPPER
The dropper is compressed and encrypted with different customized packers, full of useless code, API calls, and AV anti-emulation tricks such as calling random APIs with strange parameters to confuse the emulation engines.
The second stage uses a form of Spaghetti code implemented in the following way:
INSTRUCTION 1
INSTRUCTION 2
JNO nextStep
THE DECOMPRESSED CODE
The main code is very similar to the old iteration of CryptoWall: the malware builds its Import Address Table (IAT), obtains all the needed system information and creates its main event object for process synchronization (the name is generated from the workstation information MD5). This event has 2 goals: prevent any other CryptoWall 4 infection starting during execution and synchronization between the different involved processes.
- ZwCreateSection and ZwMapViewOfSection native APIs
- ZwAllocateVirtualMemory, ZwWriteVirtualMemory and ZwProtectVirtualMemory native APIs
At the end the code is properly relocated and another 2 different techniques are employed for the actual code injection:
- ZwQueueApcThread internal API used to queue an APC in the target process
- The classical CreateRemoteThread method
The dropper tries to disable all the System Restore Points and Windows Shadow Copies using a novel method previously unseen: it calls the SRRemoveRestorePoint API, with an index from 0 to 1000, until it returns ERROR_INVALID_DATA. It writes the value named “DisableSR” (set to 1) to the “HKLM\Software\Microsoft\Windows Nt\SystemRestore” registry key aiming to completely disable the Windows System Restore. Finally it launches the standard command to delete the Volume shadow Copies:
vssadmin.exe Delete Shadows /All /QuietExecution continues in the “svchost.exe” process, The code re-builds the IAT, creates another event object (used only for the “svchost.exe” instance), and then tries to generate and open its configuration file. More on the configuration file later. At this point the routine fails because the configuration file doesn’t exist yet. The dropper opens and decompresses the C&C URL list located inside itself (compressed with an LZ compression algorithm) and finally it tries to connect to one of its C&C servers using an announcement packet.
You can find a list of the C&C servers found in the analysed dropper in the IOC section.The CryptoWall 4 network packet is specifically crafted as below:
|<request Id>|crypt7|<workstation MD5>[|subRequest Id 1|subRequest 1 Data| … ]
At the time of writing, we have successfully isolated five different network packet types (request ID):
1, 3 – Announcement packet – used to communicate to the C&C server that a new victim has been infected
7 – Multi purpose packets. The first sub-request ID differentiates packets:
1 – Public key request – used to ask to the C&C server for a new public key (and the
language-dependant PNG wallpaper) to properly encrypt all the files
2 – End announcement packet – used to communicate that an infection is ended.
Another sub-request ID defines more precisely how the infection is ended:
1 – Success
2, 3 – Unsupported OS language packet – Exit
The network packet is sent to the web using a standard HTTP Post request, but is encrypted right before. The encryption algorithm is a custom one that uses a random string as key and produces a stream like the following one:
|<Letter>|=|<encryption Key in Hex>|<encrypted stream>|
e.g. s=6975376e7a9b0fd24886fbd0c0de32d3ab4dd97174462ca3b06af16a1c840ae893eddacafbd93e56847c23a41352d4f45fc75468e4408
After the announcement process has successfully contacted the C&C it will try to obtain the public key. Here is a weak point of CryptoWall 4: if a strong firewall or IPS is able to intercept and block the CryptoWall 4 packets, the infection will not continue. The RSA-2048 public key is retrieved using a packet with ID set to 7. The C&C server answers with a packet composed as the following:
- List of the payment URL (Tor URLs and standard URLs)
- RSA-2048 Public key codified using base-64 encoding
- A base-64 encoded language-dependant PNG picture
- (see Figure H.1-3, e.g. English or Italian or German or others, depending on the local language settings)
The public key is decoded using the CryptStringToBinary API. The decrypted buffer is stored in a global variable. The HTML and text files (compressed with LZ algorithm) are extracted from the dropper and finally the configuration file is generated, encrypted and stored in the following location:
C:\Users\<Username>\AppData\Roaming\<Random 8 digits>
CryptoWall 4 stores the following information inside the configuration file:
- the received public key binary data
- the HTML page showed to the user in the proper language
- the text file showed to the user in the proper language
- finally the localized PNG picture in the proper language
The configuration file is finally compressed with the LZ algorithm (using RtlCompressBuffer API, with index 2 – COMPRESSION_FORMAT_LZNT1) and written to disk.
THE MAIN THREAD
The main thread starts by importing the public key. This means translating the encoded public key binary data in a proper data structure that can be used by the Windows Crypto APIs. CryptoWall 4 does this process using the CryptDecodeObjectEx API. In this way, the binary data could be transformed in a CERT_PUBLIC_KEY_INFO structure. Finally, the new data structure is imported in the Crypto APIs usingCryptImportPublicKeyInfo function: a crypto-handle is returned. Then the MD5 hash of the public key is calculated. This is a very important step because it will be used to verify if a particular victim’s file has been already encrypted.
At this point, the real encryption process take place. For each logical drive found in the victim system, a check is performed:
Practically speaking, if the root path of the drive contains a file named “HELP_YOUR_FILES.PNG”, it will be skipped. We don’t know if this is a bug or a voluntary behavior. For each drive that passes the test, a new encryption thread is spawned (the thread argument is a small structure that contains a copy of the public key and a pointer to a string with the drive name).
The main thread waits until all the encryption threads finish, then writes the three files that contains the decryption instructions in two locations: the startup folder of the Start Menu, and the desktop of the victim user.
Finally an end announcement network packet (type 7, sub-id 2, 1) is built and sent to the C2 server; the configuration file is deleted and the process is terminated using ZwTerminateProcess native API.
The encryption thread performs two main tasks: first it calls “DoFilesEncryption” routine to encrypt all the files that belongs to a volume and finally it writes “HELP_YOUR_FILES.PNG” wallpaper in the root path.
The “DoFilesEncryption” routine cycles between each folder and files of the target drive.
For each encountered sub-folder, it checks its name, filtering it by CRC32 (in this way some standard folders like “windows”, “system32”, “temp” will be ignored) and checks if the “HELP_YOUR_FILES.PNG” file exists, and if not, it calls itself again, specifying the new folder path as argument.
Each found file name is filtered two times: by extension and by name. If the filtering routines report that the name is good, the “EncryptFile” routine will be called.
“EncryptFile”, as the name implies, is the routine that actually encrypts the target file: the original file is opened and its attributes queried. The “IsFileAlreadyEncrypted” function verifies the target file has been already encrypted by reading the first 16 bytes and comparing them with the MD5 hash of the public key.
// Generate a random value DWORD GenerateRandValue(int min, int max) { if (min == max) return max; // Get the random value DWORD dwRandValue = RtlRandomEx(&g_qwStartTime.LowPart); DWORD dwDelta = max - min + 1; dwRandValue = (dwRandValue % dwDelta) + min; return dwRandValue; } // Generate a Random unicode string LPWSTR GenerateRandomUString(int minSize, int maxSize) { DWORD dwStringSize = 0; // Generated string size DWORD dwNumOfDigits = 0; // Number of number letters inside the string LPWSTR lpRandString = NULL; // Random unicode string // Generate the string size, and alloc buffer dwStringSize = GenerateRandValue(minSize, maxSize); lpRandString = new TCHAR[dwStringSize+1]; for (int i = 0; i < (int)dwStringSize; i++) { DWORD dwLetter = 0; // Generated letter dwLetter = GenerateRandValue(0, 1000); dwLetter = (dwLetter % 26) + (DWORD)'a'; lpRandString[i] = (TCHAR)dwLetter; } // NULL-terminate the string lpRandString[dwStringSize] = 0; // Now insert the digits inside the string DWORD dwUpperHalf = GenerateRandValue(dwStringSize / 2, dwStringSize); dwNumOfDigits = GenerateRandValue(1, dwUpperHalf); for (int i = 0; i < (int)dwNumOfDigits; i++) { DWORD dwValue = 0, dwPos = 0; // Generated value and position dwValue = GenerateRandValue(0, 9) + (DWORD)'0'; dwPos = GenerateRandValue(0, dwStringSize-1); lpRandString[dwPos] = (TCHAR)dwValue; } return lpRandString; } // Generate a random file name starting from a file full path BOOLEAN GenerateRandomFileName(LPWSTR lpFileFullPath, LPWSTR * lppNewFileFullPath, LPWSTR * lppOrgFileName) { LPWSTR lpRandFileName = NULL; // New random file name (without extension) LPWSTR lpRandExt = NULL; // New random file extension LPWSTR lpNewFileName = NULL; // The new file full name DWORD dwSize = 0; // size of the new filename // Check the arguments if (!lpFileFullPath || !lppNewFileFullPath || !lppOrgFileName) return FALSE; // Generate the new file name (without extension) lpRandFileName = GenerateRandomUString(5, 10); // Generate the random file extension lpRandExt = GenerateRandomUString(2,5); // Combine the new file name and extension and generate the final new file path // .... dwSize = wcslen(lpRandFileName) + wcslen(lpRandExt) + 1; lpNewFileName = new TCHAR[dwSize+1]; swprintf_s(lpNewFileName, dwSize+1, L"%s.%s", lpRandFileName, lpRandExt); // .... }
The new file is created, a new AES-CBC 256 key is generated using CryptGenKey and CryptExportKeyWindows Crypto APIs. This 32-byte key will be used to encrypt the entire file.
At this point CryptoWall 4 does a smart thing: it encrypts the generated AES key using the RSA-2048 public key (256 bytes in size) received from the C&C (using CryptEncrypt API). This will produce an encrypted 256-bit stream decryptable only by the bad guys.
The MD5 hash of the public RSA-2048 key is written in the first 16 bytes of the encrypted file; then CryptoWall 4 writes the 256-bit encrypted stream. The original file attributes and size are written to the next eight bytes. The original file name is encrypted using the generated AES key and written with its size inside the new file.
At this point the real file content encryption takes place, the original file is read in blocks that are 512 KByte chunks. Each block is encrypted with the generated key, using an AES-CBC 256 algorithm, and written directly to the new file (together with the block size in the first four bytes).
Once completed all the CryptoWall 4 resources are released and the original file is now deleted in an interesting manner:
// Move the new encrypted file name in the old original position, replacing the old one bRetVal = MoveFileEx(newEncFileName, lpOrgFileName, MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING); if (!bRetVal) // Delete the old file in the standard manner: DeleteFile(lpOrgFileName); else { // Rename the original replaced file in the new random file name bRetVal = MoveFileEx(lpOrgFileName, newEncFileName, MOVEFILE_REPLACE_EXISTING); }
In this analysis we have put CryptoWall 4 under the microscope. The dropper doesn’t bring anything terribly innovative, but it still has some clever features. The weak point in the infection process is that it deeply relies on the C2 server communication. If a firewall or IPS is able to detect and block its communication packets, the infection will not be able to operate correctly because it doesn’t have any public key needed to properly encrypt the victim files. However, once CryptoWall 4 has encrypted the victim’s files, there is no known way to recover the private key and decrypt them without paying the ransom as the RSA private key is never managed by the victim’s workstation. The private key resides only on the adversaries’ infrastructure.
As our analysis shows, the adversaries behind CryptoWall have continued to innovate and evolve to ensure it remains effective against users. Addressing the overall threat that ransomware presents requires organizations to be aware that adversaries will continue to evolve. Utilizing a multi-layered defensive approach will help organizations be able to detect and protect against threats like CryptoWall. Talos will continue to monitor CryptoWall as it evolves to identify better detection methods and build better defenses to protect our customers. We strongly encourage users and organizations to follow recommended security practices, such as installing security patches as they become available, exercising caution when receiving messages from unknown third-parties, and ensuring a robust backup solution is in place. These practices will help reduce the threat of a compromise and should aid in the recovery of any such attack.
PROTECTING USERS
Advanced Malware Protection (AMP) is ideally suited to prevent the execution of the malware used by these threat actors.