Threat Spotlight: WhisperGate Wiper Wreaks Havoc in Ukraine
With tensions continuing to rise in the region, it came as a surprise to absolutely no one when a malicious threat actor was discovered to be targeting Ukrainian government, non-profit, and IT organizations. Reports of WhisperGate, a multi-staged malicious wiper disguised as ransomware, spread quickly.
Where our previous post provided an overview of the threat as a whole, this article goes into more detail on the third and fourth stages of the malware. Specifically, we’ll focus on some unexpected and potentially haphazard choices the developers made to hinder reverse engineering and prevent static analysis tools from working as effectively as they could, in order to slow analysis and buy more time for the attackers to do their damage.
WhisperGate: Digging into Stages 3 and 4
As mentioned in our previous post, Stage three of WhisperGate is a heavily obfuscated C# binary, which is responsible for disabling antivirus software and launching the fourth and final stage payload. The DLL contains the following three embedded resources:
The first of these resources is an encoded .NET DLL containing the final fourth stage wiper payload. The second resource is used to control the code flow, and further obfuscate the intention of the DLL loader. During our analysis, we identified that in addition to being a 256-byte array, this resource was initialled as a custom stream object where “getter” functions had been overwritten with de-obfuscation functions.
The third resource initially appears to be unnamed; however, after analysis, it becomes clear that it uses Unicode characters to obfuscate itself, much like it does the rest of the binary.
The resource itself is used by the obfuscation tool Eazfuscator, as part of its string encoder. Each string is resolved using the getter function shown below, which will return the decoded string from a dictionary if it exists. If not, it will decode the string and then store it in that dictionary for later retrieval.
Figure 1 - Eazfuscator's string retrieval function
The stage three DLL loader will start off by making sure it has administrator privileges. If it does not, it will attempt to escalate itself by running the following command, which will trigger a User Account Control (UAC) dialog. This warning notifies the person using the targeted machine that the program is trying to make changes, which would need to be approved before the program could progress.
C:\Windows\System32\cmd.exe /K Start <filePath> & EXIT
If running as Administrator, it will drop and execute a VBScript named “Nmddfrqqrbyjeygggda.vbs” from the Temp directory. The script adds the targeted logical drive to the Windows Defenders list of exclusions, as can be seen below.
Powershell - CreateObject(""WScript.Shell"").Run ""powershell Set-MpPreference -ExclusionPath 'C:\'"", 0, False
The resource 78c855a088924e92a7f60d661c3d1845 contains a further encoded assembly. The decode function is unusual as it uses a combination of RC4 and a simple XOR loop, as shown below.
Figure 2 - Resource decoding function
The function first resolves the following base64 string through Eazfuscator.
Once base64-decoded, the resulting byte array is then passed to another custom encoding function which uses an 8-byte key to XOR decode the array. The key is resolved inside the “GetPemBaseLong” function, which uses TinyCrypt to decrypt the constant.
This function can be seen below.
Figure 3 - Custom array permutating function
The result of this function on the input array is shown below, and it is passed into the RC4 key initialization.
Figure 4 - Final byte array passed into RC4 function
Custom Encoding Loop
Instead of relying purely on RC4 to encrypt the resource, the developers decided to build in their own custom encoding loop. This loop uses a combination of their own 8-byte key, and for every 32 bytes of input, they use 1 byte of the RC4 pseudo-random generation algorithm. It’s possible that this was done to hinder reverse engineering by overcomplicating the decryption routine, or to prevent static analysis tools from identifying standard cryptographic functions.
As mentioned previously, the decoded assembly is dynamically loaded and contains two additional resources named “AdvancedRun” and “Waqybg”, both of which are GZip compressed. The DLL loader will first decompress the AdvancedRun resource and save the file into the Temp directory as an executable under the same name.
AdvanceRun.exe is a free tool available through Nirsoft, which allows programs to be run under different settings. In this case, two commands are executed through the command line interface and specifically use the “/RunAs 8” flag to execute the commands under the TrustedInstaller group.
The first command stops the Windows Defender service from using the service control tool, which is located in the System32 directory.
/EXEFilename ""C:\Windows\System32\sc.exe"" /WindowState 0 /CommandLine ""stop WinDefend"" /StartDirectory """" /RunAs 8 /Run
The second command uses PowerShell and the “rmdir” command to recursively delete all Windows Defender files.
/EXEFilename ""C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"" /WindowState 0 /CommandLine ""rmdir 'C:\ProgramData\Microsoft\Windows Defender' -Recurse"" /StartDirectory """" /RunAs 8 /Run
After removing Windows Defender, the DLL loader moves onto executing the final fourth stage payload. This is stored inside the “Waqybg” resource, which in addition to being GZip encoded, is also in reverse byte order.
The fourth stage payload is not written to disk; instead, the DLL loader copies a legitimate application named InstallUtill.exe into the Temp directory and starts a process in a suspended state. The malicious code is then injected into the legitimate process before being restarted.
Fourth Stage Wiper
As we mentioned in our previous blog, the fourth stage is designed to overwrite all files that match a hard-coded list of file extensions. At the core of this functionality is the destructive wiper function, which creates a 1MB buffer of 0xCC bytes that is then written to each file.
However, as each file is opened using the wfopen() function”wb” mode, its existing contents are discarded. This results in the targeted file being replaced with a 1MB file of 0xCC bytes. It’s not clear if this was the intended design of the malware developers or merely an oversight. Regardless, it still functions effectively to wipe the target file.
Figure 5 - Wiper function
The developers of the WhisperGate wiper malware have made some unusual and somewhat unexpected choices in their creation of this malware. They implemented their own cryptographic functions that were built on top of standard and proven libraries. They attempted to wipe files in a strange and seemingly slap-dash manner, which may or may not have been intentional.
Regardless of this – or maybe even because of it – the WhisperGate wiper malware still has a level of intricacy not typically seen among common criminals, which is made especially clear by the lengths the developers went to in order to obfuscate the fourth stage of their creation.
As we stated in our last blog, and given the escalating geopolitical events in Ukraine and its surrounding regions, BlackBerry strongly encourages organizations with an elevated risk profile to use the information in this blog to proactively defend against any malicious activity from this group.
Check out our latest demo video here, which shows BlackBerry going head-to-head with a live sample of WhisperGate wiper.