---
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
