Key Takeaways
- Proofpoint identified a new malware called ZenRAT being distributed via fake installation packages of the password manager Bitwarden.
- The malware is specifically targeting Windows users and will redirect people using other hosts to a benign webpage.
- At this time, it is unknown how the malware is being distributed.
- The malware is a modular remote access trojan (RAT) with information stealing capabilities.
Overview
Proofpoint Emerging Threats often receives tips from the community leading to the investigation and detection of novel malware. On 10 August 2023, Jérôme Segura, Senior Director of Threat Intelligence at Malwarebytes shared a malware sample that was being distributed as a part of a Windows software installation package. The sample was initially discovered on a website pretending to be associated with Bitwarden, bitwariden[.]com, a very convincing lookalike to the real bitwarden.com. Packaged with a standard Bitwarden installation package is a malicious .NET executable that we have dubbed “ZenRAT”.
At this time, it is unknown how the malware is being distributed, however historic activities that have masqueraded as fake software installers have been delivered via SEO Poisoning, adware bundles, or via email.
Figure 1: Fake Bitwarden website, bitwariden[.]com. bears a remarkable resemblance in theme with bitwarden.com. It is uncertain as to how traffic is being directed to this domain.
Specifically Targeting Windows Users
The malicious website only displays the fake Bitwarden download if a user accesses it via a Windows host. If a non-Windows user attempts to navigate to this domain, the page changes to something entirely different.
Figure 2: If a non-Windows user attempts to visit the malicious website, they are instead redirected to a cloned opensource.com article. This screen capture was taken using Mozilla Firefox on Ubuntu 22.04.
The website instead masquerades as the legitimate website “opensource.com”, going so far as to clone an article from Opensource.com by Scott Nesbitt, about the Bitwarden password manager. Additionally, if Windows users click download links marked for Linux or MacOS on the Downloads page, they are instead redirected to the legitimate Bitwarden site, vault.bitwarden.com. Clicking the Download button or the Desktop installer for Windows download button results in an attempt to download Bitwarden-Installer-version-2023-7-1.exe. This payload is hosted on the domain crazygameis[.]com, which as of this writing no longer appears to be hosting the payload:
Figure 3: When Windows users click either the Download button or the desktop installer for Windows option, a request is made to crazygameis[.]com to retrieve the malicious Bitwarden installer.
The domain registrar for both domains appears to be NiceNIC International Group, while the sites themselves appear to be hosted on Cloudflare.
Installer Details
The malicious installer, Bitwarden-Installer-version-2023-7-1.exe appears to have been first reported on VirusTotal on 28 July 2023, under a different name CertificateUpdate-version1-102-90.
Figure 4: So far, the installer sample has been seen twice in relatively close proximity under two entirely different names.
Looking at the details of the installer, we can see that the digital signature is not valid, but more interestingly, the installer is claiming to be Piriform’s Speccy – a software application for gathering system specifications.
Figure 5: The file metadata for the malicious bitwarden installer claims that it is Speccy, an application that is used to gather information (specs) about the system on which the application is run.
Not only that, the installer claims that it is signed by Tim Kosse, an open-source software developer most well-known for the Filezilla FTP/SFTP software.
Figure 6: In addition to the questionable file properties, the installer has an invalid digital signature, and claims to have been signed by Tim Kosse, an open-source developer most well-known for the FileZilla FTP/SFTP software.
The installer file copies itself to C:\Users\[username]\Appdata\Local\Temp, and creates a hidden file, named .cmd in the same directory that launches a self-deletion loop for both itself, and the installer file.
Figure 7: A file named .cmd file gets dropped with the installer into AppData\Local\Temp, under the current user. This file runs a self-deletion loop that automatically removes itself and the installer as soon as the installer executable finishes running.
The installer places a copy of an executable, ApplicationRuntimeMonitor.exe into C:\Users\[username]\AppData\Roaming\Runtime Monitor\, and runs it.
ZenRAT Details
ZenRAT (ApplicationRuntimeMonitor.exe), unlike the installer file, features some interesting metadata claiming to be a completely different application. The file properties claim that it is created by Monitoring Legacy World Ltd:
Figure 8: File metadata for the dropped ZenRAT executable, claiming to yet another application.
Upon execution, it uses WMI queries and other system tools to gather information about the host:
-CPU Name
-GPU Name
-OS Version
-Installed RAM
-IP address and Gateway
-Installed Antivirus
-Installed Applications
ZenRAT was observed sending this information back to its command and control (C2) server along with stolen browser data/credentials in a zip file called Data.zip with the filenames InstalledApps.txt, and SysInfo.txt.
Figure 9: Upon execution, ZenRAT will gather system fingerprinting data and package it into a ZIP file for exfiltration to the C2 along with output from other modules, such as its browser information stealer. SysInfo.txt contains fingerprinting data about the infected host, while InstalledApps.txt contains a list of installed applications.
Command and Control
Upon initial execution, ZenRAT establishes communication with its C2 server. In this instance, the only active C2 server Proofpoint has observed is 185[.]186.72.14. The C2 protocol is unique.
Client-Side Communication
The Client initiates communication to the C2. Regardless of the command, and extra data transmitted, the first packet is always 73 bytes. Here is the packet structure for the client check-in:
Figure 10: General structure of ZenRAT client communications. While some command IDs may result in more transmitted data from the client, the first packet always totals 73 bytes. Additional data is not appended to this packet, but is sent as a separate packet in the same TCP stream.
Command ID – The first byte of the client packet is reserved for the command sent to the C2 server. Below is a table of observed client Command IDs:
Value |
Command |
0x01 |
Tasking Request |
0x02 |
Request Module |
0x05 |
Update |
0x06 |
Sending Module Results |
0x07 |
Change Module Status |
0x08 |
Send Activity Logs |
0x09 |
Ping |
0x0A |
Get Module Status |
Data Size – 8 bytes, beginning with the second byte in the client packet. The number of bytes to expect from the client. Including the Command ID and the Data Size value itself. For example, 0x49 in figure 10 denotes the client is sending 73 bytes in total.
Hardware ID – This value is a Sha-256 hash concatenation of the username of the current user, machine name, Windows version string and the milliseconds value from the timestamp of the Windows directory.
Bot ID – Immediately after the HWID is the 16-byte Bot ID, generated from a hard-coded GUID
Version – The next eight bytes are reserved for the implant version
Build – The final seven bytes are reserved for the build version of the implant
Server-Side Communication
The server-side communication is much simpler than the client. Like the client’s communication, the first packet the server sends back to the client is a fixed length – in this case, nine bytes in size, followed by additional packets in the stream necessary for certain responses back to the client. The packet structure for the server response is identical to the structure for the first nine bytes of the client-side communication – A one byte Response code, followed by eight bytes reserved from the amount of data being sent back to the infected host in total.
Figure 11: Packet Structure for C2 responses. The first packet is always a fixed size (nine bytes), and the structure for that packet is identical to the first nine bytes of the client packet.
Response ID – A one-byte field that denotes the response to the command the client sent to the server. Below is a table of observed Server Respond IDs:
Value |
Response |
0x00 |
Successful Acknowledgement |
0x04 |
No Tasking |
0x0A |
Client is Fully Updated |
Data Size – Eight-byte value defines the amount of data, including the Response ID and Data Size fields, the client should expect from the server.
Interesting Commands Observed
While ZenRAT has several observed Command IDs, here are some of the more interesting ones observed:
Send Logs
While great care seems to have been taken establishing a custom C2 protocol, ZenRAT is configured to send its logs to the C2 server in the clear. As mentioned above, the command ID for the client to send its logs is 0x08. The client will send its initial 73-byte packet, followed by a complete ASCII log of various tasks it has performed up until that point.
Figure 12: A screen capture of the send logs command. Useful for determining the purpose of the different Command IDs, sent to the C2 server in plaintext format.
The logs in Figure 12 indicate that prior to establishing communications with the C2 server, ZenRAT has a handful of system checks it performs:
- IsBlockedRegion: A geofencing check to ensure that the malware is not operating in any of these regions:
- ru-BY
- ru-KG
- ru-KZ
- ru-MD
- ru-RU
- ru-UA
- IsMutex: Ensures that ZenRAT can create a mutex for itself. This is to ensure there is only one copy of the malware operating on the system at a time.
- IsSmallDisk: A system check that ensures that the system disk the malware is running on is not less than 95GB in size and can be seen as an anti-sandboxing feature.
- IsDetectVM: An anti-virtualization check that checks the running processes against a blacklisted set of process names, associated with virtualization products:
- Vmtoolsd
- vboxservice
- Vmwareuser
- Vmwaretray
- VMware
- VMware Tools
- vmtoolsd
The text [ CONFIRMED ] means that a check was successful, while an unsuccessful check would result in [ ERROR ] showing up in the log instead. After passing the checks, the client sends a ping command ID to verify connectivity, then checks for updates to the client. Afterwards, in this instance, we see the client request tasking, in which the C2 server responds with a Task and Module number that it has for the client. Immediately after the client requests this module, verifies it against a SHA256 hash, and injects it into PID 2680 (in our analysis, this was the regasm.exe process), with an argument:
uZxIDqImAABkdGqXUbYcQqojy5S9DIKtioa0zReZTJK+MVGP4yuvtUIuq8JUGQM7z+3XyneLWjgDAAAAAAAAAAIAAAAAAAAABQAAAHIEAAAAAAAA
When decoded, the hexdump of this value becomes:
Figure 13: Structure of the base64 data argument observed in the client send logs command ID. Most of the values in this structure are identical to the values in the 73-byte client communication packet.
Most of the values in this data struct – Bot ID, Hardware ID, Version and Build are identical to the client communication packet structure, so let’s focus on what is different:
- IP Address – IP address of the C2 Server. As established earlier, this is 185[.]186.72.14
- Port Number – TCP port number to use when communicating with the C2 Server. In this case, the implant is using port 9890/TCP
- Module ID – Module number associated with the module the client is attempting to run (0x05)
- Task ID – Task ID assigned from the server to activate this module. Hex value (0x0472 == 1138)
Send Module Results
Client command ID 0x06 is used to transmit results from module. In a separate sample, ZenRAT was observed sending the results from Module 0x09, with a Task ID of 0x0829 back to the C2 server:
Figure 14: Structure of Data sent with the Module Results (0x06) Command ID
The data transferred in Figure 14 Is encrypted using AES-256-CBC, in chunks of 50000 bytes. To decrypt this data, it must be processed in chunks of 50016 (50000 bytes + 16 bytes of CBC padding) The 32-byte key is derived from the SHA256 Hash of the Task ID. For example, 0x2908000000000000 produces the SHA256 hash 799b9288579cac5dc19f6b7cb84636f07ea52ecfa151bc71f00e8b8dbf980869, While the 16-byte IV is the first 16 bytes of the Hardware ID (itself a SHA256 hash consisting of an amalgamation of system-specific data. This Hardware ID is identical to the Hardware ID in the Client-Side Communication section above). Trim off the 0x290800000000000000 (nine bytes in total – The eight-byte TaskID, plus 0x00) from the beginning of the next packet, use the Key and IV values above, and the result is the Data.zip file, containing the data the module has gathered from the system.
Figure 15: By using the SHA256 value of the Task ID, as the Key, and the first 16 bytes of the Hardware ID value as the IV, the data sent along with command ID 0x06 can be decrypted.
The existence of the Task and Module ID fields implies that ZenRAT is designed to be a modular, extendable implant. At this time, we have not observed other modules being used in the wild.
Conclusion
Malware is often delivered via files that masquerade as legitimate application installers. End users should be mindful of only downloading software directly from the trusted source, and always check the domains hosting software downloads against domains belonging to the official website. People should also be wary of ads in search engine results, since that seems to be a major driver of infections of this nature, especially within the last year.
Indicators of Compromise
IP Address |
Purpose |
185[.]186.72.14:9890 |
Observed ZenRAT C2 server |
185[.]156.72.8:9890 |
Observed nonresponsive ZenRAT C2 server |
Domain |
Purpose |
bitwariden[.]com |
Bitwarden look-alike domain |
crazygameis[.]com |
Payload delivery domain |
obsploject[.]com |
OBS Project look-alike domain (recently registered, no longer responsive) |
geogebraa[.]com |
GeoGebra look-alike domain (recently registered, no longer responsive) |
SHA256 |
Observed Filename |
e0c067fc8e10a662c42926f6cdadfa5c6b8c90d5dff3f0e9f381210180d47d37 |
Bitwarden-Installer-version-2023-7-1.exe |
d7d59f7db946c7e77fed4b927b48ab015e5f3ea8e858d330930e9f7ac1276536 |
ApplicationRuntimeMonitor.exe |
8378c6faf198f4182c55f85c494052a5288a6d7823de89914986b2352076bb12 |
Bitwarden-Installer-version-2023-7-1.exe |
f7573ad27ff407e84d3ebf173cbeaaa6aba62eb74b4b2b934bc0433df3d9e066 |
SearchModule.exe |
e318b2c1693bc771dfe9a66ee2cebcc2b426b01547bb0164d09d025467cb9ee3 |
CertificateUpdate.version2.10.12.exe |
60098db9f251bca8d40bf6b19e3defa1b81ff3bdc13876766988429a2e922a06 |
SystemSecurity.exe |
ba36d9d6e537a1c1ecdf1ace9f170a3a13c19e77f582a5cae5c928a341c1be8d |
2421c4cd791b1eexeexe.exe |
986aa8e20962b28971b3a5335ef46cf96c102fa828ae7486c2ac2137a0690b76 |
npp.8.4.8.Installer.exe |
Emerging Threats Rule Coverage
2037786 – ET INFO Pastebin-style Service (textbin.net in TLS SNI)
2047754 – ET MALWARE ZenRAT Ping Command
2047755 – ET MALWARE ZenRAT CnC OK Response
2047754 – ET MALWARE ZenRAT Ping Command
2047755 – ET MALWARE ZenRAT CnC OK Response
2047756 – ET MALWARE ZenRAT Get Status Command
2047757 – ET MALWARE ZenRAT Status Response
2047758 – ET MALWARE ZenRAT Change Status Command
2047759 – ET MALWARE ZenRAT Request Module Command
2047760 – ET MALWARE ZenRAT Request Module CnC Response
2047761 – ET MALWARE ZenRAT Update Command
2047762 – ET MALWARE ZenRAT Update CnC Response (Already Actual)
2047763 – ET MALWARE ZenRAT Tasking Command
2047764 – ET MALWARE ZenRAT Tasking CnC Response M1
2047765 – ET MALWARE ZenRAT Tasking CnC Response M2
Data Decryption script
The following is a decryption script for the data uploaded by the browser stealing module. This script was provided by our Reverse Engineering Team:
#! /usr/bin/env python3
# ZenRAT encrypts stolen browser data before uploading - but does it in 50000 byte chunks
import sys
import hashlib
# from Crypto.Cipher import AES
from Cryptodome.Cipher import AES
def unpad(s):
if s[-s[-1]:] == s[-1:0] * s[-1]:
return s[:-s[-1]]
else:
return s
data = sys.stdin.buffer.read()
h = hashlib.sha256()
h.update(data[9:41]) # HWID - itself the SHA256 of username + machine name + windows ver + msecs
iv = h.digest()[:16]
h = hashlib.sha256()
h.update(data[0x49:0x51]) # Task ID
key = h.digest()
out = b""
for p in range(0x52, len(data), 50016): # CBC adds 16 bytes (blocksize) to the length
aes = AES.new(key, AES.MODE_CBC, iv)
out += unpad(aes.decrypt(data[p:p + 50016]))
sys.stdout.buffer.write(out)
Acknowledgements
We would like to thank Jérôme Segura, Senior Director of Threat Intelligence at Malwarebytes for his discovery of and collaboration on this threat.