← All hunts high TLP:CLEAR Part 1 of 2

APT28: Outlook and Print Spooler Exploitation

An adversary is exploiting unpatched Outlook or Print Spooler vulnerabilities to harvest NTLM credentials or escalate privileges, evidenced by outbound SMB connections to external IPs and rare child processes launched by the spooler service.

Based on research by Sekoia 2026-09-28 12 steps · 4 queries T1041 T1190 T1555 T1566

Brief

Why now

Recent reporting from Sekoia, APT28: An Evolution of Tradecraft from X-Agent to LLM Malware, highlights how this adversary has shifted from bespoke malware to the exploitation of N-day vulnerabilities and common administrative tools. This hunt specifically addresses their use of CVE-2023-23397 (Outlook) and CVE-2022-38028 (Print Spooler) to move laterally and escalate privileges within target environments.

How the hunt flows

The hunt starts by identifying endpoints vulnerable to the specific CVEs weaponized by APT28. A lead query checks the vulnerability inventory for unpatched versions of Outlook and the Print Spooler service. This step scopes the hunt, ensuring that subsequent expensive queries only run against systems with a confirmed attack surface.

Once the hunt identifies vulnerable hosts, it gates the process. An analyst or automated agent reviews the findings to decide if the environment is exposed enough to warrant a deep dive. If vulnerable hosts exist, the hunt triggers three parallel behavioral checks across network and process telemetry.

The network phase looks for outbound SMB connections on port 445. When an adversary exploits the Outlook vulnerability, the client often attempts to authenticate against an external server, leaking Net-NTLMv2 hashes. The query filters for outbound traffic to identify these relay attempts.

The process phase baselines the Print Spooler service. It searches for rare child processes of spoolsv.exe, which is the primary indicator of the GooseEgg privilege escalation utility. The query uses a frequency analysis to ignore common printing utilities and highlight anomalies.

The final enrichment phase searches DNS logs for lookups involving spoofed phishing domains, such as ukr.net. This helps link the exploitation activity back to the initial access campaigns observed in recent APT28 operations.

What this hunt cannot see

This hunt relies on an accurate vulnerability inventory. If a host is unmanaged or the vulnerability scanner misses an endpoint, the scoping step will fail to include it. Host-based network logging is also required to see outbound SMB traffic; without port 445 visibility, the NTLM relay activity remains invisible. Finally, privilege escalation on a host without an endpoint agent will leave no process telemetry for the spooler check.

In this series

Steps

  1. Identify vulnerable hosts

    Query · scoping

    Identify endpoints that are vulnerable to the specific CVEs APT28 is known to weaponize.

    reads hb_vulnerability_findingsql
    SELECT device_uid, cve_uid, severity, affected_package_name, affected_package_version FROM hb_vulnerability_finding WHERE instr(',' || '{{target_cves}}' || ',', ',' || cve_uid || ',') > 0

    What a hit looks like. A list of device UIDs that remain unpatched. Zero rows prove the estate is patched against these specific flaws.

  2. Assess vulnerability lead

    Agent triage

    Determine if the vulnerability findings warrant a deep dive into behavioural logs.

  3. Gate on vulnerability presence

    Decision

    Route the hunt to the expensive behavioural queries only if vulnerable hosts are confirmed.

  4. Outbound SMB connections from endpoints

    Query · enrichment

    Detect potential NTLM hash harvesting triggered by Outlook reminder exploitation.

    reads hb_network_connectionsql
    SELECT device_hostname, process_name, dst_endpoint_ip, dst_endpoint_port, time FROM hb_network_connection WHERE dst_endpoint_port = 445 AND direction = 'outbound' AND time >= datetime('now', '-{{lookback_days}} days') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0)

    What a hit looks like. Network connections to port 445 on external IP addresses; silence proves no unauthenticated SMB traffic left the scope.

  5. Rare child processes of Print Spooler

    Query · detection candidate

    Detect the use of GooseEgg by identifying anomalous children of the Spooler service.

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

    What a hit looks like. Rare processes launched by spoolsv.exe; fleet-wide printing utilities will be filtered by the HAVING clause.

  6. Lookups for ukr.net phishing indicators

    Query · enrichment

    Identify activity related to the spoofed webmail portal used in recent campaigns.

    reads hb_dns_activitysql
    SELECT device_hostname, process_name, query_hostname, time FROM hb_dns_activity WHERE instr(',' || '{{ukr_net_domain}}' || ',', ',' || LOWER(query_hostname) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0)

    What a hit looks like. Any resolution of the targeted phishing domain on an endpoint.

  7. Synthesize exploitation evidence

    Agent triage

    Correlate the vulnerability findings with the network and process indicators to confirm exploitation.

  8. Route based on triage verdict

    Decision

    Initiate response for confirmed compromises or refer ambiguous cases to an analyst.

  9. Isolate compromised host

    Response action

    Contain the threat and prevent further lateral movement or credential abuse.

  10. Manual analyst review

    Analyst task

    Verify the findings and perform deeper forensic analysis.

  11. Close out hunt

    Analyst task

    Finalize the hunt and record the state of the estate.

Coverage

Scenario coverage

StageCoveredHow, or why not
Initial Access via Phishing and Vulnerabilities
T1566 · T1190
Yes lead-vulnerability-check, ukr-net-phishing-lookups
Privilege Escalation via GooseEgg
T1190
Yes spooler-privesc-baseline
Net-NTLMv2 Hash Harvesting
T1555
Yes outbound-smb-relay
Infrastructure Hijacking on Edge Devices
T1572
Out of scope Belongs to another part of the 'APT28: An Evolution of Tradecraft from X-Agent to LLM Malware' series.
LLM-Integrated Data Exfiltration
T1041
Out of scope Belongs to another part of the 'APT28: An Evolution of Tradecraft from X-Agent to LLM Malware' series.

Blind spots

  • Needs Comprehensive hb_vulnerability_finding coverage. An unmanaged host could be exploited without being caught in the lead query. It would answer Are there vulnerable hosts not currently reporting to the vulnerability scanner?. Remediation: Audit the overlap between hb_devices and hb_vulnerability_finding to identify missing assets.
  • Needs hb_network_connection with port 445 logging. Exfiltration or hash relay attempts using SMB could be missed if host-based network logging is disabled. It would answer Can we see outbound SMB traffic from every network segment?. Remediation: Ensure outbound SMB traffic is logged and alert on external port 445 connections.
  • Needs Endpoint agent on all Windows systems. Privilege escalation via GooseEgg on a host without an agent would leave no behavioural trace. It would answer Do we have process telemetry for the entire Windows estate?. Remediation: Deploy agents to all Windows servers and workstations.

Parameters & data

Parameters

ParameterTypeDefaultWhat it is
lookback_daysnumber14Days of history to examine.
scope_hostslist[host]—Hostnames identified in the scoping step to focus the behavioural search.
target_cveslist[string]CVE-2023-23397, CVE-2022-38028CVE identifiers targeted by APT28 for initial access and privilege escalation.
ukr_net_domainlist[domain]ukr.netThe phishing target domain spoofed in APT28 campaigns.

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 standard rule fires on a known CVE or a static IP; this hunt correlates
  the presence of unpatched vulnerabilities with behavioural anomalies (rare process
  children, outbound SMB) across multiple telemetry surfaces, providing context a
  single rule cannot provide.
blind_spots:
- id: vulnerability-inventory-gap
  owner: Vulnerability Management Team
  question: Are there vulnerable hosts not currently reporting to the vulnerability
    scanner?
  remediation: Audit the overlap between hb_devices and hb_vulnerability_finding to
    identify missing assets.
  requires: Comprehensive hb_vulnerability_finding coverage
  risk: An unmanaged host could be exploited without being caught in the lead query.
  stage: initial-access-phishing-and-vulnerability-exploitation
- id: network-outbound-visibility
  owner: Network Security Team
  question: Can we see outbound SMB traffic from every network segment?
  remediation: Ensure outbound SMB traffic is logged and alert on external port 445
    connections.
  requires: hb_network_connection with port 445 logging
  risk: Exfiltration or hash relay attempts using SMB could be missed if host-based
    network logging is disabled.
  stage: credential-harvesting-ntlm-relay
- id: no-agent-coverage
  owner: Endpoint Engineering
  question: Do we have process telemetry for the entire Windows estate?
  remediation: Deploy agents to all Windows servers and workstations.
  requires: Endpoint agent on all Windows systems
  risk: Privilege escalation via GooseEgg on a host without an agent would leave no
    behavioural trace.
  stage: privilege-escalation-gooseegg
coverage:
- stage: initial-access-phishing-and-vulnerability-exploitation
  status: covered
  steps:
  - lead-vulnerability-check
  - ukr-net-phishing-lookups
- stage: privilege-escalation-gooseegg
  status: covered
  steps:
  - spooler-privesc-baseline
- stage: credential-harvesting-ntlm-relay
  status: covered
  steps:
  - outbound-smb-relay
- reason: 'Belongs to another part of the ''APT28: An Evolution of Tradecraft from
    X-Agent to LLM Malware'' series.'
  stage: c2-edge-device-hijacking
  status: out_of_scope
- reason: 'Belongs to another part of the ''APT28: An Evolution of Tradecraft from
    X-Agent to LLM Malware'' series.'
  stage: exfiltration-llm-infostealer
  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: APT28 has demonstrated a decade of persistence in weaponizing zero-day
    and unpatched vulnerabilities for credential theft and privilege escalation. Identifying
    active exploitation through behaviour is required to catch intrusions that occur
    between patching cycles.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An adversary is exploiting unpatched Outlook or Print Spooler vulnerabilities
  to harvest NTLM credentials or escalate privileges, evidenced by outbound SMB connections
  to external IPs and rare child processes launched by the spooler service.
labels:
- hunt
- attack.t1190
- attack.t1566
- attack.t1555
- attack.t1041
name: 'APT28: Outlook and Print Spooler Exploitation'
parameters:
  lookback_days:
    default: '14'
    description: Days of history to examine.
    from:
      kind: manual
      observed: '2026-06-22'
      ref: standard-retention
    type: number
  scope_hosts:
    default: []
    description: Hostnames identified in the scoping step to focus the behavioural
      search.
    from:
      kind: manual
      observed: '2026-06-22'
      ref: scoping-input
    type: list[host]
  target_cves:
    default:
    - CVE-2023-23397
    - CVE-2022-38028
    description: CVE identifiers targeted by APT28 for initial access and privilege
      escalation.
    from:
      kind: article
      observed: '2026-06-22'
      ref: sekoia-apt28-evolution
    type: list[string]
  ukr_net_domain:
    default:
    - ukr.net
    description: The phishing target domain spoofed in APT28 campaigns.
    from:
      kind: article
      observed: '2026-06-22'
      ref: sekoia-apt28-evolution
    type: list[domain]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://www.sekoia.com/blog/apt28-an-evolution-of-tradecraft
    gates:
    - dry-run
    - lint
    - critic
    model: hb_google/gemini-3-flash-preview
rationale: The hunt should prioritize endpoints that are identified as vulnerable
  to the target CVEs. If vulnerability scanning coverage is incomplete, widen the
  scope to all Windows workstations and servers during the deep-dive phase.
references:
- name: "Sekoia \u2014 APT28: An Evolution of Tradecraft"
  url: https://www.sekoia.com/blog/apt28-an-evolution-of-tradecraft
related:
- hunt: apt28-edge-device-hijacking
  reason: Edge device hijacking (MooBot/FrostArmada) targets router infrastructure
    rather than endpoint software and is handled in a separate hunt.
  relation: out-of-scope-alternative
scenario:
  stages:
  - name: Initial Access via Phishing and Vulnerabilities
    observables:
    - CVE-2023-23397 (Outlook)
    - CVE-2022-38028 (Windows Print Spooler)
    - SedKit exploit kit
    - Spear phishing emails
    - UKR.NET phishing landing pages
    slug: initial-access-phishing-and-vulnerability-exploitation
    tactic: initial-access
    techniques:
    - T1566
    - T1190
  - name: Privilege Escalation via GooseEgg
    observables:
    - GooseEgg utility
    - Windows Print Spooler service exploitation
    - SYSTEM-level execution
    slug: privilege-escalation-gooseegg
    tactic: execution
    techniques:
    - T1190
  - name: Net-NTLMv2 Hash Harvesting
    observables:
    - Net-NTLMv2 hashes
    - Authentication to attacker-controlled SMB shares
    - Crafted Outlook reminders
    - Spoofed UKR.NET webmail portal
    slug: credential-harvesting-ntlm-relay
    tactic: credential-access
    techniques:
    - T1555
  - name: Infrastructure Hijacking on Edge Devices
    observables:
    - MooBot botnet
    - FrostArmada campaign
    - Ubiquiti EdgeRouters
    - MikroTik and TP-Link routers
    - Rewritten DNS/DHCP settings pointing to actor-controlled resolvers
    - X-Tunnel network pivot
    slug: c2-edge-device-hijacking
    tactic: command-and-control
    techniques:
    - T1572
  - name: LLM-Integrated Data Exfiltration
    observables:
    - LLM-integrated infostealer
    - Harvesting Office, PDF, and TXT documents
    - Commands generated by legitimate AI services
    slug: exfiltration-llm-infostealer
    tactic: exfiltration
    techniques:
    - T1041
  summary: APT28 (Fancy Bear) has transitioned from a decade-long reliance on a stable
    in-house implant suite like X-Agent to a highly fragmented, disposable toolkit
    and extensive infrastructure hijacking. The actor currently weaponizes edge devices
    such as Ubiquiti and MikroTik routers for proxying traffic and harvesting credentials,
    while integrating LLM-driven malware for automated document exfiltration.
series:
  index: 1
  slug: apt28-an-evolution-of-tradecraft-from-x-agent-to-llm-malware
  title: 'APT28: An Evolution of Tradecraft from X-Agent to LLM Malware'
  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
---


# APT28: Outlook and Print Spooler Exploitation

This hunt targets the endpoint-resident tradecraft of APT28, specifically focusing on the exploitation of CVE-2023-23397 (Outlook) and CVE-2022-38028 (Print Spooler). The hunt begins with a low-cost lead query to identify vulnerable hosts. If found, it triggers an expensive fan-out to search for active indicators: Net-NTLMv2 hash harvesting via forced SMB authentication, the GooseEgg privilege escalation utility, and lookups for known phishing domains. By correlating vulnerability state with behavioural indicators like rare spooler child processes and outbound SMB traffic, the hunt identifies active intrusions that standard signature-based rules may miss.

## lead-vulnerability-check
<!-- Identify vulnerable hosts -->
Identify endpoints that are vulnerable to the specific CVEs APT28 is known to weaponize.

```sqlite target=endpoint role=scoping params=(target_cves=target_cves)
~~~yaml
expected: A list of device UIDs that remain unpatched. Zero rows prove the estate
  is patched against these specific flaws.
reads:
- affected_package_name
- affected_package_version
- cve_uid
- device_uid
- severity
silence: evidence_of_absence
source: hb_vulnerability_finding
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT device_uid, cve_uid, severity, affected_package_name, affected_package_version FROM hb_vulnerability_finding WHERE instr(',' || '{{target_cves}}' || ',', ',' || cve_uid || ',') > 0
```

## agent-lead-assessment
<!-- Assess vulnerability lead -->
```agent target=hunter
cite: required
context:
- lead-vulnerability-check
max_iterations: 3
objective: Review the vulnerability findings and decide if the environment is exposed
  enough to continue the hunt for exploitation.
success_criteria: A recommendation to either start the deep dive or close the hunt.
tools:
- endpoint
- network
```

## gate-on-vulnerability
<!-- Gate on vulnerability presence -->
if~: "the lead assessment confirms that at least one host is unpatched for the target CVEs" (confidence: high, judge=hunter)
then: → deep-dive
indeterminate: → task-manual-review
unavailable: → task-manual-review (blind_spot: vulnerability-inventory-gap)
else: → task-close-out

## deep-dive
<!-- Fan-out behavioural analysis -->
parallel:
- → outbound-smb-relay
- → spooler-privesc-baseline
- → ukr-net-phishing-lookups
join: → agent-triage-results

## outbound-smb-relay
<!-- Outbound SMB connections from endpoints -->
Detect potential NTLM hash harvesting triggered by Outlook reminder exploitation.

```sqlite target=network role=enrichment params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: Network connections to port 445 on external IP addresses; silence proves
  no unauthenticated SMB traffic left the scope.
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-28'
~~~
SELECT device_hostname, process_name, dst_endpoint_ip, dst_endpoint_port, time FROM hb_network_connection WHERE dst_endpoint_port = 445 AND direction = 'outbound' AND time >= datetime('now', '-{{lookback_days}} days') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0)
```

## spooler-privesc-baseline
<!-- Rare child processes of Print Spooler -->
Detect the use of GooseEgg by identifying anomalous children of the Spooler service.

```sqlite target=endpoint role=detection-candidate params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
baseline:
  compare: first_seen
  window: '{{lookback_days}}d'
expected: Rare processes launched by spoolsv.exe; fleet-wide printing utilities will
  be filtered by the HAVING clause.
prevalence:
  by: device_hostname
  key:
  - process_name
  rare_below: 3
reads:
- device_hostname
- parent_process_name
- process_name
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT LOWER(process_name) AS proc, COUNT(DISTINCT device_hostname) AS host_count, MIN(time) AS first_seen FROM hb_process_activity WHERE LOWER(parent_process_name) LIKE '%spoolsv.exe' AND time >= datetime('now', '-{{lookback_days}} days') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) GROUP BY proc HAVING host_count <= 3 ORDER BY host_count ASC
```

## ukr-net-phishing-lookups
<!-- Lookups for ukr.net phishing indicators -->
Identify activity related to the spoofed webmail portal used in recent campaigns.

```sqlite target=endpoint role=enrichment params=(lookback_days=lookback_days, ukr_net_domain=ukr_net_domain, scope_hosts=scope_hosts)
~~~yaml
expected: Any resolution of the targeted phishing domain on an endpoint.
reads:
- device_hostname
- process_name
- query_hostname
- time
silence: not_evidence_of_absence
source: hb_dns_activity
verified: dry-run
verified_at: '2026-09-28'
~~~
SELECT device_hostname, process_name, query_hostname, time FROM hb_dns_activity WHERE instr(',' || '{{ukr_net_domain}}' || ',', ',' || LOWER(query_hostname) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0)
```

## agent-triage-results
<!-- Synthesize exploitation evidence -->
```agent target=hunter
cite: required
context:
- agent-lead-assessment
- outbound-smb-relay
- spooler-privesc-baseline
- ukr-net-phishing-lookups
max_iterations: 6
objective: Determine if any host is exhibiting signs of active APT28 exploitation,
  such as GooseEgg execution or NTLM relay activity, and weight the risk for each
  host.
success_criteria: A per-host verdict of compromised, suspicious, or benign with supporting
  citations.
tools:
- endpoint
- network
```

## decision-route-verdict
<!-- Route based on triage verdict -->
if~: "the triage verdict identifies at least one compromised host with active exploitation indicators" (confidence: high, judge=hunter)
then: → action-isolate-host
indeterminate: → task-manual-review
unavailable: → task-manual-review (blind_spot: no-agent-coverage)
else: → task-manual-review

## action-isolate-host
<!-- Isolate compromised host -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the host immediately. Revoke all active sessions for the user account identified in the triage.
```
→ task-manual-review

## task-manual-review
<!-- Manual analyst review -->
```manual target=analyst
Review the cited rows. Inspect the host for the presence of the GooseEgg utility or unusual SMB client activity. Check for Net-NTLMv2 hash relay attempts in identity provider logs.
```
→ task-close-out

## task-close-out
<!-- Close out hunt -->
```manual target=analyst
Document the vulnerable vs patched state of the estate. Recommend a standing rule for rare spoolsv.exe children if successful.
```
→ 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, critic, then reviewed by a person.