Skip to content

SERPENTINE#CLOUD returns: ClickFix lure drops five RATs

Kirk
16 min read
malwareclickfixbrute-ratelxwormpythoncloudflare
On this page

Matching GUIDs, encryption keys, infrastructure, and tool reuse tie this activity to the same operator behind SERPENTINE#CLOUD - five weeks after remediation. Same target organisation. Same five RAT families. New delivery chain.

The previous breach - covered across five posts starting with PureLogs - ran undetected for roughly six months before Huntress flagged it in February 2026. The attack vector was never confirmed. This time, it was ClickFix social engineering through ephemeral Cloudflare tunnels, and Huntress caught it at stage 0 before any payload executed.

The payload set is familiar: VenomRAT, AsyncRAT, XWorm/Violet (upgraded from v4.7 to v5), PureHVNC, and a new addition - Brute Ratel C4. BRc4 replaces the Annorii loader from the prior campaign. It does not operate its own C2. Instead, it decrypts and injects PureHVNC stage 2 into notepad.exe using Early Bird APC (asynchronous procedure call) queue injection with PPID (parent process ID) spoofing to explorer.exe.

Five families, four C2 endpoints. The BRc4 binary is an injection wrapper - direct syscalls and process mitigation policies that block non-Microsoft DLL injection into its target process.

All four C2 endpoints resolve to DuckDNS domains on two IPs in the same AT&T residential /24 in Chicago. The operator consolidated from three countries to a single subnet. Infrastructure pivoting attributed 13 DuckDNS domains to this operator across 12 historical IPs in six countries, with the earliest confirmed activity dating to July 2025.

If you operate a threat intelligence platform with API access and can provide a researcher account, please reach out to [email protected]. Additional data sources directly increase the quality and coverage of the threat intel published here.


What changed

The Python loader pipeline is the same. Same Kramer bytecode obfuscator (key: sparkle). Same Donut v0.9.2 x64 shellcode. Same Early Bird APC injection template. Same import base64, ctypes, sys, os header. Same embedded hex keys structure. The template has not changed in eight months.

What changed is the wrapper around it.

ComponentFebruary 2026March 2026
DeliveryUnknown (direct execution suspected)ClickFix WSH lure via Cloudflare tunnels
ObfuscationKramer on some loaders, plaintext on othersKramer on all 10 loaders
XWorm/Violetv4.7 (1.4 MB)v5 (71 KB - 95% smaller)
PureHVNC wrapperAnnorii loaderBrute Ratel C4 (PPID spoof, direct syscalls)
PureHVNC obfuscationConfuserExCustom XOR+AES + TLS cert pinning
C2 infrastructure3 IPs across Hungary, Netherlands, US2 IPs in same Chicago /24
DuckDNS domainsRotated per campaignRotated - but 902399hfjks persisted from prior campaign

The Violet install GUID (3d847c5c-4f5a-4918-9e07-a96cea49048d), separator (XSXSXSX), VenomRAT salt (DcRatByqwqdanchun), PureHVNC ProtoBuf architecture (86 message types), and Contacts-folder staging path all match the February campaign.


Kill chain

StageComponentAction
0Scan_0620954916911.pdf.wshrundll32 + davclnt.dll WebDAV fetch via CF tunnel #1
1UKMar30.wsfCopies 3 batch files from CF tunnel #2
2UKM301.batDownloads 2 ZIPs + persistence script from CF tunnel #3
3UKM302/303.batRuns all .py via embedded Python 3.12, hides dirs, self-deletes
410 Kramer .pyc payloadsAES+XOR or RC4 decrypt to Donut v0.9.2 x64 shellcode
5Donut shellcodeAMSI/WLDP bypass, CLR bootstrap, .NET assembly load
6Final payloadsVenomRAT, AsyncRAT, XWorm/Violet v5, PureHVNC, Brute Ratel C4

Huntress interrupted at stage 0. No payloads reached disk.

The kill chain was interrupted at stage 0. Huntress detected rundll32.exe loading davclnt.dll for a WebDAV fetch to the first Cloudflare tunnel at 13:56:47 UTC on March 31. The host was isolated within seconds. No payloads reached disk.


Delivery chain (stages 0-4)

Stage 0: WSH lure

Scan_0620954916911.pdf.wsh is a 127-byte Windows Script Host settings file with a .pdf.wsh double extension. It instructs rundll32.exe to load davclnt.dll for a WebDAV/SSL fetch from the first Cloudflare tunnel. The target path is /yop/ on edward-fwd-vacuum-changelog.trycloudflare.com, which was running WsgiDAV 4.3.0 with anonymous read-write access.

Stage 1: WSF loader

UKMar30.wsf is an 869-byte JScript file. It copies three batch files from the second tunnel (handed-mines-abc-intensity.trycloudflare.com, path /ku/) and executes them sequentially with 10-second sleeps between each.

Stage 2: Batch downloader

UKM301.bat relaunches itself hidden via a VBS helper, then uses curl to download two ZIP archives and a persistence batch file from the third tunnel (represents-causes-conflicts-silver.trycloudflare.com). The ZIPs extract to hidden directories under %USERPROFILE%\Contacts:

  • 1Mar23MA.zip (16.7 MB) -> MainRingtones
  • 1Mar23ST.zip (16.6 MB) -> str
  • 1Mar23SU.txt (2.7 KB) -> Startup persistence batch

Each ZIP contains Python 3.12 x64 (embedded runtime) and five Kramer-obfuscated .py payloads. The two sets are redundant - same families, different encryption keys.

Stage 3: Executor

UKM302.bat and UKM303.bat are identical. They execute all .py files via the embedded python.exe, hide the payload directories with attrib +h, kill parent processes via WMI VBS helpers, then delete themselves and the VBS files. All five RAT families launch simultaneously.

Stage 4: Persistence

1Mar23SU.txt is a batch file disguised with a .txt extension. It runs on boot from four paths including %APPDATA%\\Winic\\30.3.0rc50 (a 32-bit Python copy) and uses DiscordDial.vbs as a launch helper.


Kramer obfuscator

All 10 payload files are Python 3.12 bytecode (.pyc magic cb0d0d0a) with .py extensions. The Kramer class decodes source at runtime and passes it to eval().

The encoding converts source characters to CJK Unicode codepoints via a per-file offset, then hex-encodes the segments and joins them with / delimiters. Printable ASCII symbols and uppercase letters are shifted by +1. Newlines are encoded as Greek zeta (U+03B6).

Constants across all files: key = sparkle, alphabet = abcdefghijklmnopqrstuvwxyz0123456789. The CJK base offset varies per file (0x439E to 0xE03F0 - upper values fall outside standard CJK blocks into supplementary private-use ranges). Method names are randomised.

We decoded all 10 files natively using Python 3.12 with a hooked eval() call.


Python loader templates

Two templates across the 10 files:

Template 1: AES+XOR shellcode injector (8 files - Ann, Ass, Hvv, Vio x 2 sets)

Decryption: AES-256-CBC -> XOR with key2 -> XOR with key1. Each file has unique keys. Injection: CreateProcessA(explorer.exe, CREATE_SUSPENDED) -> VirtualAllocEx -> WriteProcessMemory -> QueueUserAPC -> ResumeThread. Early Bird APC queue injection into a suspended explorer.exe process.

Template 2: RC4 shellcode loader (2 files - 2Laz x 2 sets)

Decryption: RC4 with 8-byte ASCII key (qgCzmCuY for MA set, k5m6OUbU for ST set). Execution: VirtualProtect(PAGE_EXECUTE_READWRITE) -> CFUNCTYPE cast -> direct call. No process injection - runs shellcode in the Python process.

Both templates produce Donut v0.9.2 x64 shellcode. All six unique shellcode blobs (5 families, one shared between sets) use Chaskey-LTS encryption with the instance header at offset 0x5. The Donut loader bypasses AMSI (Antimalware Scan Interface) and WLDP (Windows Lockdown Policy), then bootstraps the CLR (Common Language Runtime) via CorBindToRuntime to load the .NET payload - or executes the native PE directly for BRc4.


Final payloads

FamilySHA256TypeSizeC2
VenomRAT v3.658d9f039ec38bbe03a1e1bf58a0102ce9c94d6efe39d2450cb44917d4a5c75af.NET PE3270,952y57kdsa.duckdns.org:7878
AsyncRAT 0.5.7B4bb4a303b8e4873401be1cea68d50bdaa454471685dc30ad61e9ef746181aa29.NET PE3252,520uejrhnfq.duckdns.org:6745
PureHVNC loaderf56a53ec6817c918d9a0056277022d694a06727bc9064bee95e4b80c50067f2a.NET PE32337,704-
PureHVNC stage 259079dbdfb0346deae4efc361d78844141bf77d916adec96b23d8061e20e123c.NET DLL788,480bsmaopm.duckdns.org:6757
XWorm/Violet v58cda591f526a09954c7a60337daa767be7948367ee52accebc30061be1dc581a.NET PE3271,464vivogrouplink.duckdns.org:2128
Brute Ratel C4026f71d40fa2e3c530283c1a70925d14eeee18d98f95506dd88cb698ccca6859PE32+ x64621,864shares PureHVNC C2

VenomRAT v3.6

VenomRAT v3.6 is a dcRAT/qwqdanchun fork. AES with passphrase EqobtaJh1ra1l2Px0fjvG8Ircxdf2e2P, salt DcRatByqwqdanchun (PBKDF2, 50,000 rounds). Certificate CN: EBOLA. AMSI and ETW bypass via memory patching. Plugin-based architecture. Install flag set to false - no persistence deployed. The process kill list targets ProcessHacker, Taskmgr, Regedit, and several Windows Defender components.

AsyncRAT 0.5.7B

AsyncRAT 0.5.7B is a lighter build of the same codebase. AES with passphrase Ff6VygGEmXLxZ17uU1fqBwyv7Not5Jtw. Mutex: AsyncMutex_6SI8OkPnk. Plugin-based, install flag false. No AMSI/ETW bypass, no process kill list. Both VenomRAT and AsyncRAT perform System Language Discovery (T1614.001) by reading HKLM\SYSTEM\ControlSet001\Control\NLS\Language.

XWorm/Violet v5

XWorm/Violet v5 dropped from 1.4 MB (v4.7) to 71 KB. The config is double-base64 encoded then XOR'd with mwrQqYk. Mutex: HOHE6S8FaZZlGf0f. 80+ commands covering reverse shell, keylogger, HVNC, credential theft, DDoS, crypto clipper, USB worm propagation, ngrok tunnelling, and BSOD. The Violet install GUID matches the February campaign.


Brute Ratel C4 loader

The BRc4 binary is a 621 KB native x64 PE that impersonates mmc.exe (Microsoft Management Console, v10.0.20348.4163) via its VS_VERSION_INFO resources. PE timestamp: 2026-03-20. The dnSUXRIL marker string appears twice in the binary - a known BRc4 identification signature.

PE structure

SectionSizePurpose
.text176 KBLoader code, FNV-1a API resolution
.data370 KBEncrypted payload blob (high entropy)
.retplne-Retpoline stubs
_sysc-Direct syscall stubs

The entire import table is minimal - IsProcessorFeaturePresent, SetUnhandledExceptionFilter, and a few CRT functions. All operational APIs are resolved at runtime by walking the PEB InLoadOrderModuleList and hashing export names with FNV-1a (offset basis 0x811c9dc5, prime 0x1000193).

Payload decryption

The .data section contains a 16-byte header followed by 369,936 bytes of ciphertext.

OffsetFieldValue
0x00uint64 injection_method1 (Early Bird APC Queue)
0x08uint64 reserved0
0x10AES-256-CBC encrypted blob369,936 bytes

Decryption:

ParameterValue
AES-256-CBC keya984c0ca515684ae39ef9af5f3872daf30bae6b91b141258914db55bf5b5869e
AES IVacb58f89cc0d198655d8a648df74b51f
Post-decrypt XORcfc1b3813d370a1c2ebcc16562d7f62b (16-byte rotating key)

The AES implementation uses standard Rijndael S-boxes in .rdata. After CBC decryption, a second pass XORs each byte with the rotating 16-byte key.

Injection

Ten injection methods are compiled into the binary, each confirmed present via static analysis of the .text section. The config byte at .data+0x00 selects the active method:

SelectorMethod
1Early Bird APC Queue (active in this sample)
2KernelCallbackTable
3Thread Hijacking
4Section View Mapping
5Thread Suspension
6LineDDA Callback
7EnumSystemGeoID Callback
8FLS Callback
9SetTimer
10Clipboard

The active method (1) spawns C:\Windows\System32\notepad.exe in a suspended state with PPID spoofed to explorer.exe via InitializeProcThreadAttributeList + UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS). The loader allocates RWX memory in notepad.exe, writes the decrypted blob, queues it as an APC on the main thread, then resumes the thread. All memory operations use direct syscalls from the _sysc section - 12 syscall sites total, bypassing any userland hooks.

Before injection, SetProcessMitigationPolicy blocks non-Microsoft DLLs from loading in notepad.exe. This prevents EDR agents from injecting monitoring DLLs into the target process.

Behavioural analysis confirmed the decrypted 370 KB blob is PureHVNC stage 2 shellcode. The injected notepad.exe process beacons to bsmaopm.duckdns.org:6757 - the PureHVNC C2. Memory dumps from notepad.exe contain .NET CLR heap structures consistent with PureHVNC, not native BRc4 badger regions. The PPID spoof is effective enough that process attribution shows notepad.exe as a child of Explorer, not the malware. The loader exits within three seconds of completing injection.

BRc4 is the delivery and evasion layer. PureHVNC is the payload. There is no separate BRc4 C2 channel.


PureHVNC

The PureHVNC loader (Ygfumkl namespace) decrypts a 311,904-byte inline array with AES-256-CBC, strips a 4-byte length prefix, GZip-decompresses the result, and reflectively loads the output via Assembly.Load. The entry point is InvokeMember("ManageSegmentedDic").

The stage 2 DLL (PureHVNC_Lib / Lhjknyy namespaces, 788 KB) implements:

  • Hidden VNC: captures the primary display at 640x480, JPEG-compressed at quality 60, streamed to C2 as SequentialProfile ProtoBuf messages
  • Browser credential theft: targets 30+ Chromium-based browsers via profile directory enumeration under AppData. All paths are XOR-obfuscated at runtime
  • PE/DLL injection: loads .NET assemblies via Assembly.Load(byte[]) or patches existing loaded assemblies. Also implements native injection via VirtualAlloc + WriteProcessMemory with runtime-constructed API names
  • File manager: recursive directory listing, upload, download, and delete
  • Persistence: copies to %AppData%\<subfolder>\<filename> (paths obfuscated) with registry Run key persistence

The C2 protocol layers TCP + TLS 1.0 (SslStream) with a custom RemoteCertificateValidationCallback that pins the server certificate against a cert embedded in the config blob. A 4-byte big-endian length prefix frames each ProtoBuf message. 86 concrete message types are registered via [ProtoInclude] directives on the ControllableInitializer base class.

All string constants are XOR-obfuscated against per-module integer masks loaded from an AES-CBC encrypted + Deflate-compressed embedded resource at assembly load time. Static extraction of the C2 host and port is not possible - the config requires runtime decryption.

The C2 was extracted through behavioural analysis: bsmaopm.duckdns.org:6757, resolving to 12.202.180.133.


Infrastructure intelligence

C2 resolution

FamilyC2PortIP (2026-04-03)
AsyncRATuejrhnfq.duckdns.org674512.202.180.133
VenomRATy57kdsa.duckdns.org787812.202.180.133
PureHVNC + BRc4bsmaopm.duckdns.org675712.202.180.133
XWorm/Violetvivogrouplink.duckdns.org212812.202.180.105

Both IPs are in 12.202.176.0/21 - AS7018, AT&T Enterprises, Chicago, Illinois. ISP-class infrastructure with no rDNS, no Shodan port history, no GreyNoise mass-scan activity, and no blacklist entries (all queried 2026-04-03).

Domain inventory

Reverse IP lookups and passive DNS (SecurityTrails, queried 2026-04-03) revealed 13 DuckDNS domains attributed to this operator:

Active on 12.202.180.133 (9 domains): bsmaopm (PureHVNC+BRc4), uejrhnfq (AsyncRAT), y57kdsa (VenomRAT), 902399hfjks (XWorm V3.1 - persisted from the February campaign), jbsak, 5840dfhk, mdata4717, hy647dhon, hjupow

Active on 12.202.180.105 (2 domains): vivogrouplink (XWorm/Violet v5), volvogroup20 (continues the vi*group* naming convention)

Sinkholed (2 domains): remgreat2740 and anongroup resolve to 192.169.69.25/.26 - HYAS sinkholes (sinkhole.hyas.com). These were formerly on ServerAstra infrastructure in Budapest used in the February campaign.

Infrastructure timeline

DNS history for 902399hfjks.duckdns.org - the domain that persisted across both campaigns - shows the migration path:

PeriodIPHoster
Nov 2025206.223.183.200Beanfield Technologies, Toronto
Nov 2025 - Jan 202645.58.143.254Sharktech, Amsterdam
Jan 2026 - present12.202.180.133AT&T, Chicago

The Sharktech period overlaps with the February campaign, which also used 45.58.143.254 for Violet, Plog, and PureHVNC C2s.

remgreat2740.duckdns.org bounced between three LeaseWeb Netherlands IPs and AT&T Chicago before HYAS sinkholed it on February 20. The consolidation to AT&T Chicago followed the HYAS sinkholing in February.

Communicating files

VirusTotal passive data on 12.202.180.133 (queried 2026-04-03) shows 10 communicating files - five from this case and five older samples from the same operator. The oldest is PNOLazJuly21_hv.py, a Python loader with the BRc4-to-PureHVNC naming pattern, hosted on jbsak.duckdns.org. This dates the operator's activity to at least July 2025.

One of the related samples - 1MaDLL.zip - contained a parallel DLL-based injection wrapper dated March 30 (the same day as this campaign). The DLL exports inject_early_bird and xor_decrypt, matching the BRc4 loader's injection method and cryptographic approach but packaged as a regsvr32-loadable DLL. The operator maintains multiple injection tools alongside the Python loader pipeline.

Obfuscation evolution

Samples from September 2025 show that Kramer obfuscation was applied selectively. In that period, only the BRc4 loader (2Sep24Laz_hv-obf.py, note the -obf suffix) was Kramer-wrapped. The standard AES+XOR loaders shipped as plaintext Python with inline hex keys. By March 2026, all 10 files are Kramer-obfuscated. The injection template itself - same imports, same injection logic, same cryptographic structure - has not changed.

The PureHVNC loader also shrunk from 3.4 MB (February 2026 build) to 338 KB (this campaign). Same Ygfumkl namespace in both builds.


IOC summary

Network

TypeValueContext
C2uejrhnfq.duckdns.org:6745AsyncRAT 0.5.7B
C2y57kdsa.duckdns.org:7878VenomRAT v3.6
C2vivogrouplink.duckdns.org:2128XWorm/Violet v5
C2bsmaopm.duckdns.org:6757PureHVNC + BRc4
C2 IP12.202.180.133AsyncRAT, VenomRAT, PureHVNC+BRc4
C2 IP12.202.180.105XWorm/Violet v5
Deliveryedward-fwd-vacuum-changelog.trycloudflare.comWSH lure (/yop/)
Deliveryhanded-mines-abc-intensity.trycloudflare.comWSF loader (/ku/)
Deliveryrover-earlier-baseline-karen.trycloudflare.comBatch files
Deliveryrepresents-causes-conflicts-silver.trycloudflare.comPayload ZIPs

Hashes

SHA256File
e84cbbbc018d7e54c5afed760f04c06731ba57c1d40414c8b94ba1c488b9c9c5Scan_0620954916911.pdf.wsh
6b45e1a38609b9b7f2f2508b0b38f700a75ee1ea9b6c548d1a086bd91863efc3UKMar30.wsf
e06dd348a334de7e2e43ef7a3739d4b4cf792b615595262aa212eec4e3005564UKM301.bat
218628edc95f7c425fad294048adca65e235ae3024f084c9afaf483f66f71b6cUKM302.bat / UKM303.bat
3bc36b9b7bc5ee73b26dd94d34a31cb707feb9a68d2e4832d276e9274e780a341Mar23MA.zip
010ce592bcabf0d4e786b20d46bbd25893734a176e1f5322a5f28c4f94d4c6e11Mar23ST.zip
58d9f039ec38bbe03a1e1bf58a0102ce9c94d6efe39d2450cb44917d4a5c75afVenomRAT v3.6
4bb4a303b8e4873401be1cea68d50bdaa454471685dc30ad61e9ef746181aa29AsyncRAT 0.5.7B
f56a53ec6817c918d9a0056277022d694a06727bc9064bee95e4b80c50067f2aPureHVNC loader
59079dbdfb0346deae4efc361d78844141bf77d916adec96b23d8061e20e123cPureHVNC stage 2
8cda591f526a09954c7a60337daa767be7948367ee52accebc30061be1dc581aXWorm/Violet v5
026f71d40fa2e3c530283c1a70925d14eeee18d98f95506dd88cb698ccca6859Brute Ratel C4

Host

IndicatorContext
%USERPROFILE%\\Contacts\\MainRingtonesPrimary payload directory (hidden)
%USERPROFILE%\\Contacts\\strSecondary payload directory (hidden)
%APPDATA%\\Winic\\30.3.0rc5032-bit Python persistence
AsyncMutex_6SI8OkPnkAsyncRAT mutex
HOHE6S8FaZZlGf0fXWorm/Violet mutex
WinSc32.exeXWorm drop filename (%TEMP%)

Behavioural

IndicatorContext
rundll32.exe + davclnt.dll WebDAV to trycloudflare.comStage 0 delivery
notepad.exe with PPID = explorer.exe, beaconing to DuckDNSBRc4 -> PureHVNC injection
NtCreateUserProcessBlockNonMicrosoftBinary on spawned processBRc4 mitigation policy
DNS queries to DuckDNS domains every 12-17 secondsC2 retry loops (all families)

Campaign assessment

The operator retargeted five weeks after remediation with an upgraded delivery chain - ClickFix social engineering and ephemeral Cloudflare tunnels - and a new evasion layer in Brute Ratel C4. The underlying toolchain has been stable since at least July 2025: same Python loaders, same Donut shellcode, same five RAT families, same DuckDNS infrastructure pattern. The infrastructure consolidation to a single AT&T /24 in Chicago followed the sinkholing of their European infrastructure.

See also: Python loader evolution, Violet RAT, PureLogs RAT, PureCrypter, Remcos AutoIt.

Share this article