← All hunts medium TLP:CLEAR Part 1 of 2

VSS Abuse Precursors: Exploitation and Lateral Movement

An attacker is moving laterally from a compromised internet-facing asset to locate high-value targets for VSS-based credential theft or ransomware deployment.

Based on research by Huntress 2026-09-17 9 steps · 4 queries T1003.002 T1018 T1021.001 T1021.002 T1190

Brief

The Shift from Detection to Hunting

Adversaries frequently abuse the Volume Shadow Copy Service (VSS) to facilitate credential theft via NTDS.dit or to ensure ransomware impact by deleting backups. While many detections focus on the final manipulation of VSS, Huntress's research in "How Attackers Abuse VSS, and How Huntress Detects It" (https://www.huntress.com/blog/vss-abuse-explained) highlights that these actions are often the culmination of a longer intrusion. This hunt shifts the focus upstream, identifying the precursors of VSS abuse during the exploitation and lateral movement phases.

How the Hunt Flows

The first phase of the hunt focuses on scoping the estate for high-risk beachheads. We use vulnerability finding surfaces to identify hosts with critical, unpatched vulnerabilities. These assets are prioritized because they represent the most likely entry points for an external attacker and provide context for subsequent behavioral anomalies.

In the second phase, we examine process activity for hallmarks of remote execution. Specifically, we look for command shells spawned as children of the Service Control Manager (services.exe), which is a common signature of PsExec-style lateral movement. By filtering these results against our initial list of vulnerable hosts, we can distinguish suspicious activity from routine administrative tasks performed on known, patched systems.

Simultaneously, we analyze environment reconnaissance through both process and network surfaces. We stack-count the use of session enumeration tools like qwinsta and query.exe across the fleet to find rare occurrences. We also inspect DNS activity for lookups targeting Active Directory infrastructure, such as LDAP or Kerberos service records. These lookups are essential for attackers trying to locate domain controllers for future VSS-based attacks.

The final phase synthesizes these signals. A host that is both vulnerable and exhibiting service-spawned shells or rare DNS reconnaissance is treated as a high-confidence indicator of a breach. This correlation allows us to route the finding directly to isolation or deep analyst review.

Blind Spots and Limitations

This hunt relies heavily on the availability of endpoint process logs. If a host lacks active monitoring or if the agent configuration does not capture parent-child process relationships, shells spawned via services.exe may go unobserved. Additionally, reconnaissance via DNS is highly ephemeral. If the attacker used a local resolver cache or if DNS logs are not retained long enough to cover the initial discovery window, the reconnaissance phase may be invisible.

In this series

Steps

  1. Identify High-Risk Vulnerable Assets

    Query · scoping

    Locate hosts with critical vulnerabilities that could serve as initial beachheads for an intrusion.

    reads hb_vulnerability_findingsql
    SELECT device_uid, cve_uid, severity, affected_package_name, first_seen FROM hb_vulnerability_finding WHERE severity_id >= 4 AND status != 'suppressed' AND resource_type = 'device'

    What a hit looks like. A list of hosts with unpatched high/critical vulnerabilities. Use these in the scope_hosts parameter for subsequent steps.

  2. Shells Spawned via Service Control Manager

    Query · detection candidate

    Detect the most common signature of remote administrative execution (PsExec) by identifying shells running as children of services.exe.

    reads hb_process_activitysql
    SELECT device_hostname, process_name, process_cmd_line, parent_process_name, user_name, time FROM hb_process_activity WHERE (instr(',' || '{{psexec_indicators}}' || ',', ',' || LOWER(process_name) || ',') > 0 OR (LOWER(parent_process_name) LIKE '%\\services.exe' AND instr(',' || '{{shell_interpreters}}' || ',', ',' || LOWER(process_name) || ',') > 0)) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')

    What a hit looks like. A shell like cmd.exe running as a child of services.exe on a host with critical vulnerabilities. This is a high-confidence indicator of lateral movement.

  3. Rare Session and Network Recon Tool Usage

    Query · baseline

    Stack-count administrative tools that are uncommon across the fleet, identifying manual environment exploration.

    reads hb_process_activitysql
    SELECT LOWER(process_name) AS tool, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_process_activity WHERE instr(',' || '{{recon_utilities}}' || ',', ',' || LOWER(process_name) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY tool HAVING host_count <= 3 ORDER BY host_count ASC

    What a hit looks like. Utilities like 'qwinsta' (session query) appearing on only one or two hosts, especially if those hosts are within the vulnerable scope.

  4. Internal Domain Reconnaissance via DNS

    Query · enrichment

    Identify hosts querying for Active Directory infrastructure, indicating reconnaissance prior to credential theft.

    reads hb_dns_activitysql
    SELECT device_hostname, query_hostname, COUNT(*) AS lookup_count, MIN(time) AS first_seen FROM hb_dns_activity WHERE (LOWER(query_hostname) LIKE '%_ldap._tcp.%' OR LOWER(query_hostname) LIKE '%_kerberos._tcp.%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY device_hostname, query_hostname

    What a hit looks like. Any host querying for service records to locate domain controllers, which is a required step for VSS-based NTDS.dit theft.

  5. Synthesize Breach Evidence

    Agent triage

    Correlate vulnerability scope with the behavioral results from the parallel branches.

  6. Route on Verdict

    Decision

    Route the findings based on the agent's synthesized verdict.

  7. Isolate Endpoint

    Response action

    Halt the intrusion before the adversary can manipulate VSS or extract secrets.

  8. Analyst Breach Review

    Analyst task

    Review the synthesized findings and identify the 'patient zero' exploit path.

Coverage

Scenario coverage

StageCoveredHow, or why not
Exploitation of Public-Facing Application
T1190
Yes scoping-vulnerable-targets
Lateral Movement via SMB and PsExec
T1021.002
Yes psexec-shell-spawn
Session and Network Reconnaissance
T1021.001
Yes rare-discovery-tools, dns-enumeration-lookups
Credential Access via Shadow Copy
T1490
Out of scope Belongs to another part of the 'How Attackers Abuse VSS, and How Huntress Detects It' series.
Inhibit System Recovery via Shadow Deletion
T1490
Out of scope Belongs to another part of the 'How Attackers Abuse VSS, and How Huntress Detects It' series.
Data Encrypted for Impact
T1486
Out of scope Belongs to another part of the 'How Attackers Abuse VSS, and How Huntress Detects It' series.

Blind spots

  • Needs hb_process_activity from a full endpoint agent (osquery/sysmon). A host without active process monitoring allows service-spawned shells to run entirely unobserved. It would answer Was a shell spawned that we missed due to agent configuration?.
  • Needs hb_dns_activity from a network tap or full local agent. If DNS logs are not retained or if the attacker used a local resolver cache that was flushed, the reconnaissance phase will be invisible. It would answer Did the attacker use DNS records to find DCs before the hunt window?.

Parameters & data

Parameters

ParameterTypeDefaultWhat it is
lookback_daysnumber14Days of history to examine.
psexec_indicatorslist[string]psexesvc.exe, psexec.exe, psexec64.exeBinary names associated with PsExec or similar remote execution tools.
recon_utilitieslist[string]qwinsta.exe, rwinsta.exe, query.exe, nslookup.exe, dnscmd.exeAdministrative tools used for session enumeration and network discovery.
scope_hostslist[host]Target specific hosts identified in the scoping step; leave empty for fleet-wide.
shell_interpreterslist[string]cmd.exe, powershell.exe, pwsh.exeCommon command shell interpreters.

Telemetry

SourceCategoryTelemetry
Endpoint telemetry (hb_ surfaces)endpointendpoint

Source

Download hunt.md Definition (JSON) An open hunt.md file; it runs anywhere that reads the format.
---
analysis: A single detection rule for PsExec often relies on the presence of a specific
  service name or file hash, both of which are trivial to change. This hunt looks
  for the underlying behavior (shells from services.exe) and contextualizes it with
  both vulnerability exposure and rarity (prevalence) across the fleet.
blind_spots:
- id: no-process-logs
  question: Was a shell spawned that we missed due to agent configuration?
  requires: hb_process_activity from a full endpoint agent (osquery/sysmon)
  risk: A host without active process monitoring allows service-spawned shells to
    run entirely unobserved.
  stage: lateral-movement-psexec
- id: ephemeral-dns-recon
  question: Did the attacker use DNS records to find DCs before the hunt window?
  requires: hb_dns_activity from a network tap or full local agent
  risk: If DNS logs are not retained or if the attacker used a local resolver cache
    that was flushed, the reconnaissance phase will be invisible.
  stage: internal-reconnaissance
coverage:
- stage: initial-exploitation
  status: covered
  steps:
  - scoping-vulnerable-targets
- stage: lateral-movement-psexec
  status: covered
  steps:
  - psexec-shell-spawn
- stage: internal-reconnaissance
  status: covered
  steps:
  - rare-discovery-tools
  - dns-enumeration-lookups
- reason: Belongs to another part of the 'How Attackers Abuse VSS, and How Huntress
    Detects It' series.
  stage: vss-credential-access
  status: out_of_scope
- reason: Belongs to another part of the 'How Attackers Abuse VSS, and How Huntress
    Detects It' series.
  stage: vss-recovery-inhibition
  status: out_of_scope
- reason: Belongs to another part of the 'How Attackers Abuse VSS, and How Huntress
    Detects It' series.
  stage: ransomware-encryption
  status: out_of_scope
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: keep-as-periodic-hunt
  justification: Attacker tradecraft often relies on legitimate tools (VSS, PsExec,
    qwinsta) that are used by administrators. A negative result confirms that these
    tools are operating within baseline norms across your high-risk assets, which
    is a critical signal for defensive posture.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An attacker is moving laterally from a compromised internet-facing asset
  to locate high-value targets for VSS-based credential theft or ransomware deployment.
labels:
- hunt
- attack.t1190
- attack.t1021.002
- attack.t1021.001
- attack.t1018
- attack.t1003.002
name: 'VSS Abuse Precursors: Exploitation and Lateral Movement'
parameters:
  lookback_days:
    default: '14'
    description: Days of history to examine.
    type: number
  psexec_indicators:
    default:
    - psexesvc.exe
    - psexec.exe
    - psexec64.exe
    description: Binary names associated with PsExec or similar remote execution tools.
    from:
      kind: manual
      observed: '2024-05-22'
      ref: sysinternals-indicators
    type: list[string]
  recon_utilities:
    default:
    - qwinsta.exe
    - rwinsta.exe
    - query.exe
    - nslookup.exe
    - dnscmd.exe
    description: Administrative tools used for session enumeration and network discovery.
    from:
      kind: article
      observed: '2026-09-14'
      ref: huntress-vss-abuse
    type: list[string]
  scope_hosts:
    default: []
    description: Target specific hosts identified in the scoping step; leave empty
      for fleet-wide.
    type: list[host]
  shell_interpreters:
    default:
    - cmd.exe
    - powershell.exe
    - pwsh.exe
    description: Common command shell interpreters.
    type: list[string]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://www.huntress.com/blog/vss-abuse-explained
    gates:
    - dry-run
    - lint
    model: hb_google/gemini-3-flash-preview
rationale: Start by identifying hosts with critical vulnerabilities (severity_id >=
  4) that haven't been remediated. These hosts are the most likely entry points and
  should be prioritized in the scope_hosts parameter if the fleet-wide results are
  too noisy.
references:
- name: How Attackers Abuse VSS, and How Huntress Detects It
  url: https://www.huntress.com/blog/vss-abuse-explained
related:
- hunt: vss-manipulation-and-ntds-theft
  reason: This hunt identifies the early movement; the follow-on hunt focuses specifically
    on the VSS creation/deletion and the theft of the ntds.dit file.
  relation: follows
scenario:
  stages:
  - name: Exploitation of Public-Facing Application
    observables:
    - Exploitation of internet-facing host
    - Vulnerability exploitation in web servers or databases
    slug: initial-exploitation
    tactic: initial-access
    techniques:
    - T1190
  - name: Lateral Movement via SMB and PsExec
    observables:
    - PsExec usage
    - Spawning of SYSTEM-level command shell processes
    - Activity on domain controllers
    slug: lateral-movement-psexec
    tactic: lateral-movement
    techniques:
    - T1021.002
  - name: Session and Network Reconnaissance
    observables:
    - Enumeration of active Remote Desktop sessions
    - DNS enumeration commands
    - Reconnaissance against additional network hosts
    slug: internal-reconnaissance
    tactic: discovery
    techniques:
    - T1021.001
  - name: Credential Access via Shadow Copy
    observables:
    - vssadmin create shadow
    - Extraction of ntds.dit from volume shadow copy
    slug: vss-credential-access
    tactic: credential-access
    techniques:
    - T1490
  - name: Inhibit System Recovery via Shadow Deletion
    observables:
    - vssadmin delete shadows /all /quiet
    - Deletion of shadow copies following credential extraction
    slug: vss-recovery-inhibition
    tactic: impact
    techniques:
    - T1490
  - name: Data Encrypted for Impact
    observables:
    - Mass file encryption
    - Ransomware detonation
    slug: ransomware-encryption
    tactic: impact
    techniques:
    - T1486
  summary: Attackers leverage Volume Shadow Copy (VSS) to facilitate credential theft
    by creating shadows to extract the NTDS.dit database or to inhibit recovery by
    deleting shadows prior to ransomware deployment. These techniques are often preceded
    by lateral movement using tools like PsExec and internal reconnaissance against
    domain controllers.
series:
  index: 1
  slug: how-attackers-abuse-vss-and-how-huntress-detects-it
  title: How Attackers Abuse VSS, and How Huntress Detects It
  total: 2
severity: medium
targets:
  analyst:
    name: Tier-2 analyst
    role: analyst
  endpoint:
    category: endpoint
    name: Endpoint telemetry (hb_ surfaces)
    telemetry:
    - endpoint
  hunter:
    agent: true
    name: Hunt agent
tlp: clear
type: investigation
---


# VSS Abuse Precursors: Exploitation and Lateral Movement

This hunt focuses on the early precursors of Volume Shadow Copy Service (VSS) abuse as researched by Huntress. It targets the initial transition from a web-based exploit to internal movement. By identifying vulnerable hosts, looking for the specific signature of PsExec-style remote execution (shells spawned by the Service Control Manager), and stack-counting the use of session enumeration tools, we identify attackers before they reach the destructive phase of deleting shadows or dumping Active Directory secrets. The hunt correlates these behaviors to distinguish an active breach from routine administrative disk hygiene.

## scoping-vulnerable-targets
<!-- Identify High-Risk Vulnerable Assets -->
Locate hosts with critical vulnerabilities that could serve as initial beachheads for an intrusion.

```sqlite target=endpoint role=scoping
~~~yaml
expected: A list of hosts with unpatched high/critical vulnerabilities. Use these
  in the scope_hosts parameter for subsequent steps.
reads:
- device_uid
- cve_uid
- severity
- affected_package_name
- first_seen
silence: not_evidence_of_absence
source: hb_vulnerability_finding
verified: dry-run
verified_at: '2026-09-17'
~~~
SELECT device_uid, cve_uid, severity, affected_package_name, first_seen FROM hb_vulnerability_finding WHERE severity_id >= 4 AND status != 'suppressed' AND resource_type = 'device'
```

## parallel-behavior-check
<!-- Gather Evidence of Lateral Movement and Recon -->
parallel:
- → psexec-shell-spawn
- → rare-discovery-tools
- → dns-enumeration-lookups
join: → triage-precursors

## psexec-shell-spawn
<!-- Shells Spawned via Service Control Manager -->
Detect the most common signature of remote administrative execution (PsExec) by identifying shells running as children of services.exe.

```sqlite target=endpoint role=detection-candidate params=(psexec_indicators=psexec_indicators, shell_interpreters=shell_interpreters, scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
expected: A shell like cmd.exe running as a child of services.exe on a host with critical
  vulnerabilities. This is a high-confidence indicator of lateral movement.
reads:
- device_hostname
- process_name
- process_cmd_line
- parent_process_name
- user_name
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-17'
~~~
SELECT device_hostname, process_name, process_cmd_line, parent_process_name, user_name, time FROM hb_process_activity WHERE (instr(',' || '{{psexec_indicators}}' || ',', ',' || LOWER(process_name) || ',') > 0 OR (LOWER(parent_process_name) LIKE '%\\services.exe' AND instr(',' || '{{shell_interpreters}}' || ',', ',' || LOWER(process_name) || ',') > 0)) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## rare-discovery-tools
<!-- Rare Session and Network Recon Tool Usage -->
Stack-count administrative tools that are uncommon across the fleet, identifying manual environment exploration.

```sqlite target=endpoint role=baseline params=(recon_utilities=recon_utilities, scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
baseline:
  compare: first_seen
  window: '{{lookback_days}}d'
expected: Utilities like 'qwinsta' (session query) appearing on only one or two hosts,
  especially if those hosts are within the vulnerable scope.
prevalence:
  by: device_hostname
  key:
  - tool
  rare_below: 3
reads:
- process_name
- device_hostname
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-17'
~~~
SELECT LOWER(process_name) AS tool, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_process_activity WHERE instr(',' || '{{recon_utilities}}' || ',', ',' || LOWER(process_name) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY tool HAVING host_count <= 3 ORDER BY host_count ASC
```

## dns-enumeration-lookups
<!-- Internal Domain Reconnaissance via DNS -->
Identify hosts querying for Active Directory infrastructure, indicating reconnaissance prior to credential theft.

```sqlite target=endpoint role=enrichment params=(scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
expected: Any host querying for service records to locate domain controllers, which
  is a required step for VSS-based NTDS.dit theft.
reads:
- device_hostname
- query_hostname
- time
silence: not_evidence_of_absence
source: hb_dns_activity
verified: dry-run
verified_at: '2026-09-17'
~~~
SELECT device_hostname, query_hostname, COUNT(*) AS lookup_count, MIN(time) AS first_seen FROM hb_dns_activity WHERE (LOWER(query_hostname) LIKE '%_ldap._tcp.%' OR LOWER(query_hostname) LIKE '%_kerberos._tcp.%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY device_hostname, query_hostname
```

## triage-precursors
<!-- Synthesize Breach Evidence -->
```agent target=hunter
cite: required
context:
- scoping-vulnerable-targets
- psexec-shell-spawn
- rare-discovery-tools
- dns-enumeration-lookups
max_iterations: 3
objective: Determine if any host identified as vulnerable is also exhibiting signs
  of lateral movement via PsExec or manual environment reconnaissance.
success_criteria: A verdict of malicious | suspicious | benign citing the intersection
  of vulnerability data and behavioral rows.
tools:
- endpoint
```

## route-on-verdict
<!-- Route on Verdict -->
if~: "the triage verdict is malicious for at least one host involving PsExec shell behavior" (confidence: high, judge=hunter)
then: → isolate-beachhead
indeterminate: → analyst-confirmation
unavailable: → analyst-confirmation (blind_spot: no-process-logs)
else: → analyst-confirmation

## isolate-beachhead
<!-- Isolate Endpoint -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the affected host(s) and capture the memory of any active service-spawned shells for forensic analysis.
```
→ analyst-confirmation

## analyst-confirmation
<!-- Analyst Breach Review -->
```manual target=analyst
Examine hb_http_activity for the affected hosts to identify the specific URL or request that triggered the initial compromise. Compare timestamps of the vulnerability being first seen with the appearance of the PsExec behavior.
```
→ 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.