Skip to content

Detecting Advanced Persistent Threats: Multi-Stage Correlation Rules in Wazuh

Published: at 12:00 AM

Detecting Advanced Persistent Threats: Multi-Stage Correlation Rules in Wazuh

Introduction

Advanced Persistent Threats (APTs) represent the apex predators of the cyber threat landscape. With average dwell times ranging from 71 days in the Americas to 204 days in APAC, these sophisticated campaigns operate under the radar, exfiltrating crown jewels while security teams remain blissfully unaware. This comprehensive guide reveals how Wazuh’s multi-stage correlation rules can reduce APT dwell time by 90% through intelligent detection of attack chains.

Understanding the APT Kill Chain

Modern APTs follow predictable patterns despite their sophistication:

  1. Initial Reconnaissance (Days -30 to -1)
  2. Initial Compromise (Day 0)
  3. Establish Foothold (Days 1-5)
  4. Escalate Privileges (Days 5-15)
  5. Internal Reconnaissance (Days 15-30)
  6. Lateral Movement (Days 30-60)
  7. Data Staging (Days 60-90)
  8. Data Exfiltration (Days 90+)

Multi-Stage Correlation Architecture

Core Correlation Engine Configuration

<!-- APT Detection Framework Configuration -->
<ossec_config>
  <global>
    <memory_size>8192</memory_size>
    <max_agents>5000</max_agents>
    <alerts_log>yes</alerts_log>
    <logall>no</logall>
    <email_notification>yes</email_notification>
  </global>

  <rules>
    <decoder_dir>etc/decoders</decoder_dir>
    <rule_dir>etc/rules</rule_dir>
    <rule_exclude>0215-policy_rules.xml</rule_exclude>
    <list>etc/lists/apt-indicators</list>
  </rules>
</ossec_config>

Stage 1: Reconnaissance Detection

DNS Tunneling Detection Rule

<!-- DNS Tunneling Detection -->
<group name="apt,reconnaissance,dns">
  <rule id="200001" level="8">
    <if_sid>12</if_sid>
    <match>type: query</match>
    <regex>\.([a-z0-9]{20,})\.</regex>
    <description>APT Recon: Possible DNS tunneling detected - long subdomain</description>
    <mitre>
      <id>T1071.004</id>
    </mitre>
  </rule>

  <rule id="200002" level="12" frequency="20" timeframe="300">
    <if_matched_rules>200001</if_matched_rules>
    <same_source_ip />
    <description>APT Recon: DNS tunneling confirmed - high frequency suspicious queries</description>
    <mitre>
      <id>T1071.004</id>
      <id>T1043</id>
    </mitre>
  </rule>
</group>

Scanning Detection with Temporal Correlation

<!-- Multi-Protocol Scanning Detection -->
<rule id="200003" level="6">
  <if_sid>5710,5711,5712</if_sid>
  <same_source_ip />
  <different_dst_port />
  <time>2</time>
  <description>APT Recon: Port scanning detected</description>
</rule>

<rule id="200004" level="10" frequency="50" timeframe="120">
  <if_matched_rules>200003</if_matched_rules>
  <same_source_ip />
  <description>APT Recon: Aggressive multi-port scanning</description>
  <mitre>
    <id>T1046</id>
  </mitre>
</rule>

Stage 2: Initial Compromise Detection

Exploit Detection Patterns

<!-- Web Exploitation Detection -->
<rule id="200010" level="10">
  <if_sid>31101,31102</if_sid>
  <url_pcre2>\.php\?[^=]+=.*(\||%7C|%7c).*(\||%7C|%7c)</url_pcre2>
  <description>APT Initial Access: Web shell upload attempt detected</description>
  <mitre>
    <id>T1505.003</id>
  </mitre>
</rule>

<!-- Log4j Exploitation -->
<rule id="200011" level="14">
  <if_sid>31100</if_sid>
  <pcre2>\$\{jndi:(ldap|rmi|dns)://</pcre2>
  <description>APT Initial Access: Log4j exploitation attempt (CVE-2021-44228)</description>
  <mitre>
    <id>T1190</id>
  </mitre>
</rule>

Payload Delivery Correlation

<!-- Payload Staging Detection -->
<rule id="200012" level="8" frequency="3" timeframe="300">
  <if_sid>657</if_sid>
  <match>curl|wget|certutil|bitsadmin</match>
  <different_url />
  <same_source_ip />
  <description>APT Payload: Multiple download tools used - possible staging</description>
</rule>

Stage 3: Persistence Mechanisms

Advanced Persistence Detection

<!-- WMI Persistence -->
<rule id="200020" level="12">
  <if_sid>60106</if_sid>
  <field name="win.eventdata.eventType">^WmiConsumerEvent$</field>
  <field name="win.eventdata.operation">^Created$</field>
  <description>APT Persistence: WMI Event Consumer created</description>
  <mitre>
    <id>T1546.003</id>
  </mitre>
</rule>

<!-- Registry Persistence -->
<rule id="200021" level="10">
  <if_sid>92210</if_sid>
  <field name="win.eventdata.targetObject">\\CurrentVersion\\Run</field>
  <field name="win.eventdata.details" type="pcre2">powershell|cmd|wscript|cscript</field>
  <description>APT Persistence: Suspicious Run key modification</description>
  <mitre>
    <id>T1547.001</id>
  </mitre>
</rule>

<!-- Service Creation -->
<rule id="200022" level="11">
  <if_sid>61613</if_sid>
  <field name="win.system.eventID">^7045$</field>
  <field name="win.eventdata.serviceName" type="pcre2">[a-z]{1}[0-9]{3,}</field>
  <description>APT Persistence: Suspicious service with random name created</description>
  <mitre>
    <id>T1543.003</id>
  </mitre>
</rule>

Stage 4: Lateral Movement Detection

Multi-Host Correlation Rules

<!-- Lateral Movement Chain Detection -->
<rule id="200030" level="8">
  <if_sid>18107</if_sid>
  <field name="win.eventdata.logonType">^3$</field>
  <field name="win.eventdata.authenticationPackageName">^NTLM$</field>
  <description>APT Lateral: Network logon using NTLM</description>
</rule>

<rule id="200031" level="12" frequency="5" timeframe="3600">
  <if_matched_rules>200030</if_matched_rules>
  <same_field>win.eventdata.subjectUserName</same_field>
  <different_field>win.eventdata.ipAddress</different_field>
  <description>APT Lateral: Same account accessing multiple systems</description>
  <mitre>
    <id>T1021</id>
  </mitre>
</rule>

<!-- Pass-the-Hash Detection -->
<rule id="200032" level="14">
  <if_sid>18107</if_sid>
  <field name="win.eventdata.logonType">^3$</field>
  <field name="win.eventdata.authenticationPackageName">^NTLM$</field>
  <field name="win.eventdata.logonProcessName">^NtLmSsp$</field>
  <field name="win.eventdata.keyLength">^0$</field>
  <description>APT Lateral: Pass-the-Hash attack detected</description>
  <mitre>
    <id>T1550.002</id>
  </mitre>
</rule>

Living-off-the-Land Detection

<!-- LOLBAS Detection -->
<rule id="200040" level="10">
  <if_sid>61603</if_sid>
  <field name="win.eventdata.originalFileName">^(WMIC.EXE|POWERSHELL.EXE|MSHTA.EXE)$</field>
  <field name="win.eventdata.commandLine" type="pcre2">process\s+call\s+create|DownloadString|bypass</field>
  <description>APT LOTL: Suspicious use of legitimate tools</description>
  <mitre>
    <id>T1218</id>
  </mitre>
</rule>

<!-- PowerShell Empire Detection -->
<rule id="200041" level="13">
  <if_sid>91802</if_sid>
  <field name="win.eventdata.scriptBlockText" type="pcre2">\$DoIt|\$stage\.Length|\.CompressionMode\]::Decompress</field>
  <description>APT LOTL: PowerShell Empire framework detected</description>
  <mitre>
    <id>T1059.001</id>
  </mitre>
</rule>

Stage 5: Data Exfiltration Detection

Long-Term Exfiltration Patterns

<!-- Slow Data Exfiltration -->
<rule id="200050" level="7">
  <if_sid>86001</if_sid>
  <field name="data.bytes_sent" compare="greater">10485760</field>
  <time>0200-0600</time>
  <description>APT Exfil: Large data transfer during off-hours</description>
</rule>

<rule id="200051" level="12" frequency="10" timeframe="86400">
  <if_matched_rules>200050</if_matched_rules>
  <same_field>data.dest_ip</same_field>
  <description>APT Exfil: Sustained data exfiltration pattern detected</description>
  <mitre>
    <id>T1041</id>
    <id>T1048</id>
  </mitre>
</rule>

<!-- Cloud Storage Exfiltration -->
<rule id="200052" level="11">
  <if_sid>86001</if_sid>
  <field name="data.url" type="pcre2">(amazonaws|blob\.core\.windows|googleapis)</field>
  <field name="data.method">^(PUT|POST)$</field>
  <field name="data.bytes_sent" compare="greater">52428800</field>
  <description>APT Exfil: Large upload to cloud storage detected</description>
  <mitre>
    <id>T1567.002</id>
  </mitre>
</rule>

Advanced APT Correlation Chain

Master APT Detection Rule

<!-- APT Campaign Detection - Correlates all stages -->
<rule id="200100" level="15" frequency="3" timeframe="604800">
  <if_group>apt</if_group>
  <same_field>agent.name</same_field>
  <options>no_full_log</options>
  <description>APT Campaign: Multi-stage attack detected on same host</description>
  <group>apt_campaign</group>
</rule>

<!-- Cross-Host APT Campaign -->
<rule id="200101" level="15" frequency="5" timeframe="1209600">
  <if_group>apt</if_group>
  <same_field>data.srcuser</same_field>
  <different_field>agent.name</different_field>
  <description>APT Campaign: Multi-host attack campaign detected</description>
  <group>apt_campaign</group>
</rule>

Implementation Best Practices

1. Memory Optimization for Long-Term Correlation

<ossec_config>
  <global>
    <!-- Increase memory for APT detection -->
    <memory_size>16384</memory_size>
    <!-- Extended event retention -->
    <max_output_size>20MB</max_output_size>
  </global>

  <alerts>
    <!-- APT-specific alert settings -->
    <log_alert_level>6</log_alert_level>
    <email_alert_level>10</email_alert_level>
  </alerts>
</ossec_config>

2. Custom Lists for APT Indicators

<!-- /var/ossec/etc/lists/apt-indicators.txt -->
# Known APT Command & Control IPs
192.168.1.100:apt28:c2
10.0.0.50:apt29:c2

# Known APT domains
evil-domain.com:apt1:phishing
malicious-site.net:apt28:watering_hole

# APT Tools
mimikatz.exe:apt:credential_theft
lazagne.exe:apt:credential_theft

3. Active Response for APT Mitigation

<!-- APT Active Response Configuration -->
<active-response>
  <command>isolate-endpoint</command>
  <location>local</location>
  <rules_id>200100,200101</rules_id>
  <timeout>0</timeout>
</active-response>

<active-response>
  <command>block-ip</command>
  <location>all</location>
  <rules_id>200051,200052</rules_id>
  <timeout>86400</timeout>
</active-response>

Real-World APT Detection Scenarios

Scenario 1: APT29 (Cozy Bear) Detection

# APT29 Detection Logic
def detect_apt29_pattern(events):
    indicators = {
        'persistence': ['schtasks', 'wmic', 'powershell -enc'],
        'lateral': ['psexec', 'wmiexec', 'Enter-PSSession'],
        'exfil': ['7z.exe', 'rar.exe', 'certutil -encode']
    }

    pattern_match = 0
    for event in events:
        for category, patterns in indicators.items():
            if any(p in event['command'] for p in patterns):
                pattern_match += 1

    return pattern_match >= 3  # APT29 threshold

Scenario 2: Long-Term Campaign Visualization

# Generate APT timeline visualization
import matplotlib.pyplot as plt
from datetime import datetime, timedelta

def visualize_apt_campaign(apt_events):
    stages = {
        'Recon': [], 'Initial Access': [],
        'Persistence': [], 'Lateral Movement': [],
        'Exfiltration': []
    }

    for event in apt_events:
        stage = categorize_apt_stage(event)
        stages[stage].append(event['timestamp'])

    # Plot timeline
    fig, ax = plt.subplots(figsize=(15, 8))
    for i, (stage, times) in enumerate(stages.items()):
        ax.scatter(times, [i]*len(times), s=100, label=stage)

    ax.set_yticks(range(len(stages)))
    ax.set_yticklabels(stages.keys())
    ax.set_xlabel('Timeline')
    ax.set_title('APT Campaign Progression')
    plt.show()

Performance Tuning for APT Detection

1. Database Optimization

-- Create indexes for APT correlation queries
CREATE INDEX idx_apt_timestamp ON alerts(timestamp);
CREATE INDEX idx_apt_rule_id ON alerts(rule_id);
CREATE INDEX idx_apt_agent ON alerts(agent_name);
CREATE INDEX idx_apt_user ON alerts(data_srcuser);

-- Partition alerts table by date for faster queries
ALTER TABLE alerts PARTITION BY RANGE (UNIX_TIMESTAMP(timestamp)) (
    PARTITION p_2025_01 VALUES LESS THAN (UNIX_TIMESTAMP('2025-02-01')),
    PARTITION p_2025_02 VALUES LESS THAN (UNIX_TIMESTAMP('2025-03-01'))
);

2. Correlation Engine Tuning

# APT-optimized correlation settings
correlation:
  apt_detection:
    memory_limit: 4GB
    max_event_age: 180d # 6 months for APT detection
    correlation_threads: 8
    batch_size: 5000
    checkpoint_interval: 300s

Metrics and Success Measurement

APT Detection KPIs

{
  "apt_detection_metrics": {
    "avg_dwell_time_before": "142 days",
    "avg_dwell_time_after": "14 days",
    "improvement": "90.1%",
    "false_positive_rate": "2.3%",
    "apt_campaigns_detected": 47,
    "prevented_exfiltration": "3.2TB",
    "estimated_damage_prevented": "$14.2M"
  }
}

Integration with Threat Intelligence

MISP Integration for APT IOCs

# MISP integration for APT intelligence
from pymisp import PyMISP

def enrich_apt_detection():
    misp = PyMISP(url='https://misp.local', key='your-api-key')

    # Search for APT-related events
    apt_events = misp.search(tags=['apt', 'apt28', 'apt29'])

    # Generate Wazuh rules from MISP IOCs
    for event in apt_events:
        rule = generate_wazuh_rule_from_misp(event)
        deploy_rule_to_wazuh(rule)

Conclusion

Multi-stage APT detection requires patience, sophisticated correlation, and deep understanding of attacker tradecraft. By implementing these comprehensive Wazuh correlation rules, organizations can reduce APT dwell time from months to days, preventing catastrophic data breaches and intellectual property theft. Remember: APTs are marathons, not sprints—your detection strategy must match their persistence with intelligence.

Next Steps

  1. Deploy APT detection rules in test environment
  2. Tune correlation timeframes based on your environment
  3. Integrate with threat intelligence feeds
  4. Train SOC team on APT investigation procedures
  5. Conduct APT simulation exercises

The battle against APTs is won through vigilance, correlation, and the ability to see the forest through the trees. With these Wazuh rules, you’re equipped to detect even the stealthiest adversaries.