{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "promote-to-detection",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "Human-operated intrusions that pivot toward identity infrastructure represent a critical risk of enterprise-wide compromise; identifying interactive implants early is essential to prevent ransomware deployment."
      },
      "name": "Persistent Node.js Backdoor Activity",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1071",
        "attack.t1090.003",
        "attack.t1041",
        "attack.t1059.001",
        "attack.t1218.011",
        "attack.t1555"
      ],
      "series": {
        "slug": "impersonating-it-support-how-threat-actors-turn-a-remote-session-into-enterprise-wide-access",
        "index": 2,
        "title": "Impersonating IT support: how threat actors turn a remote session into enterprise-wide access",
        "total": 2
      },
      "related": [
        {
          "hunt": "it-support-social-engineering-teams",
          "reason": "The initial social engineering and remote session setup stage is a separate point of visibility.",
          "relation": "out-of-scope-alternative"
        }
      ],
      "targets": {
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "network": {
          "name": "Network telemetry",
          "category": "network",
          "telemetry": [
            "network"
          ]
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        }
      },
      "analysis": "A standard rule may flag Node.js execution, but this hunt correlates the execution with fleet-wide rarity, reconnaissance-themed scripts, and internal WinRM traffic to distinguish an intruder from a legitimate developer.",
      "coverage": [
        {
          "stage": "node-js-implant-c2",
          "steps": [
            "node-execution-scoping",
            "rare-node-paths"
          ],
          "status": "covered"
        },
        {
          "stage": "host-and-domain-reconnaissance",
          "steps": [
            "recon-script-activity"
          ],
          "status": "covered"
        },
        {
          "stage": "lateral-movement-winrm",
          "steps": [
            "winrm-internal-connections"
          ],
          "status": "covered"
        },
        {
          "stage": "it-support-social-engineering",
          "reason": "Belongs to another part of the 'Impersonating IT support: how threat actors turn a remote session into enterprise-wide access' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "malicious-msi-installation",
          "reason": "Belongs to another part of the 'Impersonating IT support: how threat actors turn a remote session into enterprise-wide access' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "edge-update-persistence",
          "reason": "Belongs to another part of the 'Impersonating IT support: how threat actors turn a remote session into enterprise-wide access' series.",
          "status": "out_of_scope"
        }
      ],
      "scenario": {
        "stages": [
          {
            "name": "IT Support Social Engineering",
            "slug": "it-support-social-engineering",
            "tactic": "initial-access",
            "techniques": [
              "T1566.003"
            ],
            "observables": [
              "quickassist.exe",
              "Microsoft Teams external contact prompts",
              "Accept/Block control prompts"
            ]
          },
          {
            "name": "Malicious MSI Installation",
            "slug": "malicious-msi-installation",
            "tactic": "execution",
            "techniques": [
              "T1059.001"
            ],
            "observables": [
              "msiexec.exe /qn",
              "devfix.msi",
              "Hotfix.msi",
              "PowerShell downloading from cloud storage"
            ]
          },
          {
            "name": "Implant Persistence",
            "slug": "edge-update-persistence",
            "tactic": "persistence",
            "techniques": [
              "T1059.001"
            ],
            "observables": [
              "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\EdgeUpdate",
              "EdgeUpdate.lnk in user Startup folder",
              "WScript launching Node.js"
            ]
          },
          {
            "name": "Node.js Implant C2",
            "slug": "node-js-implant-c2",
            "tactic": "command-and-control",
            "techniques": [
              "T1071",
              "T1090.003",
              "T1041"
            ],
            "observables": [
              "node.exe executing from LocalAppData",
              "randomized HTTPS long-polling",
              "JS loaders with .tmp, .ini, .dat, .bin, or .cfg extensions"
            ]
          },
          {
            "name": "Host and Domain Reconnaissance",
            "slug": "host-and-domain-reconnaissance",
            "tactic": "discovery",
            "techniques": [
              "T1059.001",
              "T1218.011",
              "T1555"
            ],
            "observables": [
              "ADSI queries for domain enumeration",
              "AV and VM discovery checks",
              "rundll32.exe loading actor-supplied DLLs",
              "Base64 encoded screenshots in temp files"
            ]
          },
          {
            "name": "Lateral Movement via WinRM",
            "slug": "lateral-movement-winrm",
            "tactic": "lateral-movement",
            "techniques": [
              "T1059.001"
            ],
            "observables": [
              "WinRM connections over TCP port 5985",
              "Pivoting toward Domain Controllers and CAs"
            ]
          }
        ],
        "summary": "Threat actors use Microsoft Teams to impersonate helpdesk personnel, tricking users into allowing remote control and installing a persistent Node.js implant. This implant enables persistent command-and-control, host discovery, and lateral movement via WinRM toward high-value infrastructure."
      },
      "severity": "medium",
      "rationale": "Focus on hosts where users have LocalAppData execution rights and where external Microsoft Teams collaboration is permitted.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An intruder is maintaining interactive control via a Node.js implant staged in a user profile, performing Active Directory reconnaissance and moving laterally via WinRM.",
      "parameters": {
        "scope_hosts": {
          "type": "list[host]",
          "default": [],
          "description": "A list of hostnames to focus the search; leave empty to hunt across the entire estate."
        },
        "lookback_days": {
          "type": "number",
          "default": "14",
          "description": "Days of history to examine."
        }
      },
      "provenance": {
        "authors": [
          {
            "org": "huntbase.io",
            "name": "Huntbase hunt generation"
          }
        ],
        "generated": {
          "by": "huntbase-hunt-generation",
          "from": "https://www.microsoft.com/en-us/security/blog/2026/09/02/impersonating-it-support-threat-actors-turn-remote-session-into-enterprise-wide-access/",
          "gates": [
            "dry-run",
            "lint",
            "critic"
          ],
          "model": "hb_google/gemini-3-flash-preview"
        }
      },
      "references": [
        {
          "url": "https://www.microsoft.com/en-us/security/blog/2026/09/02/impersonating-it-support-threat-actors-turn-remote-session-into-enterprise-wide-access/",
          "name": "MSRC Blog: Impersonating IT support: how threat actors turn a remote session into enterprise-wide access"
        }
      ],
      "blind_spots": [
        {
          "id": "encrypted-c2-tasks",
          "risk": "The intruder can change their reconnaissance patterns in memory without producing new on-disk artifacts, making it difficult to fully scope their actions.",
          "stage": "node-js-implant-c2",
          "question": "What specific JavaScript instructions are being sent over the randomized HTTPS polling?",
          "requires": "Network TLS inspection or in-memory script capture"
        },
        {
          "id": "winrm-over-non-standard-ports",
          "risk": "The query specifically targets port 5985; movement on custom ports would not be visible here.",
          "stage": "lateral-movement-winrm",
          "question": "Did the attacker move laterally over WinRM using a non-standard port?",
          "requires": "Deep packet inspection for administrative protocols"
        }
      ]
    },
    "name": "Persistent Node.js Backdoor Activity",
    "description": "This hunt targets the post-exploitation behavior of an adversary who has gained access through social engineering. It focuses on the unusual execution of a legitimate Node.js runtime from LocalAppData, a pattern used to evade binary-based detections. The hunt correlates this execution with rare file paths, reconnaissance-themed script blocks (ADSI, AV/VM discovery), and internal network pivoting over the WinRM protocol to identify hands-on-keyboard activity."
  },
  "nodes": [
    {
      "id": "hypothesis",
      "type": "hypothesis",
      "label": "Hypothesis",
      "config": {
        "tags": [],
        "series": {
          "slug": "impersonating-it-support-how-threat-actors-turn-a-remote-session-into-enterprise-wide-access",
          "index": 2,
          "title": "Impersonating IT support: how threat actors turn a remote session into enterprise-wide access",
          "total": 2
        },
        "coverage": [
          {
            "stage": "node-js-implant-c2",
            "steps": [
              "node-execution-scoping",
              "rare-node-paths"
            ],
            "status": "covered"
          },
          {
            "stage": "host-and-domain-reconnaissance",
            "steps": [
              "recon-script-activity"
            ],
            "status": "covered"
          },
          {
            "stage": "lateral-movement-winrm",
            "steps": [
              "winrm-internal-connections"
            ],
            "status": "covered"
          },
          {
            "stage": "it-support-social-engineering",
            "reason": "Belongs to another part of the 'Impersonating IT support: how threat actors turn a remote session into enterprise-wide access' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "malicious-msi-installation",
            "reason": "Belongs to another part of the 'Impersonating IT support: how threat actors turn a remote session into enterprise-wide access' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "edge-update-persistence",
            "reason": "Belongs to another part of the 'Impersonating IT support: how threat actors turn a remote session into enterprise-wide access' series.",
            "status": "out_of_scope"
          }
        ],
        "rationale": "An intruder is maintaining interactive control via a Node.js implant staged in a user profile, performing Active Directory reconnaissance and moving laterally via WinRM.",
        "blind_spots": [
          {
            "id": "encrypted-c2-tasks",
            "risk": "The intruder can change their reconnaissance patterns in memory without producing new on-disk artifacts, making it difficult to fully scope their actions.",
            "stage": "node-js-implant-c2",
            "question": "What specific JavaScript instructions are being sent over the randomized HTTPS polling?",
            "requires": "Network TLS inspection or in-memory script capture"
          },
          {
            "id": "winrm-over-non-standard-ports",
            "risk": "The query specifically targets port 5985; movement on custom ports would not be visible here.",
            "stage": "lateral-movement-winrm",
            "question": "Did the attacker move laterally over WinRM using a non-standard port?",
            "requires": "Deep packet inspection for administrative protocols"
          }
        ],
        "scoping_notes": "Focus on hosts where users have LocalAppData execution rights and where external Microsoft Teams collaboration is permitted.",
        "beyond_detection": "A standard rule may flag Node.js execution, but this hunt correlates the execution with fleet-wide rarity, reconnaissance-themed scripts, and internal WinRM traffic to distinguish an intruder from a legitimate developer."
      }
    },
    {
      "id": "node-execution-scoping",
      "type": "query",
      "label": "Node.js execution from user-writable paths",
      "config": {
        "dsl": "sqlite",
        "role": "scoping",
        "source": "endpoint",
        "content": "SELECT device_hostname, process_path, process_cmd_line, user_name, time FROM hb_process_activity WHERE (LOWER(process_path) LIKE '%\\appdata\\local\\%' OR LOWER(process_path) LIKE '%\\users\\%\\appdata\\%') AND (LOWER(process_name) LIKE '%node.exe' OR LOWER(process_original_file_name) = 'node.exe') AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_process_activity",
        "description": "Identify hosts where the Node.js runtime or renamed copies are executing from LocalAppData, which is the primary execution pattern for this implant.",
        "expected_signal": "Hosts where Node.js is running from a user profile. Legitimate development often uses specific paths; outliers here warrant investigation."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "scoping",
        "label": "Node.js execution from user-writable paths",
        "reads": [
          "device_hostname",
          "process_cmd_line",
          "process_name",
          "process_original_file_name",
          "process_path",
          "time",
          "user_name"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, process_path, process_cmd_line, user_name, time FROM hb_process_activity WHERE (LOWER(process_path) LIKE '%\\appdata\\local\\%' OR LOWER(process_path) LIKE '%\\users\\%\\appdata\\%') AND (LOWER(process_name) LIKE '%node.exe' OR LOWER(process_original_file_name) = 'node.exe') AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Hosts where Node.js is running from a user profile. Legitimate development often uses specific paths; outliers here warrant investigation.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "rare-node-paths",
      "type": "query",
      "label": "Prevalence of Node.js execution paths",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "endpoint",
        "content": "SELECT LOWER(process_path) AS path, COUNT(DISTINCT device_hostname) AS hosts, COUNT(*) AS runs FROM hb_process_activity WHERE (LOWER(process_path) LIKE '%\\appdata\\local\\%' OR LOWER(process_path) LIKE '%\\users\\%\\appdata\\%') AND (LOWER(process_name) LIKE '%node.exe' OR LOWER(process_original_file_name) = 'node.exe') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY path HAVING hosts <= 3 ORDER BY hosts ASC",
        "surface": "hb_process_activity",
        "description": "Stack-count the execution paths to find rare, randomly named directories used for implant staging.",
        "expected_signal": "A path seen on only one or two hosts, which is highly characteristic of the randomly named staging directories in this campaign."
      },
      "parents": [
        {
          "id": "node-execution-scoping"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Prevalence of Node.js execution paths",
        "reads": [
          "device_hostname",
          "process_name",
          "process_original_file_name",
          "process_path",
          "time"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT LOWER(process_path) AS path, COUNT(DISTINCT device_hostname) AS hosts, COUNT(*) AS runs FROM hb_process_activity WHERE (LOWER(process_path) LIKE '%\\appdata\\local\\%' OR LOWER(process_path) LIKE '%\\users\\%\\appdata\\%') AND (LOWER(process_name) LIKE '%node.exe' OR LOWER(process_original_file_name) = 'node.exe') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY path HAVING hosts <= 3 ORDER BY hosts ASC",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "A path seen on only one or two hosts, which is highly characteristic of the randomly named staging directories in this campaign.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "path"
          ],
          "rare_below": 3
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "recon-script-activity",
      "type": "query",
      "label": "Discovery and reconnaissance script blocks",
      "config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "source": "endpoint",
        "content": "SELECT device_hostname, script_path, script_content, time FROM hb_script_activity WHERE (LOWER(script_content) LIKE '%adsisearcher%' OR LOWER(script_content) LIKE '%antivirusproduct%' OR LOWER(script_content) LIKE '%win32_videocontroller%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_script_activity",
        "description": "Find evidence of domain enumeration and defensive checks performed through the Node.js implant.",
        "expected_signal": "Script blocks containing ADSI search queries or WMI checks for AV and VMs. This is a high-confidence signal for post-exploitation discovery."
      },
      "parents": [
        {
          "id": "node-execution-scoping"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "label": "Discovery and reconnaissance script blocks",
        "reads": [
          "device_hostname",
          "script_content",
          "script_path",
          "time"
        ],
        "source": "hb_script_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, script_path, script_content, time FROM hb_script_activity WHERE (LOWER(script_content) LIKE '%adsisearcher%' OR LOWER(script_content) LIKE '%antivirusproduct%' OR LOWER(script_content) LIKE '%win32_videocontroller%') 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 ADSI search queries or WMI checks for AV and VMs. This is a high-confidence signal for post-exploitation discovery.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "winrm-internal-connections",
      "type": "query",
      "label": "Lateral movement over WinRM",
      "config": {
        "dsl": "sqlite",
        "role": "enrichment",
        "source": "network",
        "content": "SELECT device_hostname, process_name, dst_endpoint_ip, dst_endpoint_port, direction, time FROM hb_network_connection WHERE (LOWER(process_name) LIKE '%node.exe' OR LOWER(process_path) LIKE '%\\appdata\\local\\%') AND dst_endpoint_port = 5985 AND direction = 'outbound' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_network_connection",
        "description": "Identify internal connections on port 5985, which the operator uses to pivot from the beachhead toward identity servers.",
        "expected_signal": "A Node.js process initiating WinRM connections to other internal hosts. This confirms lateral movement intent."
      },
      "parents": [
        {
          "id": "node-execution-scoping"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "enrichment",
        "label": "Lateral movement over WinRM",
        "reads": [
          "device_hostname",
          "direction",
          "dst_endpoint_ip",
          "dst_endpoint_port",
          "process_name",
          "process_path",
          "time"
        ],
        "source": "hb_network_connection",
        "target": "network",
        "content": "SELECT device_hostname, process_name, dst_endpoint_ip, dst_endpoint_port, direction, time FROM hb_network_connection WHERE (LOWER(process_name) LIKE '%node.exe' OR LOWER(process_path) LIKE '%\\appdata\\local\\%') AND dst_endpoint_port = 5985 AND direction = 'outbound' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "A Node.js process initiating WinRM connections to other internal hosts. This confirms lateral movement intent.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "triage-agent",
      "type": "analytic",
      "label": "Triage implant behavior",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint",
          "network"
        ],
        "context": [
          "node-execution-scoping",
          "rare-node-paths",
          "recon-script-activity",
          "winrm-internal-connections"
        ],
        "objective": "Determine whether the Node.js activity in user profiles, the rare execution paths, and the subsequent WinRM or discovery behavior indicates an active hands-on-keyboard intrusion.",
        "description": "Synthesize process, script, and network data to determine if a host is compromised by the Node.js implant.",
        "max_iterations": 5,
        "expected_signal": "A high-confidence verdict linking unusual Node.js runtime execution to reconnaissance and lateral pivoting.",
        "success_criteria": "A per-host verdict citing the specific process paths and script contents that indicate malicious intent."
      },
      "parents": [
        {
          "id": "rare-node-paths",
          "kind": "merge"
        },
        {
          "id": "recon-script-activity",
          "kind": "merge"
        },
        {
          "id": "winrm-internal-connections",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "routing-decision",
      "type": "checkpoint",
      "label": "Route based 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": "encrypted-c2-tasks",
        "confidence": "high",
        "description": "Isolate the host if the implant's presence and activity are confirmed.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "triage-agent"
        }
      ]
    },
    {
      "id": "isolate-host",
      "type": "action",
      "label": "Isolate host",
      "config": {
        "target": "endpoint",
        "description": "Sever the attacker's interactive session to prevent further lateral movement.",
        "instructions": "Isolate the host and collect the Node.js binary and any .js or .tmp files found in the LocalAppData directory identified by the agent.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "routing-decision",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "analyst-review",
      "type": "task",
      "label": "Analyst verification",
      "config": {
        "assignee": "analyst",
        "description": "Perform deeper investigation into the targets of lateral movement and verify the origin of the MSI.",
        "instructions": "Review the WinRM destination IPs to identify which other hosts may have been accessed. Check authentication logs for any failed or successful logons following the implant activity."
      },
      "parents": [
        {
          "id": "routing-decision",
          "branch": "default"
        },
        {
          "id": "routing-decision",
          "branch": "on_unavailable"
        },
        {
          "id": "isolate-host"
        }
      ]
    },
    {
      "id": "close-out",
      "type": "task",
      "label": "Hunt documentation",
      "config": {
        "assignee": "analyst",
        "description": "Finalize findings and suggest detection improvements.",
        "instructions": "Summarize the affected user and hosts. Consider promoting the reconnaissance script query to a permanent detection rule if the false positive rate is low."
      },
      "parents": [
        {
          "id": "routing-decision",
          "branch": "on_refutes"
        },
        {
          "id": "analyst-review"
        }
      ]
    }
  ]
}