In a recent international operation, law enforcement agencies from the US and EU have taken down the QakBot botnet (see Press Release by U.S. Department of Justice, or in German, Press Release by Bundeskriminalamt).
QakBot is a notorious malware that was primarily distributed via malicious emails. Its main purpose was to gain initial access to a network. Once a foothold had been established and the victim looked like a promising target, the botnet operators will provide (or more likely, sell) the access to a ransomware group. The ransomware group will try to expand their reach in the victim’s network and sooner or later deploy a ransomware payload in order to extort money from the victim.
Other functionality included a plugin system that could be used to expand the malware’s capabilities – e.g., an Outlook stealer that exfiltrates emails and address books in order to identify new targets for email spam or to make the emails look more convincing. Furthermore, there was a worm plugin that automatically enumerated the network and tried to access other machines using weak credentials and tried to spread the infection there using a combination of SMB (Server Message Block, aka “Windows filesharing”) and Service Control Manager access via RPC (Remote Procedure Call).
G DATA Advanced Analytics has been tracking the QakBot botnet so that we receive new bot versions and plugins as early as possible. Late on August 25th, the C2 servers started distributing a payload using command type 42, which executes a piece of x86 shellcode in the context of the malware process. The shellcode consists of two parts: a ~2.5K dynamic library mapper, followed by the library to be loaded (~11K). The library is encrypted using a XOR scheme involving a 128-bit key and the current buffer offset, which is subtracted after the XOR operation. After decrypting the DLL, we obtain a well-formed PE compiled on August 16th using Visual Studio 2019. The following screenshot shows the pseudocode for the decryption:
As can already be guessed from the file size, the DLL contains very few functions. As it turns out, it implements the bare minimum of functionality required to stop an active instance of QakBot on a system. The following screenshot shows a list of user-defined functions in the DLL (whereas everything beginning from
__security_check_cookie belongs to the C runtime):
QakBot uses the Mersenne Twister pseudo-random number generator (also called MTRand) in order to generate various identifiers that it will use on the system. This applies to a multitude of different objects, including mutexes, registry key names, file names and pipe names. The generator is seeded with a CRC32 checksum derived from the computer name, volume serial number of the C: partition, and username. This allows the malware to consistently find its resources across process boundaries and reboots, as long as they execute under the same user. As a consequence, there is also no definite path where QakBot stores itself for persistence that would be valid for all infected systems, since both the folder name (under
%APPDATA%) and file name are generated using the described mechanism.
The uninstall library constructs the name for a named pipe that the main QakBot core polls. It connects to the pipe and simply sends a command that tells QakBot to terminate itself. The exact details of how this looks, including info from a QakBot build with debug logging, can be found in a blog post by SecureWorks.
One might wonder how it is possible that this cleans the infection in a way that it won’t simply reassert itself after the next system boot. This is because QakBot removes both its Run key from the registry and file on disk upon startup in order to make the infection harder to detect. The termination procedure called via pipe does not restore this persistence, since it was probably meant for bot updates where a newer instance of QakBot has spun up and is asking the old instance to quit.
Upon closer inspection, we see two minor problems with the payload where it runs into edge cases:
- It is linked dynamically rather than statically, meaning it depends on the Visual C++ 2015-2019 x86 Runtime being installed on the system. Especially on older Windows 7/8/8.1 systems that perhaps primarily use older software, it’s possible this runtime has not been installed by the user (or by applications they use). As a consequence, the uninstall payload will crash since it cannot successfully resolve its dependencies.
- The command type 42 that is used to deploy the shellcode is a relatively recent addition to QakBot. It first appeared in November 2022. Older versions do not understand this command – they return an error code (-2) to the server. In tests we ran, the server ignores this response and keeps sending the same unsupported command over and over. Admittely, it’s questionable whether old infections (e.g., because an infected system or VM has been offline for a prolonged period) can even reach the C2 infrastructure due to old server lists. Another possible scenario would be that the malware failed to properly update itself to a newer binary version for whatever reason, but is still in contact with the servers.
Since most people are on Windows 10/11 nowadays, in most cases this should work fine and practically remove the QakBot infection from the system. And even if the bot lingers on older systems, it is relatively harmless because it either cannot find a working server, or the server is under control of law enforcement and thus shouldn’t send any commands that cause further harm.
SHA256 of the full shellcode:
SHA256 of the decrypted library:
Article Link: QakBot Takedown Payload Analysis – cyber.wtf