Curly COMrades: Evasion and Persistence via Hidden Hyper-V Virtual Machines
Bitdefender first documented the Curly COMrades threat actor, operating to support Russian interests in geopolitical hotbeds, in August 2025. Since that initial discovery, subsequent forensics and incident response efforts have revealed critical new tools and techniques. Valuable support was provided by the Georgian CERT, whose collaboration significantly advanced the investigation. It alerted us to a […]
Posted: Wednesday, Nov 05

i 3 Table of Contents

Curly COMrades: Evasion and Persistence via Hidden Hyper-V Virtual Machines

Bitdefender first documented the Curly COMrades threat actor, operating to support Russian interests in geopolitical hotbeds, in August 2025. Since that initial discovery, subsequent forensics and incident response efforts have revealed critical new tools and techniques. Valuable support was provided by the Georgian CERT, whose collaboration significantly advanced the investigation. It alerted us to a detected sample communicating with a compromised site we were monitoring, enabling a joint analysis. The Georgian CERT was then instrumental in evidence acquisition and conducting a forensic analysis of the compromised site itself, which the attackers leveraged as a proxy to their actual infrastructure.

The most notable finding in this campaign is the exploitation of legitimate virtualisation technologies, demonstrating how threat actors are innovating to bypass standard EDR solutions as they become commodity tools. The attackers enabled the Hyper-V role on selected victim systems to deploy a minimalistic, Alpine Linux-based virtual machine. This hidden environment, with its lightweight footprint (only 120MB disk space and 256MB memory), hosted their custom reverse shell, CurlyShell, and a reverse proxy, CurlCat. By isolating the malware and its execution environment within a VM, the attackers effectively bypassed many traditional host-based EDR detections. EDR needs to be complemented by host-based network inspection to detect C2 traffic escaping the VM, and proactive hardening tools to restrict the initial abuse of native system binaries. (Bitdefender examples: This functional requirement is met by integrating capabilities like Network Attack Defence (NAD) and Proactive Hardening and Attack Surface Reduction (PHASR).)

The threat actor demonstrated a clear determination to maintain a reverse proxy capability, repeatedly introducing new tooling into the environment. Artifacts identified included a wide array of proxy and tunnelling samples, such as Resocks, Rsockstun, Ligolo-ng, CCProxy, TStunnel, and SSH-based methods. This flexible and layered approach was critical for sustaining access.

During investigation it was also uncovered a PowerShell script designed for remote command execution that abused Kerberos tickets, further expanding the adversary’s operational toolkit. In addition, multiple PowerShell scripts configured through Group Policy pointed to a deceptively simple but effective persistence mechanism tied to local account creation.

Hyper-V Evasion – Host-Isolated Operational Base

The most interesting finding is the abuse of native Windows virtualisation features to establish a covert, isolated operational base for the C2 implant directly on the victim host.  The threat actors enabled the Hyper-V feature on a compromised Windows machine, then downloaded and imported a lightweight Alpine Linux-based VM with their malware for persistent, low-visibility access to local network.

Virtual Machine Deployment

The operation began in early July, when two remote commands were executed on two computers to enable the microsoft-hyper-v virtualisation feature while disabling its management interface.

A few days later, the deployment phase followed. All commands were prefixed with ‘cmd.exe /C’ and all output was redirected (both standard output 1 and standard error 2) to a temporary file. A non-intrusive connectivity check for the next download – it uses an unusual redirection pattern when it echoes (prints on the screen) the curl.exe command and pipes it to a secondary cmd.exe process for execution.

Next, a dir command was run against c:Program Files – likely to verify the presence of required files such as rar.exe (executed from this location in the next step).

The virtual machine files (such as the VHDX and VMCX) are extracted into a deceptive folder. The Import-VM PowerShell cmdlet is then used to import the virtual machine. This cmdlet registers the pre-configured VM file (.vmcx) extracted in the previous step with the local Hyper-V manager.

Finally, using the Start-VM PowerShell cmdlet, this newly imported virtual machine is started. While the name WSL suggests the use of Windows Subsystem for Linux, it’s only a deceptive strategy. WSL is a feature that allows users to run a Linux environment natively within Windows, and because it is generally considered a benign developer tool, it often receives less scrutiny. It is critical to note that despite the naming convention, this VM is a fully isolated Hyper-V instance, entirely separate from and outside of the standard Windows Subsystem for Linux framework.

Virtual Machine Configuration

The deployed virtual machine was a custom-configured, victim-specific operational environment. Running the security-oriented, lightweight Alpine Linux, it occupied a mere 120MB of disk space and was configured to use only 256MB of memory. The primary goal of this minimalistic environment was to host the custom implants, CurlyShell and CurlCat, providing a dedicated, isolated base for the reverse shell and reverse proxy operations. Its minimal footprint and small size minimised the risk of detection, while providing all the tools that attackers needed.

The VM was configured to use the Default Switch network adaptor in Hyper-V. This setting routes the VM’s traffic through the host’s network stack using Hyper-V’s internal Network Address Translation (NAT) service. In effect, all malicious outbound communication appears to originate from the legitimate host machine’s IP address. Some of the included files demonstrate a high degree of tailoring for the compromised domain. Examination of the VM’s file system revealed an attacker-controlled domain-to-IP mapping within the /etc/hosts file and a specific private DNS server entry in /etc/resolv.conf, confirming that the VM was customised to communicate with the C2 infrastructure.

Virtual Machine Payload

The VM was not packed with large offensive frameworks or penetration testing tools; instead, it was a lightweight implant designed for a very specific purpose. The environment hosts only two closely related, custom malware families – CurlyShell (new malware) and CurlCat (previously documented by Bitdefender) – both built using the libcurl library but serving distinctly different operational roles. CurlyShell provides the persistent reverse shell, while CurlCat manages the traffic tunnelling, giving the threat actor robust access to the network and the ability to execute commands remotely. This minimalist approach avoids leaving a heavy forensic footprint.

CurlyShell is the core persistent reverse shell. For persistence, it’s using a simple but effective root-level persistence mechanism: a crontab entry running with root privileges. This cron task executes a script at 20 minutes past every fourth hour. The script then executes CurlyShell itself.

CurlyShell is responsible for establishing and maintaining the primary reverse shell connection using HTTPS for its communication, connecting to a specific, separate C2 infrastructure.

CurlCat is managing the SSH reverse proxy tunnel. It does not maintain system persistence itself; instead, it can be initiated by a command sent over the persistent CurlyShell channel when proxy access is needed. Its sole function is to wrap all outgoing SSH traffic into standard HTTP request payloads, making the traffic blend in on the wire. This capability is integrated directly into the SSH client configuration, where CurlCat is specified as the ProxyCommand to covertly tunnel all subsequent SSH connections through a SOCKS proxy listening on port 20155 on the attacker’s machine.

Authentication for this tunnel uses a dedicated key found in the /root/.ssh/ directory, logging in as the user ‘bob’ to the remote C2 infrastructure. This file is a private SSH key used to authenticate to the remote C2 server without needing a password.

CurlyShell Analysis

The two custom implants deployed within the Hyper-V environment, CurlyShell and CurlCat (read our previous analysis), share a largely identical code base. Both are compiled binaries written in C++ and built around the libcurl library.

The malware is packaged as an ELF binary, with its core functionality implemented in the main() function. At startup, file descriptors 0, 1, and 2 are closed (Standard Input (stdin), Standard Output (stdout), and Standard Error (stderr)). This action suppresses all output to the terminal and detaches the process from the initiating shell, running the CurlyShell invisibly as a headless background daemon.

The code then creates an instance of the custom C++ class, SesCustom.

The program’s custom session management begins with the construction of the SesCustom object. This starts with the explicit initialisation of a custom Base64 alphabet using a hardcoded 64-character string, which is then loaded into internal std::map structures. This custom character set is used by encoding and decoding methods perform a non-standard Base64 transformation to evade tools expecting the standard alphabet. Furthermore, the constructor immediately calls SesCustom::get_ses_id() to generate a unique, randomly Base64-encoded string to be used as a PHP session cookie in the C2 network traffic.

Once the SesCustom object is created, a key-value data structure (implemented in C++ as an std::map) containing the required HTTP headers is built and passed to the critical SesCustom::init() method along with the C2 URL. This header map includes the spoofed PHP session cookie, required for the C2 handshake mechanism.

The init() method then sets up the libcurl objects and configures the curl_write_callback. This is a standard feature of the libcurl library that points this callback to the malware’s own function. When the C2 server sends an encrypted data back, libcurl hands that raw data off to this custom-written WriteFunction() for processing.

After initialisation, a HTTP GET request is issued to verify C2 responsiveness. The returned data is expected to precisely match the PHP session cookie generated earlier. If the response fails to match this session cookie, the init() function returns false, causing CurlyShell to terminate immediately. If the server is responsive and returns the expected value, the function confirms that the target is a live C2, and the core C2 logic is launched via SesCustom::to_run(), implementing the reverse shell functionality.

Up to this stage, both CurlyShell and CurlCat share almost identical code, with their logic overlapping almost entirely. The key distinction lies in the to_run() method: in CurlyShell, the received data is interpreted as commands to execute, whereas in CurlCat it is forwarded directly to the SSH process.

The actual C2 communication and command execution happens in the to_run() method. The method manages data exchange by switching between HTTP methods: it uses HTTP POST requests to send command output back to the C2 when data is available, and falls back to HTTP GET requests to poll the server when there is no data to send.

The primary distinction between the two implants lies in how they process the server’s response. CurlyShell, being the reverse shell, executes incoming commands using the SesCustom::to_pipe() function, which internally relies on the popen() system call. The received command is wrapped with timeout 30 sh -c ‘<command>’ 2>&1 to limit the execution time (30 seconds) and capture both standard output and error. CurlCat, in contrast, is designed only for data relay; it completely bypasses command execution and instead uses the SesCustom::to_out() and SesCustom::from_in() functions to simply relay raw data.

PowerShell Scripts

The investigation uncovered two distinct types of PowerShell scripts linked to the attackers. One was designed to inject a Kerberos ticket into LSASS, enabling authentication to remote systems and execution of commands. The other was deployed via Group Policy to create a local account across domain-joined machines likely to achieve persistence.

Kerberos Ticket Injector

The threat actor’s customised tooling is nicely illustrated by a script dropped at c:programdatakb_upd.ps1 and executed remotely via PowerShell (often using atexec). This script is a two-part template for remote command execution. The first part, which handles loading and injecting a Kerberos ticket into LSASS, is almost identical to the public TicketInjector utility. But while the C# string assigned to the $ptt variable is stored in plaintext in the original version, it’s encrypted and stored as a SecureString in this version with a hardcoded key:

Once decrypted, the embedded C# code is compiled and loaded into memory by the Load() function, which serves the same purpose as the original TicketInjector utility’s entry point. This compiled C# code is responsible for the actual low-level manipulation of the Kerberos tickets within the LSASS process.

The second part of the PowerShell script defines two additional functions essential for post-exploitation:

  • Ticket Injection: One function invokes the Load() routine to read the Kerberos ticket and inject the modified version into LSASS.
  • Lateral Movement (RemoteWorker): The other key function, RemoteWorker(), executes lateral movement commands.

The RemoteWorker() function is designed as a template for executing post-exploitation tasks, using the newly injected Kerberos tickets to authenticate against remote systems via SMB. The following example illustrates this operation: it uses net use to connect to a remote share, runs reconnaissance commands to collect data about user profiles and system files, then deletes the connection, and immediately clears the current ticket cache using klist purge. The function’s flexible structure means the threat actor can easily substitute the commands for file deletion, malware deployment, or horizontal movement.

Local Account Persistence

During forensic analysis, a suspicious PowerShell script was discovered on multiple compromised systems. The script reset the password of the local account user, creating the account if it did not already exist – likely as a persistence mechanism.

This script was later replaced by a variant which instead targeted a local account called camera. Further analysis showed the script was distributed through Group Policy. The recurring password reset routine suggests an effort to counteract remediation attempts by ensuring continued access even if defenders change the account’s password.

At first, these scripts could not be directly linked to the attack. However, more recent activity involving an attempt to deploy a Resocks binary revealed that the c:Windowsps1 directory was actively used by this threat actor, which ties these scripts to the intrusion with medium confidence.

International Collaboration and C2 Analysis

The successful mapping and detailed analysis of the CurlCat communication channel were made possible through swift international cooperation with the Georgian National CERT (CERT.GOV.GE). This collaboration demonstrated the critical value of shared threat intelligence in dismantling sophisticated operations.

The initial connection was established when the Georgian CERT contacted our team regarding a detected CurlCat sample observed on a system it was monitoring, which was communicating with a compromised site we were also tracking. We provided them with an initial analysis of the malware’s communication protocol and identified the compromised Georgian website being used as an apparent Command and Control (C2) server.

The Georgian CERT successfully seized the compromised server and performed a detailed forensic analysis, sharing its findings to complete the picture of the attacker’s infrastructure.

The forensic analysis of the seized, compromised server (running via NGINX) provided following insights into how the attackers used the site to relay CurlCat traffic:

  • The attackers configured iptables rules to redirect traffic on port 443 from a specific victim to the attacker’s infrastructure at 88.198.91[.]116 on port 22. All other traffic remained unaffected.
  • The analysis confirmed the finding from the malware side: the CurlCat sample had been configured with libcurl options that disabled TLS certificate verification. This allowed the attackers to use arbitrary certificates on the compromised server to successfully decrypt the HTTP traffic and extract the encapsulated SSH communications.
  • In addition, the attackers manually started a sshd service on port 31637 with a customised configuration and deployed an application-level proxy service on port 443. This proxy implemented TLS and redirected tunnelling traffic to the hidden sshd service.
  • The attackers demonstrated a high level of operational security, leaving few traces on the compromised host. For example, they issued the unset HISTFILE command to prevent recording of their activity in shell history.

Conclusion and Recommendations

The investigation revealed that the attackers relied on a combination of custom malware and stealth techniques to establish and maintain persistence within the victim environment. Two custom malware families – CurlyShell and CurlCat – were at the centre of this activity, sharing a largely identical code base but diverging in how they handled received data: CurlyShell executed commands directly, while CurlCat funnelled traffic through SSH. These tools were deployed and operated in ways that ensured flexible control and adaptability.

A key aspect of the campaign was the abuse of virtualisation technologies. By enabling Hyper-V and running lightweight virtual machines, the attackers created isolated environments from which reverse shells, proxies, and custom malware could operate. This isolation protected the custom malware from behavioural analysis, EDR, and static signature scanning that would normally run on the host operating system. However, the resulting reverse shells and C2 traffic still had to exit the host machine via the network stack. This means that while the malware remained isolated, a security layer like Network Attack Defence (NAD) running on the host is still capable of intercepting and detecting the malicious communication patterns as the traffic passes through the host’s network interfaces. NAD includes algorithms for generic content identification, allowing it to recognise objects such as executables or URL addresses even for previously unknown or custom-built protocols.

Throughout the activity, the threat actor demonstrated a strong focus on stealth and operational security. Techniques included encrypting embedded payloads, abusing native PowerShell capabilities, and minimising forensic traces on compromised systems. To counter stealthy lateral movement, organisations must detect abnormal access to the LSASS process and suspicious Kerberos ticket creation or injection attempts, which occur outside the VM and are highly detectable. Use GravityZone EDR/XDR capabilities to detect malicious access to credential processes and mitigate memory-based attacks. For organisations operating with a lean security staff, adopting Managed Detection and Response (MDR) services offers an effective solution.

The sophistication demonstrated by Curly COMrades confirms a key trend: as EDR/XDR solutions become commodity tools, threat actors are getting better at bypassing them through tooling or techniques like VM isolation. To counter this, organisations must move beyond relying on a single security layer and implement defence-in-depth, multilayered security. It is critical to start designing the entire environment to be hostile to attackers. This means using solutions that restrict an adversary’s operational space, such as Proactive Hardening and Attack Surface Reduction (PHASR), which prevents the abuse of native system tools and forces attackers to take riskier, more detectable actions, thereby raising the operational cost of the attack and securing the environment at every layer.

Oisin O'Callaghan
Share This