Obfuscated Script Loaders — Detecting ClickFix Payloads That Don't Exist Yet
The page source contained zero malicious content. The ClickFix payload was fetched from a remote C2 server by a heavily obfuscated JavaScript loader that used _0x variable renaming, Base64-encoded URLs, string array rotation, and CSS body-hiding to conceal everything.
The Technique
The loader used multiple layers of obfuscation working together: _0x-style variable renaming (characteristic of obfuscator.io output), a C2 URL hidden inside an atob() call, a push/shift while loop that rotates a string array to defeat static analysis, parseInt shuffling chains that compute array indices at runtime, a CSS injection that hides the page body with opacity:0 and a delayed fadeIn animation while the loader runs, and a sessionStorage.getItem('__sync_load') check that stops the attack from firing more than once per session.
The C2 URL decoded from the Base64 was primetimehost.me/ama.php — a remote server that served the actual ClickFix HTML payload. The host and timestamp were sent as query parameters for tracking. After fetching the payload, the loader used document.write() to replace the entire page.
How We Added Detection
A new detection layer was built that scans all inline <script> blocks for obfuscation signatures. Each signal is scored independently:
atob() with long Base64 string (35 pts) — the key C2 hiding technique. The detector also attempts to decode the Base64 and checks if the result contains a URL.
Base64 decodes to URL (30 pts) — confirms the atob is hiding a remote resource, not just data. The decoded URL is extracted and included in the warning banner.
_0x obfuscation pattern (30 pts) — five or more _0x-prefixed identifiers in a single script block is a strong obfuscator.io fingerprint.
Dynamic script injection (25 pts) — createElement('script') with src assignment, covering both dot notation and bracket notation variants.
CSS body-hide (25 pts) — opacity:0 with a fadeIn animation on the body element.
sessionStorage gating (15 pts) — only scores if other signals are present, to avoid flagging legitimate session management.
String array rotation (20 pts) — the push/shift while loop combined with parseInt chains that compute against a magic number.
The signals are layered so normal sites don't trip — a single atob() call scores 35 (suspicious, not blocked). Real ClickFix loaders stack 4–6 signals simultaneously, reaching 100 and triggering the warning before the C2 payload has even arrived.
Obfuscated loader detection fires on the initial page load — before the C2 fetch completes, before document.write() replaces the page, and before any clipboard payload is delivered. Combined with the heartbeat recovery mechanism, the defense covers both the loader phase and the post-replacement ClickFix lure.