{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "keep-as-periodic-hunt",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "TerminalFix infections lead to persistent network-level proxy access; identifying the transition from social engineering to reconnaissance is critical to stop the intruder before they reach internal databases or domain controllers."
      },
      "name": "TerminalFix ClickFix Delivery and Automated Reconnaissance",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1115",
        "attack.t1059.001",
        "attack.t1547.001",
        "attack.t1053.005",
        "attack.t1018",
        "attack.t1087.002",
        "attack.t1482"
      ],
      "series": {
        "slug": "terminalfix-campaign-deploys-a-reverse-tunnel-through-multistage-intrusion",
        "index": 2,
        "title": "TerminalFix campaign deploys a reverse tunnel through multistage intrusion",
        "total": 3
      },
      "related": [
        {
          "hunt": "terminalfix-tunnel-detection",
          "reason": "This hunt targets the delivery and discovery phases; a sibling hunt targets the Python reverse tunnel deployment.",
          "relation": "follows"
        }
      ],
      "targets": {
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        }
      },
      "analysis": "A single rule for the Run key can be evaded with randomized naming; this hunt pivots from delivery lures (script content) to local staging (ProgramData) to discovery bursts, requiring an analyst to weigh the full chain of evidence.",
      "coverage": [
        {
          "stage": "defense-evasion-steganography",
          "reason": "Detection shifted to initial delivery interaction (ClickFix T1115/T1059.001) per design review to prioritize high-fidelity social engineering lures.",
          "status": "not_visible",
          "blind_spot": "no-script-logging"
        },
        {
          "stage": "persistence-mechanisms",
          "steps": [
            "scoping-programdata-activity"
          ],
          "status": "covered"
        },
        {
          "stage": "discovery-domain-reconnaissance",
          "steps": [
            "reconnaissance-baseline"
          ],
          "status": "covered"
        },
        {
          "stage": "initial-access-social-engineering",
          "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "execution-powershell-launcher",
          "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "defense-evasion-dll-sideloading",
          "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "command-and-control-asynchronous-shell",
          "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "command-and-control-reverse-tunnel",
          "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
          "status": "out_of_scope"
        }
      ],
      "scenario": {
        "stages": [
          {
            "name": "Social Engineering via Fake CAPTCHA",
            "slug": "initial-access-social-engineering",
            "tactic": "initial-access",
            "techniques": [
              "T1204.001"
            ],
            "observables": [
              "Cloudflare Turnstile verification overlay",
              "Verification command copied to clipboard",
              "Instructions to open Windows Terminal or PowerShell",
              "Fake Cloudflare-themed terminal output messages"
            ]
          },
          {
            "name": "Malicious PowerShell Launcher",
            "slug": "execution-powershell-launcher",
            "tactic": "execution",
            "techniques": [
              "T1059.001",
              "T1105"
            ],
            "observables": [
              "C:\\ProgramData\\f47f2a8c21c9df4e",
              "1.bat",
              "ZIP archive download with custom User-Agent",
              "I am not a robot - Cloudflare ID: f47f2a8c21c9df4e"
            ]
          },
          {
            "name": "DLL Sideloading via LockScreenContentServer",
            "slug": "defense-evasion-dll-sideloading",
            "tactic": "defense-evasion",
            "techniques": [
              "T1574.001"
            ],
            "observables": [
              "LockScreenContentServer.exe",
              "dui70.dll (unsigned, forged timestamp 2104)",
              "LockScreenContentServer.exe loading dui70.dll from ProgramData"
            ]
          },
          {
            "name": "Steganographic Payload Extraction",
            "slug": "defense-evasion-steganography",
            "tactic": "defense-evasion",
            "techniques": [
              "T1027.003"
            ],
            "observables": [
              "p1.png",
              "p2.png",
              "p3.png",
              "gitnow.dev",
              "Extract-RawFileFromImage PowerShell function",
              "Reassembling DLL fragments from PNG pixel data"
            ]
          },
          {
            "name": "Redundant Persistence",
            "slug": "persistence-mechanisms",
            "tactic": "persistence",
            "techniques": [
              "T1547.001",
              "T1053.005"
            ],
            "observables": [
              "LockScreenContentServer_MuODG5yBM",
              "Registry Run Key: HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
              "Scheduled Task running every 60 minutes",
              "attrib +h +s folder hiding on C:\\ProgramData subfolders"
            ]
          },
          {
            "name": "Extensive Domain Discovery",
            "slug": "discovery-domain-reconnaissance",
            "tactic": "discovery",
            "techniques": [
              "T1018",
              "T1087.002",
              "T1482"
            ],
            "observables": [
              "nltest /domain_trusts",
              "net group \"domain admins\" /domain",
              "get-aduser",
              "get-adcomputer",
              "Ping sweeps of dc, db, backup, gateway, mail servers"
            ]
          },
          {
            "name": "Asynchronous File-Watch Command Loop",
            "slug": "command-and-control-asynchronous-shell",
            "tactic": "command-and-control",
            "techniques": [
              "T1059.001"
            ],
            "observables": [
              "PowerShell file-watch loop monitoring text files",
              "Invoke-Expression (IEX) on watched file content",
              "Command output written to disk files"
            ]
          },
          {
            "name": "Reverse WebSocket Tunneling",
            "slug": "command-and-control-reverse-tunnel",
            "tactic": "command-and-control",
            "techniques": [
              "T1572",
              "T1090.003"
            ],
            "observables": [
              "pythonw.exe",
              "client.py",
              "gitnow.dev:443",
              "Reverse WebSocket tunnel providing SOCKS proxy access"
            ]
          }
        ],
        "summary": "The TerminalFix campaign employs fake Cloudflare CAPTCHA prompts to trick users into executing malicious PowerShell commands that initiate a multi-stage infection. The attack leverages DLL sideloading and steganography to deploy a persistent Python-based reverse tunnel, enabling attackers to conduct extensive Active Directory reconnaissance and maintain encrypted SOCKS-style proxy access to the victim's internal network."
      },
      "severity": "high",
      "rationale": "Start with user workstations; focus on hosts with activity in the randomized ProgramData directory or those running nltest and net group commands.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An intruder has used a fake Cloudflare verification lure to trick a user into pasting a PowerShell command, facilitating local directory staging and automated domain discovery.",
      "parameters": {
        "scope_hosts": {
          "from": {
            "ref": "analyst-input",
            "kind": "manual",
            "observed": "2026-08-29"
          },
          "type": "list[host]",
          "default": [],
          "description": "Hosts identified in the scoping step."
        },
        "lookback_days": {
          "from": {
            "ref": "standard-retention",
            "kind": "manual",
            "observed": "2026-08-29"
          },
          "type": "number",
          "default": "14",
          "description": "Days of telemetry to examine."
        },
        "programdata_target": {
          "from": {
            "ref": "msrc-blog",
            "kind": "article",
            "observed": "2026-08-29"
          },
          "type": "string",
          "default": "f47f2a8c21c9df4e",
          "description": "Randomized folder name used in the campaign summary."
        }
      },
      "provenance": {
        "authors": [
          {
            "org": "huntbase.io",
            "name": "Huntbase hunt generation"
          }
        ],
        "generated": {
          "by": "huntbase-hunt-generation",
          "from": "https://www.microsoft.com/en-us/security/blog/2026/08/28/terminalfix-campaign-deploys-reverse-tunnel-through-multistage-intrusion/",
          "gates": [
            "dry-run",
            "lint"
          ],
          "model": "hb_google/gemini-3-flash-preview"
        }
      },
      "references": [
        {
          "url": "https://www.microsoft.com/en-us/security/blog/2026/08/28/terminalfix-campaign-deploys-reverse-tunnel-through-multistage-intrusion/",
          "name": "MSRC Blog: TerminalFix campaign deploys a reverse tunnel through multistage intrusion"
        }
      ],
      "blind_spots": [
        {
          "id": "no-script-logging",
          "risk": "Without script block logging, the pasted multi-line PowerShell command will not be visible in telemetry.",
          "stage": "defense-evasion-steganography",
          "question": "whether the lure was executed in a terminal",
          "requires": "hb_script_activity with Script Block Logging (ID 4104)"
        },
        {
          "id": "endpoint-visibility",
          "risk": "If the host is not reporting registry events, the persistence mechanism remains hidden.",
          "stage": "persistence-mechanisms",
          "question": "whether the Run key exists on unmanaged hosts",
          "requires": "hb_registry_activity (Sysmon) or osquery hive snapshot"
        }
      ]
    },
    "name": "TerminalFix ClickFix Delivery and Automated Reconnaissance",
    "description": "This hunt targets the early-to-mid stages of a TerminalFix intrusion, focusing on the transition from social engineering (ClickFix) to environment mapping. It identifies the interaction where clipboard-pasted PowerShell lures are executed, staged in unique ProgramData paths, and followed by a rapid burst of Active Directory and infrastructure discovery commands. By correlating these distinct behavioural surfaces, the hunt identifies compromised hosts acting as network pivot points before the deployment of reverse tunnels."
  },
  "nodes": [
    {
      "id": "hypothesis",
      "type": "hypothesis",
      "label": "Hypothesis",
      "config": {
        "tags": [],
        "series": {
          "slug": "terminalfix-campaign-deploys-a-reverse-tunnel-through-multistage-intrusion",
          "index": 2,
          "title": "TerminalFix campaign deploys a reverse tunnel through multistage intrusion",
          "total": 3
        },
        "coverage": [
          {
            "stage": "defense-evasion-steganography",
            "reason": "Detection shifted to initial delivery interaction (ClickFix T1115/T1059.001) per design review to prioritize high-fidelity social engineering lures.",
            "status": "not_visible",
            "blind_spot": "no-script-logging"
          },
          {
            "stage": "persistence-mechanisms",
            "steps": [
              "scoping-programdata-activity"
            ],
            "status": "covered"
          },
          {
            "stage": "discovery-domain-reconnaissance",
            "steps": [
              "reconnaissance-baseline"
            ],
            "status": "covered"
          },
          {
            "stage": "initial-access-social-engineering",
            "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "execution-powershell-launcher",
            "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "defense-evasion-dll-sideloading",
            "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "command-and-control-asynchronous-shell",
            "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "command-and-control-reverse-tunnel",
            "reason": "Belongs to another part of the 'TerminalFix campaign deploys a reverse tunnel through multistage intrusion' series.",
            "status": "out_of_scope"
          }
        ],
        "rationale": "An intruder has used a fake Cloudflare verification lure to trick a user into pasting a PowerShell command, facilitating local directory staging and automated domain discovery.",
        "blind_spots": [
          {
            "id": "no-script-logging",
            "risk": "Without script block logging, the pasted multi-line PowerShell command will not be visible in telemetry.",
            "stage": "defense-evasion-steganography",
            "question": "whether the lure was executed in a terminal",
            "requires": "hb_script_activity with Script Block Logging (ID 4104)"
          },
          {
            "id": "endpoint-visibility",
            "risk": "If the host is not reporting registry events, the persistence mechanism remains hidden.",
            "stage": "persistence-mechanisms",
            "question": "whether the Run key exists on unmanaged hosts",
            "requires": "hb_registry_activity (Sysmon) or osquery hive snapshot"
          }
        ],
        "scoping_notes": "Start with user workstations; focus on hosts with activity in the randomized ProgramData directory or those running nltest and net group commands.",
        "beyond_detection": "A single rule for the Run key can be evaded with randomized naming; this hunt pivots from delivery lures (script content) to local staging (ProgramData) to discovery bursts, requiring an analyst to weigh the full chain of evidence."
      }
    },
    {
      "id": "scoping-programdata-activity",
      "type": "query",
      "label": "Identify campaign-specific directory activity",
      "config": {
        "dsl": "sqlite",
        "role": "scoping",
        "source": "endpoint",
        "content": "SELECT device_hostname, process_path, process_cmd_line, time FROM hb_process_activity WHERE (LOWER(process_path) LIKE '%\\programdata\\{{programdata_target}}\\%' OR LOWER(process_cmd_line) LIKE '%\\programdata\\{{programdata_target}}\\%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_process_activity",
        "description": "Find hosts where files are being executed from or paths are established in the unique ProgramData folder mentioned in the campaign.",
        "expected_signal": "A list of hosts running processes from the campaign's staging directory. Silence means this specific path has not been used."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "scoping",
        "label": "Identify campaign-specific directory activity",
        "reads": [
          "device_hostname",
          "process_path",
          "process_cmd_line",
          "time"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, process_path, process_cmd_line, time FROM hb_process_activity WHERE (LOWER(process_path) LIKE '%\\programdata\\{{programdata_target}}\\%' OR LOWER(process_cmd_line) LIKE '%\\programdata\\{{programdata_target}}\\%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "A list of hosts running processes from the campaign's staging directory. Silence means this specific path has not been used.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "clickfix-delivery-interaction",
      "type": "query",
      "label": "Detect ClickFix PowerShell interaction",
      "config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "source": "endpoint",
        "content": "SELECT device_hostname, script_content, time FROM hb_script_activity WHERE (instr(LOWER(script_content), 'cloudflare') > 0 AND (instr(LOWER(script_content), 'verification') > 0 OR instr(LOWER(script_content), 'not a robot') > 0)) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_script_activity",
        "description": "Identify PowerShell script blocks that match the fake Cloudflare verification lure pasted into the terminal.",
        "expected_signal": "Script blocks containing fake verification messages. Silence proves the lure was not executed via a script-block logging interface."
      },
      "parents": [
        {
          "id": "scoping-programdata-activity"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "label": "Detect ClickFix PowerShell interaction",
        "reads": [
          "device_hostname",
          "script_content",
          "time"
        ],
        "source": "hb_script_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, script_content, time FROM hb_script_activity WHERE (instr(LOWER(script_content), 'cloudflare') > 0 AND (instr(LOWER(script_content), 'verification') > 0 OR instr(LOWER(script_content), 'not a robot') > 0)) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Script blocks containing fake verification messages. Silence proves the lure was not executed via a script-block logging interface.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "reconnaissance-baseline",
      "type": "query",
      "label": "Monitor for automated AD discovery",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, COUNT(*) as cmd_count, MIN(time) as first_seen FROM hb_process_activity WHERE (instr(LOWER(process_cmd_line), '/domain_trusts') > 0 OR instr(LOWER(process_cmd_line), 'domain admins') > 0 OR instr(LOWER(process_cmd_line), 'get-aduser') > 0 OR (LOWER(process_name) LIKE '%ping.exe%' AND (LOWER(process_cmd_line) LIKE '%dc%' OR LOWER(process_cmd_line) LIKE '%db%' OR LOWER(process_cmd_line) LIKE '%backup%'))) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY device_hostname, process_name, process_cmd_line",
        "surface": "hb_process_activity",
        "description": "Identify hosts performing a burst of domain and infrastructure discovery commands often seen in TerminalFix campaigns.",
        "expected_signal": "A cluster of discovery commands on one host that are rare across the fleet. Multiple matches in a short window indicate automated mapping."
      },
      "parents": [
        {
          "id": "scoping-programdata-activity"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Monitor for automated AD discovery",
        "reads": [
          "device_hostname",
          "process_name",
          "process_cmd_line",
          "time"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, COUNT(*) as cmd_count, MIN(time) as first_seen FROM hb_process_activity WHERE (instr(LOWER(process_cmd_line), '/domain_trusts') > 0 OR instr(LOWER(process_cmd_line), 'domain admins') > 0 OR instr(LOWER(process_cmd_line), 'get-aduser') > 0 OR (LOWER(process_name) LIKE '%ping.exe%' AND (LOWER(process_cmd_line) LIKE '%dc%' OR LOWER(process_cmd_line) LIKE '%db%' OR LOWER(process_cmd_line) LIKE '%backup%'))) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY device_hostname, process_name, process_cmd_line",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "A cluster of discovery commands on one host that are rare across the fleet. Multiple matches in a short window indicate automated mapping.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "process_cmd_line"
          ],
          "rare_below": 5
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "triage-agent",
      "type": "analytic",
      "label": "Weigh campaign evidence",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint"
        ],
        "context": [
          "scoping-programdata-activity",
          "clickfix-delivery-interaction",
          "reconnaissance-baseline"
        ],
        "objective": "Determine if the host shows a complete chain from ClickFix interaction to campaign-specific staging and automated environment discovery.",
        "description": "Correlate the directory staging with the social engineering lure and the resulting reconnaissance burst to confirm a TerminalFix infection.",
        "max_iterations": 4,
        "expected_signal": "A per-host verdict citing specific scripts and command lines.",
        "success_criteria": "A verdict of malicious | suspicious | benign per host with citations of script content matching the Cloudflare lure."
      },
      "parents": [
        {
          "id": "clickfix-delivery-interaction",
          "kind": "merge"
        },
        {
          "id": "reconnaissance-baseline",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "route-verdict",
      "type": "checkpoint",
      "label": "Route on verdict",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "the triage verdict is malicious for at least one host",
        "condition": "the triage verdict is malicious for at least one host",
        "blind_spot": "no-script-logging",
        "confidence": "high",
        "description": "Direct high-confidence findings to containment and others to manual review.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "triage-agent"
        }
      ]
    },
    {
      "id": "isolate-host",
      "type": "action",
      "label": "Isolate compromised host",
      "config": {
        "target": "endpoint",
        "description": "Sever the network connection of a confirmed TerminalFix beachhead to prevent lateral movement.",
        "instructions": "Isolate the host and collect the contents of the ProgramData campaign directory for forensic analysis.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "route-verdict",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "analyst-review",
      "type": "task",
      "label": "Analyst review",
      "config": {
        "assignee": "analyst",
        "description": "Review findings, tune discovery baselines, and look for signs of the follow-on reverse tunnel.",
        "instructions": "Verify the cited script blocks. Pivot to network traffic for connections to gitnow.dev or unexpected pythonw.exe activity on port 443."
      },
      "parents": [
        {
          "id": "route-verdict",
          "branch": "default"
        },
        {
          "id": "route-verdict",
          "branch": "on_unavailable"
        },
        {
          "id": "route-verdict",
          "branch": "on_refutes"
        },
        {
          "id": "isolate-host"
        }
      ]
    },
    {
      "id": "close-out",
      "type": "task",
      "label": "Close out",
      "config": {
        "assignee": "analyst",
        "description": "Document findings and verify remediation.",
        "instructions": "Ensure the registry persistence keys and scheduled tasks are removed. Record any new infrastructure pings identified in the triage process."
      },
      "parents": [
        {
          "id": "analyst-review"
        }
      ]
    }
  ]
}