On June 14th, 2017, a new variant of ZXShell appears to have been uploaded from the Marmara region of Turkey. The Trojan itself is well known and contained x32 and x64 rootkits. This blog describes the functionality of ZXShell, as well as the associate rootkits. The Trojan source code is available here.
|File Name: 5d2a4cde9fa7c2fdbf39b2e2ffd23378d0c50701a3095d1e91e3cf922d7b0b16.dll
File Size: 950368 bytes
PE Time: 0x549A82E1 [Wed Dec 24 09:09:53 2014 UTC]
Name Entropy MD5
.text 6.62 163c64599d79322c596724b07b8b1c3e
.rdata 6.05 882510633f1de7ca620f954d9d938b2b
.data 7.32 a4d961e6ca1372e2db7394a9a9f313af
.zh0 6.65 18c2f27a8641da65a8936242bbce2ac7
.zh1 7.82 c7fd2160012526aa7708d5a3784cd929
.reloc 6.73 cebfde9dc81a4587832ef23054c66282
.rsrc 4.1 174d54af2191173b9759cd8a003f9194
With the malware analysis having been documented, as well as the source code being freely available, we can get to the fun part. Using a lab environment with RSA NetWitness® Packets and RSA NetWitness Endpoint installed, we allowed the malware to entrench and install the rootkit driver.
Figure 1 Malware Entrenchment
Figure 2 Rootkit Driver Filesystem and Network Hooks
The malware immediately resolved to domain api7.mcafee.01o[.]us – which resolves to 103.224.81[.]159 – and was first seen June 15th, 2017. There are about 40 other suspicious-looking domains in that IP. The TCP and UDP beaconing were typical of ZXShell, cycling between ports 25, 443, 80, 53 and 21.
Figure 3 ZXShell beaconing
Left to beacon overnight, we checked in the next morning and found that an actor had visited the site (as they had administrative control of the malware). Using the RSA NetWitness platform as a forensics tool, provides a clear record of what took place. The actor began with traditional reconnaissance of the machine their Trojan landed on: executing whoami, ipconfig, netstat and the ver command.
Figure 4 Simple Reconnaissance of Machine
For unknown reasons, the ZXShell main menu is transmitted in clear-text to the actor, which allows us to view them typing in commands for the Trojan.
Figure 5 Plaintext Command Listing for ZXShell
After dropping a compressed CAB archive and expanding it, the actor used ZXShell to create a named pipe running the uncompressed file, which was a password dumper. The pcap timestamps appear to be a few minutes off, but as this was a long TCP session the session start is registered in the time field.
Figure 6 Password Dumper
|File Name: makecab.cab.exe
File Size: 157184 bytes
PE Time: 0x548871BE [Wed Dec 10 16:15:58 2014 UTC]
Name Entropy MD5
.text 6.36 34e7ba8238c64368bc14977c5ade240c
.rdata 4.39 2791758f6832c0a01c87c19137fb5bf7
.data 2.18 3ff9e4160b1b6215060db85f84390778
.pdata 4.92 6a38e85b4d71fc06f1ccc221f54b3f50
.rsrc 5.18 6e4e0c4894943dff286673de86c60c8f
.reloc 3.52 8df2a0bc3d8d683ff3d07386e22650c7
Figure 7 Clear-Text Output from RSA NetWitness Packets
The actor moved on to verifying the rootkit was working properly (by looking for the TCP connection with the netstat piped through the find command), dropping and executing the same malware DLL with rundll32.exe. This was followed by executing the ShellMainThread named export.
Figure 8 Verification and Additional Malware
Apparently the actor had seen enough and decided we weren’t a target as the actor used the ZXShell Uninstall built-in command and, attempted to remove the Trojan. (We wonder what gave it away, the superhero username or the awful password [P@ssw0rd]?)
Figure 9 Attempt #1 to Uninstall ZXShell
The output from the malware console stated the removal was a success. Most malware control panels list machines actively connected to the command and control server (C2), much like RSA NetWitness Endpoint. This uninstall failed, so the console likely alerted the operator that this machine was still connected. The actor then spent 15 minutes repeatedly issuing the uninstall command. When that failed, they connected to the machine via the built-in RDP client of the Trojan. We can detect this behavior with both RSA NetWitness Packets and RSA NetWitness Endpoint. In RSA NetWitness Endpoint we see the process smss.exe, the session manager process, create winlogon.exe which then creates LogonUI.exe. This is the sequence we expect to see when any user logs onto a Windows operating system-based PC interactively. We can tell its RDP because svchost.exe creates rdpclip.exe, which handles the terminal services clipboard functionality. This is the process that synchronizes the clipboards of the local and remote session so a user can copy/paste text or files via a remote session. The actor then opens the task manager, explorer.exe will be the parent of any newly created applications, and even does a traceroute to google.com before leaving the machine alone for roughly an hour. The actor then attempts to manually delete the file, but is again stopped by their own rootkit.
Figure 10 #Fail
Figure 11 A Very Confused Threat Actor
Figure 12 RDP Tunneled Over HTTP
The actor made many attempts to uninstall the Trojan via the ZXShell menu many times while on my network, at one point dropping the same malware with a different name in an attempt to uninstall the original Trojan. Each time being defeated by the rootkit, which reroutes any request to the entrenched malware either to tcpip.sys or ntfs.sys, core Windows drivers for filesystem management and networking.
The term APT gets thrown around a lot, these days. Was this malware advanced? Yes and no, it’s certainly a full featured Remote Access Trojan (RAT), but given its high detection rate on VirusTotal and the plaintext communications it’s easy to detect. The rootkit loaded into memory hid the activities from applications running on the host, but RSA NetWitness Endpoint sits at the same layer, Ring 0. Unsigned kernel drivers are a rarity with modern Windows OS’, so when we find one it warrants investigation. The advanced aspect of this Trojan is exactly what would lead to its discovery with a good endpoint detection and response tool such as RSA NetWitness Endpoint. So, while this malware could be considered advanced, the actor behind the malware certainly was not.5