← All hunts high TLP:CLEAR Part 2 of 2

Spring Ring: NTLM Relay and RAT C2

An attacker has deployed a custom Python environment to facilitate NTLM relay attacks and a PowerShell-based RAT that beacons to external command-and-control infrastructure.

Based on research by Unit 42 2026-09-20 9 steps · 3 queries T1071.001 T1210 T1557.001

Brief

Why now

Unit 42 recently published a detailed analysis of the Spring Ring campaign (https://unit42.paloaltonetworks.com/spring-ring-voice-phishing-campaigns/). These actors use voice phishing (vishing) within Microsoft Teams to trick users into installing malicious software. Once they establish a foothold, they pivot to NTLM relay attacks to move laterally and gain domain-level access. Our team has developed a new hunt.md playbook to help practitioners identify the technical markers of this campaign within their environments.

Finding the custom Python environment

The hunt starts by searching for the deployment of the attacker's tools. The adversary stages a tailored Python interpreter in the ProgramData directory. They use this environment to run scripts like PetitPotam, which triggers NTLM authentication from target servers back to the attacker's infrastructure. The first phase of our hunt identifies any host where this specific binary has executed, capturing the user context and the command-line arguments.

Corroborating network evidence

Once we identify potential beachhead hosts, the hunt pivots to network-layer evidence. The second phase runs two queries in parallel. One query monitors for outbound SMB scanning on port 445. The adversary uses the custom Python environment to reach out to numerous internal IP addresses, searching for targets for coercion. High volumes of outbound SMB traffic from a single endpoint suggest an active relay attempt.

Beaconing to command-and-control

The other parallel query focuses on command-and-control activity. The campaign involves a PowerShell-based Remote Access Trojan (RAT) that communicates with specific external domains. We check DNS activity for resolutions of known indicators, such as san-sid.com. This helps confirm if the compromised host has successfully established a link with the attacker's infrastructure.

Evaluating the intrusion

The triage phase brings these disparate signals together. An analyst reviews the correlated data to determine if the activity represents a true positive. We look for the confluence of the custom execution path, the outbound SMB scanning, and the C2 DNS resolutions. Finding all three on a single host provides high confidence of a Spring Ring intrusion.

Blind Spots

There are specific limits to what this hunt can see. While we can observe the outbound SMB connections from the beachhead, we lack visibility into the target server's response without server-side logs or Domain Controller events. Therefore, we cannot confirm if the NTLM relay actually succeeded in capturing a valid credential. Additionally, while DNS logs confirm the RAT's intent to communicate, the lack of TLS inspection means the contents of the command-and-control traffic remain hidden.

In this series

Steps

  1. Find custom Python interpreter

    Query · scoping

    Identify hosts running the tailored Python environment used to initiate NTLM relay attacks.

    reads hb_process_activitysql
    SELECT device_hostname, process_path, process_cmd_line, user_name, MIN(time) AS first_seen FROM hb_process_activity WHERE LOWER(process_path) = LOWER('{{python_path}}') AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3, 4

    What a hit looks like. A list of hosts and users executing the specific Python binary. Silence indicates the environment has not been deployed on any enrolled Windows endpoint.

  2. Outbound SMB scanning on port 445

    Query · detection candidate

    Identify potential PetitPotam coercion attempts by finding hosts contacting many internal targets over SMB.

    reads hb_network_connectionsql
    SELECT device_hostname, process_name, dst_endpoint_ip, COUNT(*) AS connections, MIN(time) AS first_seen FROM hb_network_connection WHERE dst_endpoint_port = 445 AND direction = 'outbound' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3 HAVING connections > 5 ORDER BY connections DESC

    What a hit looks like. A host connecting to multiple internal IP addresses on port 445. The presence of the suspicious python.exe as the originating process is a critical signal.

  3. DNS lookups for Spring Ring C2

    Query · enrichment

    Verify if hosts are beaconing to the PowerShell RAT command-and-control infrastructure.

    reads hb_dns_activitysql
    SELECT device_hostname, query_hostname, process_name, COUNT(*) AS lookups, MAX(time) AS last_seen FROM hb_dns_activity WHERE instr(',' || '{{c2_domains}}' || ',', ',' || LOWER(query_hostname) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3

    What a hit looks like. Resolutions for the known C2 domains from the beachhead hosts. Silence means no DNS activity for these specific indicators was captured.

  4. Evaluate Spring Ring intrusion

    Agent triage

    Correlate the findings from all three surfaces to determine if a host is compromised and attempting lateral movement.

  5. Route on malicious verdict

    Decision

    Direct the hunt to containment or manual review based on the agent's findings.

  6. Isolate host

    Response action

    Sever the attacker's connection and prevent further lateral movement attempts.

  7. Forensic review of SMB scanning

    Analyst task

    Verify the targets of the SMB scanning to confirm if Domain Controllers were targeted.

  8. Cleanup and report

    Analyst task

    Document the findings and close the hunt.

Coverage

Scenario coverage

StageCoveredHow, or why not
NTLM Relay and PetitPotam
T1557.001 · T1210
Yes find-custom-python, smb-scanning
PowerShell RAT C2 Beaconing
T1071.001
Yes c2-beaconing
Teams Vishing and Impersonation
T1566.003
Out of scope Belongs to another part of the 'Spring Ring: An Inside Look at Voice Phishing Campaigns in Microsoft Teams' series.
User Execution of RMM and Payloads
T1204.002 · T1219
Out of scope Belongs to another part of the 'Spring Ring: An Inside Look at Voice Phishing Campaigns in Microsoft Teams' series.
Staging and Persistence
T1547
Out of scope Belongs to another part of the 'Spring Ring: An Inside Look at Voice Phishing Campaigns in Microsoft Teams' series.
Bypassing AMSI and Browser Hijacking
T1027 · T1562.001 · T1176
Out of scope Belongs to another part of the 'Spring Ring: An Inside Look at Voice Phishing Campaigns in Microsoft Teams' series.
Host and Domain Discovery
T1033 · T1069.002
Out of scope Belongs to another part of the 'Spring Ring: An Inside Look at Voice Phishing Campaigns in Microsoft Teams' series.

Blind spots

  • Needs hb_network_connection with log visibility on domain controllers. We see the outbound scan from the beachhead but cannot confirm if the relay attack succeeded without server-side logs. It would answer whether the DC successfully authenticated back to the attacker.
  • Needs TLS inspection of outbound web traffic. DNS lookups show intent but not the content of the payload delivery, which may use arithmetic obfuscation that automated tools miss. It would answer whether the PowerShell RAT received further payloads.

Parameters & data

Parameters

ParameterTypeDefaultWhat it is
c2_domainslist[domain]san-sid.comC2 domains for the PowerShell RAT.
lookback_daysnumber14Days of history to examine.
python_pathpathC:\ProgramData\IntegrityData\python.exeThe specific Python path used for PetitPotam coercion.
scope_hostslist[host]Paste hosts from the scoping step here to narrow subsequent queries.

Telemetry

SourceCategoryTelemetry
Endpoint telemetry (hb_ surfaces)endpointendpoint
Network telemetrynetworknetwork

Source

Download hunt.md Definition (JSON) An open hunt.md file; it runs anywhere that reads the format.
---
analysis: A simple detection rule on the Python path can be evaded by renaming the
  binary. This hunt pivots to the behavioral impact (SMB scanning) and network indicators
  (DNS) to confirm the intrusion's intent.
blind_spots:
- id: no-smb-visibility
  question: whether the DC successfully authenticated back to the attacker
  requires: hb_network_connection with log visibility on domain controllers
  risk: We see the outbound scan from the beachhead but cannot confirm if the relay
    attack succeeded without server-side logs.
  stage: lateral-movement-ntlm-relay
- id: ephemeral-c2-infrastructure
  question: whether the PowerShell RAT received further payloads
  requires: TLS inspection of outbound web traffic
  risk: DNS lookups show intent but not the content of the payload delivery, which
    may use arithmetic obfuscation that automated tools miss.
  stage: command-and-control-rat
coverage:
- stage: lateral-movement-ntlm-relay
  status: covered
  steps:
  - find-custom-python
  - smb-scanning
- stage: command-and-control-rat
  status: covered
  steps:
  - c2-beaconing
- reason: 'Belongs to another part of the ''Spring Ring: An Inside Look at Voice Phishing
    Campaigns in Microsoft Teams'' series.'
  stage: initial-access-teams-vishing
  status: out_of_scope
- reason: 'Belongs to another part of the ''Spring Ring: An Inside Look at Voice Phishing
    Campaigns in Microsoft Teams'' series.'
  stage: execution-rmm-and-custom-payloads
  status: out_of_scope
- reason: 'Belongs to another part of the ''Spring Ring: An Inside Look at Voice Phishing
    Campaigns in Microsoft Teams'' series.'
  stage: persistence-staging-temp
  status: out_of_scope
- reason: 'Belongs to another part of the ''Spring Ring: An Inside Look at Voice Phishing
    Campaigns in Microsoft Teams'' series.'
  stage: defense-evasion-obfuscation-and-hijack
  status: out_of_scope
- reason: 'Belongs to another part of the ''Spring Ring: An Inside Look at Voice Phishing
    Campaigns in Microsoft Teams'' series.'
  stage: discovery-host-and-domain
  status: out_of_scope
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: promote-to-detection
  justification: The Spring Ring campaign targets domain controllers via NTLM relay
    after establishing a beachhead via vishing. A negative result confirms that the
    known technical execution phase has not occurred on the enrolled estate.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An attacker has deployed a custom Python environment to facilitate NTLM
  relay attacks and a PowerShell-based RAT that beacons to external command-and-control
  infrastructure.
labels:
- hunt
- attack.t1557.001
- attack.t1210
- attack.t1071.001
name: 'Spring Ring: NTLM Relay and RAT C2'
parameters:
  c2_domains:
    default:
    - san-sid.com
    description: C2 domains for the PowerShell RAT.
    from:
      kind: article
      observed: '2026-08-31'
      ref: Spring Ring
    type: list[domain]
  lookback_days:
    default: '14'
    description: Days of history to examine.
    type: number
  python_path:
    default: C:\ProgramData\IntegrityData\python.exe
    description: The specific Python path used for PetitPotam coercion.
    from:
      kind: article
      observed: '2026-08-31'
      ref: Spring Ring
    type: path
  scope_hosts:
    default: []
    description: Paste hosts from the scoping step here to narrow subsequent queries.
    type: list[host]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://unit42.paloaltonetworks.com/spring-ring-voice-phishing-campaigns/
    gates:
    - dry-run
    - lint
    model: hb_google/gemini-3-flash-preview
rationale: Start with general endpoints. If the find-custom-python step identifies
  hits, use those hostnames in the scope_hosts parameter for the scanning and C2 steps.
references:
- name: "Unit 42 \u2014 Spring Ring: An Inside Look at Voice Phishing Campaigns in\
    \ Microsoft Teams"
  url: https://unit42.paloaltonetworks.com/spring-ring-voice-phishing-campaigns/
related:
- hunt: spring-ring-initial-access-vishing
  reason: This hunt focuses on technical execution after a potential vishing breach.
  relation: follows
- hunt: teams-vishing-payload-execution
  relation: follows
scenario:
  stages:
  - name: Teams Vishing and Impersonation
    observables:
    - internalsystemsdaily.onmicrosoft.com
    - itprotectiondepartment.onmicrosoft.com
    - mandatorynetworkmonitoring.onmicrosoft.com
    - internalusahelpdeskit.onmicrosoft.com
    - certifiedupdatenetwork.onmicrosoft.com
    - infrastructureopsdesk.onmicrosoft.com
    - systemdeploymentcenter.onmicrosoft.com
    - systemsupportoperations.onmicrosoft.com
    slug: initial-access-teams-vishing
    tactic: initial-access
    techniques:
    - T1566.003
  - name: User Execution of RMM and Payloads
    observables:
    - Quick Assist
    - s3.us-west-2.amazonaws.com
    - '*-org-filters-update-*.exe'
    - san-sid.com
    slug: execution-rmm-and-custom-payloads
    tactic: execution
    techniques:
    - T1204.002
    - T1219
  - name: Staging and Persistence
    observables:
    - \Temp\vhlp-*.exe
    - \Temp\scnr-*.exe
    slug: persistence-staging-temp
    tactic: persistence
    techniques:
    - T1547
  - name: Bypassing AMSI and Browser Hijacking
    observables:
    - amsiInitFailed
    - Headless Microsoft Edge
    - Sideloaded Edge extension
    - Obfuscated PowerShell script
    slug: defense-evasion-obfuscation-and-hijack
    tactic: defense-evasion
    techniques:
    - T1027
    - T1562.001
    - T1176
  - name: Host and Domain Discovery
    observables:
    - whoami /groups
    - net group /dom
    slug: discovery-host-and-domain
    tactic: discovery
    techniques:
    - T1033
    - T1069.002
  - name: NTLM Relay and PetitPotam
    observables:
    - C:\ProgramData\IntegrityData\python.exe
    - Port 445 SMB scanning
    - PetitPotam coercion against Domain Controllers
    slug: lateral-movement-ntlm-relay
    tactic: lateral-movement
    techniques:
    - T1557.001
    - T1210
  - name: PowerShell RAT C2 Beaconing
    observables:
    - san-sid.com
    slug: command-and-control-rat
    tactic: command-and-control
    techniques:
    - T1071.001
  summary: Spring Ring is a social engineering campaign that leverages external Microsoft
    Teams accounts to impersonate IT help desks via vishing calls. Attackers coerce
    employees into running remote management tools or custom malware, leading to domain
    enumeration and NTLM relay attacks (PetitPotam) intended to compromise domain
    controllers.
series:
  index: 2
  slug: spring-ring-an-inside-look-at-voice-phishing-campaigns-in-microsoft-teams
  title: 'Spring Ring: An Inside Look at Voice Phishing Campaigns in Microsoft Teams'
  total: 2
severity: high
targets:
  analyst:
    name: Tier-2 analyst
    role: analyst
  endpoint:
    category: endpoint
    name: Endpoint telemetry (hb_ surfaces)
    telemetry:
    - endpoint
  hunter:
    agent: true
    name: Hunt agent
  network:
    category: network
    name: Network telemetry
    telemetry:
    - network
tlp: clear
type: investigation
---


# Spring Ring: NTLM Relay and RAT C2

This hunt targets the lateral movement and command-and-control phases of the Spring Ring campaign. It identifies the execution of a tailored Python interpreter used for NTLM coercion (PetitPotam) and correlates it with outbound SMB scanning and DNS resolutions for known C2 domains. By pivoting from a specific process path to network-layer behaviors, the hunt detects attempts to escalate privileges to the domain level.

## find-custom-python
<!-- Find custom Python interpreter -->
Identify hosts running the tailored Python environment used to initiate NTLM relay attacks.

```sqlite target=endpoint role=scoping params=(python_path=python_path, lookback_days=lookback_days)
~~~yaml
baseline:
  compare: first_seen
  window: '{{lookback_days}}d'
expected: A list of hosts and users executing the specific Python binary. Silence
  indicates the environment has not been deployed on any enrolled Windows endpoint.
prevalence:
  by: device_hostname
  key:
  - process_path
  rare_below: 3
reads:
- device_hostname
- process_cmd_line
- process_path
- time
- user_name
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, process_path, process_cmd_line, user_name, MIN(time) AS first_seen FROM hb_process_activity WHERE LOWER(process_path) = LOWER('{{python_path}}') AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3, 4
```

## gather-evidence
<!-- Corroborate scanning and C2 -->
parallel:
- → smb-scanning
- → c2-beaconing
join: → triage-verdict

## smb-scanning
<!-- Outbound SMB scanning on port 445 -->
Identify potential PetitPotam coercion attempts by finding hosts contacting many internal targets over SMB.

```sqlite target=network role=detection-candidate params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: A host connecting to multiple internal IP addresses on port 445. The presence
  of the suspicious python.exe as the originating process is a critical signal.
reads:
- device_hostname
- direction
- dst_endpoint_ip
- dst_endpoint_port
- process_name
- time
silence: not_evidence_of_absence
source: hb_network_connection
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, process_name, dst_endpoint_ip, COUNT(*) AS connections, MIN(time) AS first_seen FROM hb_network_connection WHERE dst_endpoint_port = 445 AND direction = 'outbound' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3 HAVING connections > 5 ORDER BY connections DESC
```

## c2-beaconing
<!-- DNS lookups for Spring Ring C2 -->
Verify if hosts are beaconing to the PowerShell RAT command-and-control infrastructure.

```sqlite target=endpoint role=enrichment params=(c2_domains=c2_domains, lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: Resolutions for the known C2 domains from the beachhead hosts. Silence means
  no DNS activity for these specific indicators was captured.
reads:
- device_hostname
- process_name
- query_hostname
- time
silence: evidence_of_absence
source: hb_dns_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, query_hostname, process_name, COUNT(*) AS lookups, MAX(time) AS last_seen FROM hb_dns_activity WHERE instr(',' || '{{c2_domains}}' || ',', ',' || LOWER(query_hostname) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3
```

## triage-verdict
<!-- Evaluate Spring Ring intrusion -->
```agent target=hunter
cite: required
context:
- find-custom-python
- smb-scanning
- c2-beaconing
max_iterations: 5
objective: Decide whether the combined evidence of custom python execution, SMB scanning,
  and C2 beaconing indicates an active Spring Ring campaign on any host.
success_criteria: A verdict of malicious for any host showing the custom python execution
  alongside scanning or C2 activity.
tools:
- endpoint
- network
```

## route-on-verdict
<!-- Route on malicious verdict -->
if~: "the triage-verdict identifies at least one host as malicious" (confidence: high, judge=hunter)
then: → isolate-host
indeterminate: → investigate-lateral-movement
unavailable: → investigate-lateral-movement (blind_spot: no-smb-visibility)
else: → cleanup-and-report

## isolate-host
<!-- Isolate host -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the host and terminate any processes running from C:\ProgramData\IntegrityData\.
```
→ investigate-lateral-movement

## investigate-lateral-movement
<!-- Forensic review of SMB scanning -->
```manual target=analyst
Examine the destination IPs from the smb-scanning step. Check Domain Controller logs for NTLM authentication attempts or coercion errors around the same time.
```
→ cleanup-and-report

## cleanup-and-report
<!-- Cleanup and report -->
```manual target=analyst
Summarize the hosts identified and the specific behaviors observed. Note any gaps in SMB visibility on servers.
```
→ end

Run it

Take this hunt into your environment.

Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.

Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.