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
-
Find custom Python interpreter
Query · scopingIdentify hosts running the tailored Python environment used to initiate NTLM relay attacks.
reads hb_process_activitysqlSELECT 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, 4What 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.
-
Outbound SMB scanning on port 445
Query · detection candidateIdentify potential PetitPotam coercion attempts by finding hosts contacting many internal targets over SMB.
reads hb_network_connectionsqlSELECT 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 DESCWhat 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.
-
DNS lookups for Spring Ring C2
Query · enrichmentVerify if hosts are beaconing to the PowerShell RAT command-and-control infrastructure.
reads hb_dns_activitysqlSELECT 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, 3What 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.
-
Evaluate Spring Ring intrusion
Agent triageCorrelate the findings from all three surfaces to determine if a host is compromised and attempting lateral movement.
-
Route on malicious verdict
DecisionDirect the hunt to containment or manual review based on the agent's findings.
-
Isolate host
Response actionSever the attacker's connection and prevent further lateral movement attempts.
-
Forensic review of SMB scanning
Analyst taskVerify the targets of the SMB scanning to confirm if Domain Controllers were targeted.
-
Cleanup and report
Analyst taskDocument the findings and close the hunt.
Coverage
Scenario coverage
| Stage | Covered | How, 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
| Parameter | Type | Default | What it is |
|---|---|---|---|
c2_domains | list[domain] | san-sid.com | C2 domains for the PowerShell RAT. |
lookback_days | number | 14 | Days of history to examine. |
python_path | path | C:\ProgramData\IntegrityData\python.exe | The specific Python path used for PetitPotam coercion. |
scope_hosts | list[host] | — | Paste hosts from the scoping step here to narrow subsequent queries. |
Telemetry
| Source | Category | Telemetry |
|---|---|---|
| Endpoint telemetry (hb_ surfaces) | endpoint | endpoint |
| Network telemetry | network | network |
Source
---
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.