Zscaler Blog
Get the latest Zscaler blog updates in your inbox
SubscribeTechnical Analysis of Pikabot
Key Takeaways
- Pikabot is a new malware trojan that emerged in early 2023 that consists of two components: a loader and a core module.
- The core module implements the malicious functionality that includes the ability to execute arbitrary commands and inject payloads that are provided by a command-and-control server.
- Pikabot utilizes a code injector to decrypt and inject the core module.
- The core module and its injector use a series of anti-analysis techniques. In addition, they use the public tool ADVobfuscator for string obfuscation.
- Pikabot shares similarities with the Qakbot trojan including the distribution methods, campaigns, and malware behaviors.
Pikabot is a malicious backdoor that has been active since early 2023. The malware is modular with a loader and a core component that implements the majority of the functionality. Pikabot is capable of receiving commands from a command-and-control server such as the injection of arbitrary shellcode, DLLs or executable files. Zscaler Threatlabz has observed Pikabot being used to distribute Cobalt Strike.
The Pikabot malware author has added a number of anti-analysis techniques to thwart automated analysis in sandbox and research environments. The code checks for the presence of debuggers, breakpoints, and system information including memory and the number of processors. Pikabot also uses the ADVobfuscator library to encrypt important strings used by the malware.
Threatlabz has noticed some resemblances between Pikabot and Qakbot including the method of distribution, behavior, and internal campaign identifiers. However, there is not sufficient evidence at this time to definitively link these malware families to the same threat actor.
Technical Analysis
In the following sections, we focus on Pikabot’s core module and its injector since the downloader does not contain any functionality/features worth mentioning.
Core Module Injector
Pikabot uses an injector to run a series of anti-analysis tests and then decrypt and inject the core module payload. If any of these tests fail, Pikabot will terminate execution. ThreatLabz has identified the following anti-analysis methods implemented by the injector:
- Exception Handlers by using int 2d and int 3 instructions to raise them.
- Reading the BeingDebugged flag of the process environment block (PEB).
- Use of the Windows API function Beep to delay the execution.
- Attempt to load junk and incorrect libraries in order to detect sandboxes.
- Use of the Windows API functions CheckRemoteDebuggerPresent and IsDebuggerPresent for debugger detection.
- The value of the NtGlobalFlag in the PEB that indicates a debugger is present.
- Use of the Windows API function NtQueryInformationProcess with the classes ProcessDebugPort and ProcessDebugFlags.
- Use of the GetWriteWatch API. The implementation seems to have been copied from here: https://github.com/BaumFX/cpp-anti-debug/blob/master/anti_debug.cpp#L260
- Use of the OutputDebugString function in order to detect a debugger. The implementation has been copied from here: https://github.com/BaumFX/cpp-anti-debug/blob/master/anti_debug.cpp#L456
- Check the number of processors, which should be greater than or equal to 2.
- Use of the rdtsc instruction to check for single stepping during debugging.
- The system random access memory (RAM) must be greater than 2GB.
- Detection of hardware breakpoints.
- Detection by checking the trap flag via __readeflags.
ANALYST NOTE: It should be noted that the use of exceptions is used in many parts of the code, for example, during the decryption of the core payload.
The injector decrypts the core module as follows:
- Loads a set of PNG images, which are stored in the resources section (RCDATA), and decrypts them using a bitwise XOR operation with a hardcoded 32-byte key. Note that each PNG image holds an encrypted chunk of the core module.
- Decrypt the XOR decrypted data using AES (CBC mode) with the same 32-byte key and use the first 16 bytes of the encrypted data as an initialization vector (IV).
Once the core payload has been decrypted, the Pikabot injector creates a process with a specified file path (e.g. WerFault) and injects the core module into it. Finally, the Pikabot injector sets the PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON flag in order to protect the injected process from non-signed Microsoft binaries.
Core Module
In the following sections, the core module is analyzed with samples compiled in May 2023.
Anti-Analysis
Similar to the injector, the Pikabot core module performs additional anti-analysis checks. One notable technique is a “sleep” function, which Pikabot uses to delay execution. Instead of using common Windows API functions, Pikabot uses the NtContinue API function in order to set a timer. The technique is not new and it is similar to other proof-of-concepts implementations.
In addition to the tests above, Pikabot stops execution if the system's language is any of the following:
- Georgian (Georgia)
- Kazakh (Kazakhstan)
- Uzbek (Cyrillic)
- Tajik (Tajikistan)
- Russian (Russia)
- Ukrainian (Ukraine)
- Belarusian (Belarus)
- Slovenian (Slovenia)
This check is common for many threat actors that originate from countries in the Commonwealth of Independent States (CIS) to reduce the chances of criminal prosecution.
Persistence
Pikabot uses two methods to add persistence on a host:
- Upon execution, Pikabot retrieves its current execution folder and checks if it is located in the AppData folder under a hardcoded folder name (might differ from sample to sample).
If Pikabot is not run from this specific file path, then it will add persistence on the compromised host by creating a new value with its file path in the Run registry key (the key name is hardcoded in the binary). On top of that, Pikabot corrupts the current executable file by replacing it with its PE header (512 bytes length) followed by null bytes (3,584 bytes in length).
- Pikabot downloads a PowerShell script from the command-and-control server and stores it in HKEY_CURRENT_USER\Software\predefined_name, where predefined_name is a hardcoded string in the binary file. Additionally, it stores the encrypted command-and-control servers in the same registry path.
Lastly, Pikabot sets a value in the Run registry key to execute a command line that invokes this PowerShell script (e.g., cmd /q /c start /min " powershell "$cimeter = Get-ItemProperty -Path HKCU:\Software\cimeter; powershell -encodedcommand $cimeter.unbevelledHamuli")
ANALYST NOTE: Pikabot also has the option to directly execute a downloaded file instead of using this persistence mechanism (Even though this is not currently being used).
Command-and-Control Configuration
Pikabot does not store the command-and-control information in a single block (e.g. as Qakbot does). Instead, each component (e.g. URIs) is encrypted using ADVobfuscator and the command-and-control server IP addresses and ports are further decrypted during runtime using the following algorithm. Firstly, Pikabot decrypts a string that includes a set of Base64 encoded strings. Then it parses the string using the delimiter '&' and decrypts the contents by following the below steps:
- Read the first 32 bytes of the string and use them as an AES key.
- Decode the rest of the string using Base64.
- Read the first 16 bytes of the decoded string and use them as an IV.
- Read the rest of the decoded data and decrypt it using AES (CBC mode).
- The decrypted output is a Base64 string, which results in the command-and-control server IP address and corresponding port. Note that many of the Pikabot command-and-control servers listen on ports that are identical to the ports used by Qakbot’s proxy module such as 1194, 2078, and 2222.
There have been some minor changes over the last few months in the way that Pikabot command-and-control servers have been stored. For example, in previous versions, the command-and-control servers were only encoded using Base64 and no further encryption or parsing was required.
Pikabot also appears to contain a campaign ID and binary version in each sample. These can be observed during the network communication, where the JSON data has the keys "version" and "stream". The latter appears to be a campaign ID. An example request (before encryption) containing these values is shown below:
{"uuid": "F37670100000074E33652510483", "stream": "BB1@T@2e88e610b66b4205853b211f21873208", "os_version": "Win 10.0 19050", "product_number": 161, "username": "test", "pc_name": "DESKTOP-TEST", "cpu_name": "11th Gen Intel(R) Core(TM)", "pc_uptime": 29884462, "gpu_name": "GPU_NAME", "ram_amount": 8096, "screen_resolution": "1560x1440", "version": "0.5.3", "domain_name": "", "domain_controller_name": "unknown", "domain_controller_address": "unknown", "knock_timeout": 254, "is_elevated": 0}
The campaign ID values observed by Threatlabz are particularly interesting because of the prefixes BB1 and eu_bb_0. These resemble some of the campaign IDs that have been observed in Qakbot binaries, which frequently contain the prefix BB followed by an integer.
Network communication
Pikabot starts by registering the compromised host with the command-and-control servers. The registration process involves collecting system information and reporting it to the command-and-control server with an HTTPS POST request. A variety of data is collected such as the following:
- Network information by executing the command ipconfig.exe /all
- User/groups information by executing whoami.exe /all
- Windows build information.
- Generic host information (e.g. available RAM, screen resolution)
- Domain controllers information.
Similar to other botnets, Pikabot generates a unique bot identifier for the compromised host. The algorithm, which Pikabot uses to generate the bot identifier can be replicated in Python using the code here.
Once the registration procedure has been completed and persistence to the compromised host has been established, Pikabot starts requesting tasks from the server. Pikabot supports the following command types:
- task - a command to execute
- knock - a keep-alive message
The tasks that Pikabot currently supports are described in Table 1.
Task Name | Description |
cmd | Executes a shell command via cmd.exe. |
destroy | Exits the current process. |
shellcode | Injects and executes downloaded shellcode. |
dll | Injects a downloaded DLL file. |
exe | Injects a downloaded EXE file. |
additional | Collects additional host information by executing one of the commands in Table 2. |
knock_timeout | Updates the timer value, which indicates how often Pikabot should send a knock request. |
Table 1 - Pikabot tasks description
Pikabot also supports the “additional” commands shown in Table 2, which are focused on collecting further system information.
Command | Description |
screenshoot | Not implemented. |
whoami | Executes the shell command whoami /all. |
ipconfig | Executes the shell command ipconfig /all. |
processes | Collects process information. |
Table 2 - Additional Pikabot commands description
It is worth noting that depending on the network request, Pikabot uses a different URI (which may differ among samples). For example, for reporting a command output, the URI may be Duenna/ZuGAYDS3Y2BeS2vW7vm?AnacrusisCrotalinae=zH4Tfz.
The network data encryption procedure is similar to the configuration's decryption process. Pikabot encrypts a network request by following the steps below:
- The request data is encoded using Base64.
- Pikabot generates a random 32-byte key and encodes the data again using Base64.
- Pikabot reads the first 16-bytes of a function prologue and uses these bytes as an IV.
- The data is encrypted using AES (CBC mode) and encoded with Base64.
- The 32-byte key is prepended to the encoded data.
- The hardcoded URI key (e.g. mMG50=) is prepended to the final output.
Cloud Sandbox
In addition to sandbox detections, Zscaler’s multilayered cloud security platform detects indicators related to Pikabot at various levels with the following threat names:
Conclusion
Overall, Pikabot is a new malware family that implements an extensive set of anti-analysis techniques and offers common backdoor capabilities to load shellcode and execute arbitrary second-stage binaries. Pikabot may have potential ties to Qakbot with some commonalities in the distribution, design, and campaign identifiers. However, ThreatLabz has not established a definitive link yet between the two malware families.
Indicators Of Compromise (IOCs)
Host Indicators
SHA256 Hash |
Description |
92153e88db63016334625514802d0d1019363989d7b3f6863947ce0e490c1006 |
Pikabot Injector/Core module |
a48c39cc45efea110a7c8edadcb6719f5d1ebbeebb570b345f47172d393c0821 |
Pikabot Injector/Core module |
8ee9141074b48784c89aa5d3cd4010fcf4e6d467b618c8719970f78fcc24a365 |
Pikabot Injector/Core module |
a9db5aca01499f6ce404db22fb4ba3e4e0dc4b94a41c805c520bd39262df1ddc |
Pikabot Injector/Core module |
347e2f0d8332dd2d9294d06544c051a302a2436da453b2ccfa2d7829e3a79944 |
Pikabot Injector/Core module |
Network Indicators
IOC |
Description |
hxxps://129.153[.]135.83:2078 |
Command-and-Control server |
hxxps://132.148.79[.]222:2222 |
Command-and-Control server |
hxxps://45.154.24[.]57:2078 |
Command-and-Control server |
hxxps://45.85.235[.]39:2078 |
Command-and-Control server |
hxxps://94.199.173[.]6:2222 |
Command-and-Control server |
Was this post useful?
Get the latest Zscaler blog updates in your inbox
By submitting the form, you are agreeing to our privacy policy.