What is threat hunting?
Threat hunting is the proactive, hypothesis-driven search for adversaries who have evaded existing security controls and are operating silently inside an environment. Unlike alert-driven detection, hunters assume a breach has already occurred and go looking for evidence.
Assume breach
Start from the premise that an attacker is already inside. Your job is to find them before they achieve their objective.
Core mindsetHypothesis-driven
Every hunt begins with a structured hypothesis based on threat intelligence, past incidents, or ATT&CK techniques.
ProcessIntelligence-led
Hunters consume CTI feeds, MISP, ISAC reports, and vendor advisories to know what adversary groups are actively doing.
IntelIterative loop
Hunt → find → document → create detection rule → automate → hunt next hypothesis. Hunting feeds your SIEM.
CycleNot all indicators are equal. David Bianco's Pyramid of Pain describes how painful each indicator type is for an adversary when defenders detect it. Hashes are trivial to change; TTPs require the attacker to fundamentally re-tool.
Most domains contain two core labs — one guided (beginner/intermediate) and one scenario-based (advanced) — plus additional labs covering newer skill areas (Velociraptor VQL, cloud hunting, ESXi). Complete them in order within each domain. Labs are platform-agnostic: queries are written in pseudo-syntax with notes for Splunk SPL, ELK/KQL, and Sigma rule equivalents, alongside vendor-specific syntax (KQL, VQL) where the tool itself is the point of the lab. Estimated time per domain: 2–4 hours; the Cloud Hunting domain and capstone run longer at 4–6 hours each.
Lab environment setup guide
This workbook spans four platforms. You do not need all four running simultaneously — set up each one as you reach the relevant domain. Every platform listed below is free and open-source. Estimated total setup time: 3–5 hours across all environments.
All labs must be performed in isolated environments you own or control. Never run these tools, queries, or techniques against systems, networks, or accounts without explicit written authorisation. Use only the virtual machines and sample data described below.
Platform-to-domain coverage map — click any row to expand its full setup instructions:
What this gives you
- Windows Security Event Log (4624, 4625, 4648, 4769 etc.) for authentication hunting
- Sysmon telemetry (process creation, network connections, file events, process access)
- PowerShell ScriptBlock logging for obfuscated command detection
- A safe target system for running simulated attack commands
-
1
Get a Windows 10/11 evaluation VM. Microsoft provides free 90-day evaluation ISOs. Download from the Microsoft Evaluation Center — search "Windows 10 Enterprise Evaluation ISO". Import into VirtualBox (free) or VMware Workstation Player (free). Allocate at least 4 GB RAM and 60 GB disk.
:: After importing the ISO, create and configure the VM C:\> VBoxManage createvm --name "ThreatHuntLab" --ostype Windows10_64 --register C:\> VBoxManage modifyvm "ThreatHuntLab" --memory 4096 --cpus 2 C:\> VBoxManage modifyvm "ThreatHuntLab" --nic1 hostonly :: Host-only networking: VM cannot reach internet, only the host — safe for labs -
2
Take a clean snapshot before installing anything. This lets you reset to a known-good state between labs. In VirtualBox: Machine → Take Snapshot → name it "Clean Install".
-
3
Download and install Sysmon. Sysmon is part of Microsoft's Sysinternals suite. Download
Sysmon64.exefrom Microsoft's official Sysinternals page. Then download the SwiftOnSecurity Sysmon configuration — the most widely used community baseline.# Run PowerShell as Administrator # Download Sysinternals Sysmon PS> Invoke-WebRequest -Uri "https://download.sysinternals.com/files/Sysmon.zip" ` -OutFile "$env:TEMP\Sysmon.zip" PS> Expand-Archive "$env:TEMP\Sysmon.zip" -DestinationPath "C:\Tools\Sysmon" # Download SwiftOnSecurity config (most widely used baseline) PS> Invoke-WebRequest -Uri "https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml" ` -OutFile "C:\Tools\Sysmon\sysmonconfig.xml" # Install Sysmon with the config PS> cd C:\Tools\Sysmon PS> .\Sysmon64.exe -accepteula -i sysmonconfig.xml # Verify Sysmon is running PS> Get-Service Sysmon64 | Select-Object Name, Status, StartType # Expected: Status = Running -
4
Enable PowerShell ScriptBlock logging. This captures the full content of every PowerShell command executed — critical for detecting obfuscated payloads in Labs 1.2 and 2.2.
# Run as Administrator PS> $psLogPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" PS> If (!(Test-Path $psLogPath)) { New-Item -Path $psLogPath -Force } PS> Set-ItemProperty -Path $psLogPath -Name "EnableScriptBlockLogging" -Value 1 PS> Set-ItemProperty -Path $psLogPath -Name "EnableScriptBlockInvocationLogging" -Value 1 # Enable Module logging too (captures all PS module activity) PS> $modLogPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" PS> If (!(Test-Path $modLogPath)) { New-Item -Path $modLogPath -Force } PS> Set-ItemProperty -Path $modLogPath -Name "EnableModuleLogging" -Value 1 # Verify: open Event Viewer → Applications and Services Logs # → Microsoft → Windows → PowerShell → Operational # Run a test: Invoke-Expression "whoami" — should appear as Event ID 4104 -
5
Enable enhanced Windows Security auditing. Default Windows auditing is minimal. Apply the recommended audit policy to capture the event IDs used throughout this workbook.
:: Run Command Prompt as Administrator :: Logon events (4624, 4625, 4634, 4648) C:\> auditpol /set /subcategory:"Logon" /success:enable /failure:enable C:\> auditpol /set /subcategory:"Logoff" /success:enable :: Process creation (4688) — also captured by Sysmon Event 1 C:\> auditpol /set /subcategory:"Process Creation" /success:enable :: Kerberos events (4768, 4769, 4771) — on domain controllers C:\> auditpol /set /subcategory:"Kerberos Authentication Service" /success:enable /failure:enable C:\> auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable :: Account management (4720, 4732, 4740) C:\> auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable :: Verify current policy C:\> auditpol /get /category:* -
6
Load sample EVTX attack logs for offline hunting. The EVTX-ATTACK-SAMPLES repository on GitHub contains real Windows event log captures of attack techniques — perfect for practising queries without needing a live attack environment.
# Clone the EVTX-ATTACK-SAMPLES repo (requires git) PS> git clone https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES.git C:\Labs\EVTX-Samples # Or download the ZIP from GitHub and extract to C:\Labs\EVTX-Samples # Load a specific EVTX file into Event Viewer for analysis: # Event Viewer → Action → Open Saved Log → select .evtx file # Query a loaded EVTX with PowerShell Get-WinEvent PS> Get-WinEvent -Path "C:\Labs\EVTX-Samples\Defense_Evasion\sysmon_evasion.evtx" | Where-Object { $_.Id -eq 1 } | Select-Object TimeCreated, Message | Format-List -
7
Install osquery for endpoint hunting labs. osquery lets you query the live Windows system state using SQL — used in Labs 2.1 and 5.1.
# Download the latest osquery MSI from https://osquery.io/downloads PS> Invoke-WebRequest -Uri "https://pkg.osquery.io/windows/osquery-5.12.1.msi" ` -OutFile "$env:TEMP\osquery.msi" PS> Start-Process msiexec.exe -ArgumentList "/i $env:TEMP\osquery.msi /quiet" -Wait # Launch interactive shell PS> cd "C:\Program Files\osquery" PS> .\osqueryi.exe # Test query inside osqueryi shell osquery> SELECT name, path, status FROM services WHERE status = 'RUNNING' LIMIT 10;
Before moving to Lab 1.1, confirm: (1) Sysmon service is Running in services.msc. (2) Event Viewer shows Sysmon events under Applications and Services Logs → Microsoft → Windows → Sysmon → Operational. (3) A test PowerShell command appears as Event ID 4104 in the PowerShell Operational log. (4) Security event log shows Event ID 4624 on logon.
What this gives you
- Zeek (Bro) for network log generation from PCAP files
- Wireshark and tshark for packet-level analysis
- YARA for file-based malware pattern matching
- Python 3 with pandas, requests for beacon detection scripts and VirusTotal API
- Shodan CLI for infrastructure pivoting
-
1
Download Kali Linux. Get the pre-built VirtualBox or VMware image from
kali.org/get-kali— choose "Virtual Machines" for the fastest setup. Default credentials:kali / kali. Allocate 4 GB RAM minimum, 8 GB recommended. -
2
Update the system and install lab tools. All tools below are available in Kali's repositories or via pip. Run as root (Kali default).
# Update package lists and upgrade existing packages # apt update && apt upgrade -y # Install Zeek (network analysis framework) # apt install zeek -y # echo 'export PATH=$PATH:/opt/zeek/bin' >> ~/.bashrc && source ~/.bashrc # zeek --version # Install YARA # apt install yara -y # yara --version # Install Wireshark (accept non-root users prompt) # apt install wireshark tshark -y # Install Python libraries for beacon detection scripts # pip install pandas requests shodan --break-system-packages # Install Shodan CLI and initialise with your API key (free tier available) # shodan init YOUR_API_KEY_HERE # Install jq for JSON parsing of API responses # apt install jq -y -
3
Download sample PCAP files for network hunting labs. These are pre-captured network traffic files containing real attack patterns — use them in Labs 3.1 and 3.2 without needing a live network.
# Create labs directory # mkdir -p ~/labs/pcaps && cd ~/labs/pcaps # Malware Traffic Analysis — free PCAP exercises (malware-traffic-analysis.net) # Download a specific exercise ZIP (example — check site for current exercises) # wget "https://malware-traffic-analysis.net/2024/01/15/2024-01-15-traffic-analysis-exercise.pcap.zip" # unzip *.zip # password is typically: infected # CIRCL has free PCAP samples for C2 and lateral movement # https://www.circl.lu/doc/misp/feed-osint/ # Generate your own with tcpdump while running attack simulations # tcpdump -i eth0 -w ~/labs/pcaps/capture.pcap & -
4
Process a PCAP with Zeek to generate hunt-ready logs. Zeek converts raw packet captures into structured JSON/TSV logs (conn.log, dns.log, http.log, ssl.log, files.log) that your queries in Lab 3.1 operate on.
# Create output directory for this exercise # mkdir -p ~/labs/zeek-output && cd ~/labs/zeek-output # Process a PCAP file with Zeek (offline analysis) # zeek -C -r ~/labs/pcaps/capture.pcap # Zeek generates these log files in the current directory: # conn.log — all TCP/UDP/ICMP connections (src, dst, port, bytes, duration) # dns.log — DNS queries and responses # http.log — HTTP requests, URIs, user-agents, response codes # ssl.log — TLS handshake metadata (JA3, certificate CN, issuer) # files.log — files transferred over the network # Quick inspection with zeek-cut # zeek-cut ts id.orig_h id.resp_h id.resp_p proto duration < conn.log | head -20 -
5
Set up your YARA lab directory. Create a clean directory structure for the malware samples and YARA rules used in Lab 4.1.
# mkdir -p ~/labs/yara/{rules,samples,clean,output} # Download community YARA rules for reference # git clone https://github.com/Yara-Rules/rules.git ~/labs/yara/community-rules # Test YARA is working with a simple rule # echo 'rule test { strings: $s = "This program" condition: $s }' > /tmp/test.yar # yara /tmp/test.yar /bin/ls # Should return: test /bin/ls (or no output if string not found) # For malware samples: use MalwareBazaar (abuse.ch) with a free account # Download ONLY in an isolated VM with no network — never on a host machine # https://bazaar.abuse.ch/browse/
Before running Lab 3.1, confirm: (1) zeek --version returns a version number. (2) yara --version returns a version number. (3) python3 -c "import pandas, requests; print('OK')" prints OK. (4) At least one PCAP file exists in ~/labs/pcaps/. (5) Zeek successfully processes the PCAP and generates conn.log in ~/labs/zeek-output/.
What this gives you
- Volatility 3 for memory forensics and process injection hunting
- PEStudio, pefile, and strings for static PE analysis
- FakeNet-NG for intercepting malware C2 connections safely
- Capa for automatic technique identification in binaries
- oledump, oletools for Office macro analysis
-
1
Download REMnux. Get the pre-built OVA (VirtualBox/VMware appliance) from
remnux.org/docs/distro/get. The OVA comes with hundreds of malware analysis tools pre-installed. Default credentials:remnux / malware. File size is approximately 5 GB. -
2
Critical: set networking to Host-Only. Before starting REMnux for malware analysis, set the VM network adapter to "Host-Only" in VirtualBox/VMware. This prevents any malware you execute from reaching the real internet.
-
3
Verify pre-installed tools and update REMnux.
# Update the REMnux toolset (run occasionally, not before every lab) $ remnux upgrade # Verify Volatility 3 $ vol.py --version # Expected: Volatility 3 Framework x.x.x # Verify pefile and other Python analysis libs $ python3 -c "import pefile, yara; print('pefile and yara: OK')" # Verify strings utility $ strings --version # Verify capa (technique identification in binaries) $ capa --version # Verify oletools (Office macro analysis) $ oledump.py --help | head -5 -
4
Get a memory dump sample for Lab 2.2 (process injection). The DFIR.science GitHub repository and MemLabs CTF provide safe, legal memory dump files (.raw/.vmem) with known malware present — ideal for Volatility practice.
# Create labs directory $ mkdir -p ~/labs/memory && cd ~/labs/memory # MemLabs CTF — lab memory images (legal, safe to analyse) # Download from: https://github.com/stuxnet999/MemLabs $ wget "https://mega.nz/..." # see MemLabs README for current links # Test Volatility 3 against the image $ vol.py -f ~/labs/memory/memlabs-lab1.raw windows.pslist # Lists all running processes from the memory snapshot $ vol.py -f ~/labs/memory/memlabs-lab1.raw windows.malfind # Finds memory regions with suspicious characteristics -
5
Set up FakeNet-NG for dynamic malware analysis. FakeNet simulates network services (DNS, HTTP, SMTP) so that malware "believes" it has reached its C2 server — allowing you to capture C2 traffic without real internet access.
# FakeNet-NG is pre-installed on REMnux # Start it before executing any malware sample $ sudo fakenet # FakeNet will intercept all DNS queries and return 127.0.0.1 # It logs all C2 communication attempts to the terminal # C2 domains and IPs contacted will appear in real time # In a separate terminal, run your sample: $ wine ~/labs/samples/suspicious.exe # Watch FakeNet terminal for captured C2 traffic
Before Lab 4.1, confirm: (1) VM network is set to Host-Only. (2) vol.py --version responds. (3) yara --version responds. (4) A memory dump file exists in ~/labs/memory/. (5) FakeNet starts without error when run with sudo.
What this gives you
- Elasticsearch + Kibana (SIEM) — query Windows Event Logs and Zeek logs with KQL
- Zeek bundled and pre-configured for network monitoring
- Suricata IDS with Emerging Threats rules pre-loaded
- osquery fleet management — query endpoints from a central UI
- Kibana dashboards pre-built for threat hunting workflows
Security Onion is the most realistic SOC environment but requires more RAM (minimum 16 GB, 32 GB recommended) and longer setup time (~45 minutes). If you have sufficient hardware, it provides the best all-in-one experience and closely mirrors what enterprise SOC analysts actually use. If resources are limited, use the individual tools (Kali + Windows VM) instead.
-
1
Download the Security Onion ISO. Get the latest ISO from
securityonionsolutions.com/software. Create a VM with: 4 CPU cores, 16 GB RAM minimum, 200 GB disk, two network adapters (one NAT for management, one host-only for monitoring). -
2
Run the setup wizard. Boot from the ISO, log in as
onion / onion, then runsudo sosetup. Choose "Evaluation" mode for a standalone lab — this installs everything on one VM. Select your monitoring interface (the host-only adapter) when prompted.# After booting the ISO and logging in $ sudo sosetup # Follow the wizard: Evaluation → set admin email/password → wait ~30 min # After setup completes, check all services are running $ sudo so-status # All services should show green / running # Access the web interface from your host browser # URL: https://<security-onion-ip> # Login with the admin email/password you set during setup # Import a PCAP for analysis $ sudo so-import-pcap ~/labs/capture.pcap # Zeek and Suricata process the PCAP — logs appear in Kibana within minutes -
3
Forward Windows Event Logs to Security Onion. Install Elastic Winlogbeat or the Security Onion agent on your Windows VM to ship Sysmon and Security event logs into the Elasticsearch backend for unified hunting.
# Download the SO agent installer from your Security Onion web UI # Navigate to: SO Web UI → Administration → Downloads → Windows Agent # Run the installer as Administrator on your Windows VM PS> Start-Process .\so-agent-installer.exe -ArgumentList "/S" -Wait # Sysmon events, Security events, and PowerShell logs will now # appear in Kibana in real time under the hunt-* index # Verify in Kibana: Hunt → Overview — you should see Windows events
Before using Security Onion for labs, confirm: (1) sudo so-status shows all services green. (2) The web UI is accessible from your host browser. (3) Importing a PCAP with so-import-pcap generates Zeek logs visible in Kibana. (4) Windows events appear in Kibana after installing the SO agent on your Windows VM.
All recommended datasets for lab exercises — all free, all legal to use for security research and education:
| Dataset | Type | Used in | Where to get it |
|---|---|---|---|
| EVTX-ATTACK-SAMPLES | Windows Event Log (.evtx) | Labs 1.1, 1.2, 5.1, 5.2 | github.com/sbousseaden/EVTX-ATTACK-SAMPLES |
| Malware Traffic Analysis exercises | PCAP files | Labs 3.1, 3.2 | malware-traffic-analysis.net |
| MemLabs CTF memory images | Memory dumps (.raw) | Lab 2.2, 4.2 | github.com/stuxnet999/MemLabs |
| MalwareBazaar samples | Malware binaries | Lab 4.1, 4.2 | bazaar.abuse.ch (free account — use in isolated VM only) |
| YARA community rules | YARA rule files | Lab 4.1 | github.com/Yara-Rules/rules |
| DetectionLab | Full AD lab environment | Labs 5.1, 5.2 | github.com/clong/DetectionLab (Vagrant/Terraform) |
| SwiftOnSecurity Sysmon config | Sysmon XML config | All Windows labs | github.com/SwiftOnSecurity/sysmon-config |
Log analysis & SIEM querying
Logs are the primary data source for threat hunters. This domain covers Windows Event Logs, Sysmon telemetry, and SIEM query construction to surface anomalous behaviour across authentication, process execution, and network connections.
Learning objectives
- Identify Windows authentication event IDs and their meaning
- Construct SIEM queries to detect brute-force and password spray activity
- Distinguish between a brute-force attack (one account, many passwords) and a password spray (many accounts, one password)
- Create a detection hypothesis and map it to MITRE ATT&CK T1110
An adversary is attempting to gain initial access to our environment by brute-forcing user accounts via the Windows Remote Desktop Protocol or VPN portal.
Key Windows Security Event IDs for authentication hunting:
| Event ID | Description | Hunt value |
|---|---|---|
| 4624 | Successful logon | Baseline normal; look for unusual logon types (3=network, 10=remote interactive) |
| 4625 | Failed logon | Core brute-force indicator — volume, account, source IP, logon type |
| 4648 | Logon with explicit credentials | Lateral movement — running tools as another user |
| 4740 | Account locked out | High-confidence brute-force signal |
| 4768/4771 | Kerberos TGT request / pre-auth failure | Password spraying against AD from internal hosts |
-
1
Establish a baseline. Before hunting anomalies, understand normal. Query the last 30 days of Event ID 4625 and count failures per account per day. Record the typical range — this becomes your threshold.
// Platform-agnostic logic — adapt to your SIEM // Splunk: index=security EventCode=4625 // ELK: event.code:4625 // Sigma: logsource.product: windows, service: security SELECT TargetUserName, COUNT(*) AS failures, DATE(TimeGenerated) AS hunt_day FROM SecurityEvents WHERE EventID = 4625 AND TimeGenerated >= DATEADD(day, -30, NOW()) GROUP BY TargetUserName, hunt_day ORDER BY failures DESC -
2
Hunt brute-force: many failures on one account. Flag accounts with more than 20 failures within any 10-minute window from the same source IP. This pattern indicates credential stuffing or dictionary attack.
SELECT TargetUserName, IpAddress, COUNT(*) AS failures, MIN(TimeGenerated) AS first_seen, MAX(TimeGenerated) AS last_seen FROM SecurityEvents WHERE EventID = 4625 GROUP BY TargetUserName, IpAddress, FLOOR(UNIX_TIMESTAMP(TimeGenerated) / 600) HAVING failures > 20 ORDER BY failures DESC -
3
Hunt password spray: one failure per many accounts, same source. A spray tries one password against hundreds of accounts to avoid lockout. The signature is low per-account failure count but high unique account count from one IP.
SELECT IpAddress, COUNT(DISTINCT TargetUserName) AS unique_accounts, COUNT(*) AS total_failures FROM SecurityEvents WHERE EventID = 4625 AND TimeGenerated >= DATEADD(minute, -30, NOW()) GROUP BY IpAddress HAVING unique_accounts > 15 AND (total_failures / unique_accounts) < 3 ORDER BY unique_accounts DESC -
4
Correlate with successful logins. The most critical signal is a cluster of 4625 events followed by a 4624 from the same source — a successful login after repeated failures strongly indicates a compromised credential.
-
5
Document your findings using the hunt report template: Hypothesis → Evidence collected → Timeline → Verdict (confirmed / unconfirmed / false positive) → Recommended SIEM rule → MITRE mapping.
🧠 Reflection questions
- What logon type would you expect to see for an RDP brute-force attack vs a web application login attack?
- Why does a password spray evade account lockout policies and how would you tune your detection to compensate?
- If the attacker is using a distributed botnet (thousands of IPs), how would you modify your query to still catch the spray?
Learning objectives
- Understand Sysmon event schema and its value over native Windows logging
- Identify abnormal parent-child process relationships (process genealogy)
- Detect LOLBins (Living-off-the-Land Binaries) abuse — legitimate tools used maliciously
- Map findings to MITRE T1059 (Scripting Interpreter) and T1218 (System Binary Proxy Execution)
An attacker has gained initial access and is using legitimate Windows binaries (LOLBins) to execute malicious code, evade detection, and establish persistence — avoiding custom malware that might trigger AV.
Suspicious parent-child process chains to hunt:
| Parent process | Suspicious child | Why suspicious |
|---|---|---|
| winword.exe / excel.exe | powershell.exe, cmd.exe, wscript.exe | Office macro spawning shell — common phishing payload |
| svchost.exe | powershell.exe, cmd.exe | Service host should not spawn shells directly |
| explorer.exe | mshta.exe, regsvr32.exe, wmic.exe | LOLBin execution from desktop click |
| powershell.exe | net.exe, whoami.exe, ipconfig.exe | Enumeration commands run from PS — post-exploitation |
| msiexec.exe | powershell.exe, cmd.exe | MSI package spawning shell — installer abuse |
-
1
Enable Sysmon with the SwiftOnSecurity config (most widely used baseline). Install on Windows with:
sysmon64.exe -accepteula -i sysmonconfig.xml. Verify Sysmon is generating Event ID 1 (Process Create) in Event Viewer under Applications and Services → Microsoft → Windows → Sysmon → Operational. -
2
Hunt Office macro execution. Query for any process where the parent is an Office application and the child is a shell interpreter. This is a high-fidelity indicator of a phishing payload executing.
SELECT TimeGenerated, Computer, ParentImage, Image AS ChildProcess, CommandLine, User FROM SysmonEvents WHERE EventID = 1 AND ParentImage LIKE ANY ('%winword%', '%excel%', '%powerpnt%', '%outlook%') AND Image LIKE ANY ('%powershell%', '%cmd.exe%', '%wscript%', '%cscript%', '%mshta%', '%regsvr32%') ORDER BY TimeGenerated DESC -
3
Hunt encoded PowerShell. Attackers frequently use Base64-encoded commands (
-EncodedCommand/-enc) to obfuscate their payloads from simple string matching. Hunt for these in Sysmon Event 1 CommandLine field.SELECT TimeGenerated, Computer, User, CommandLine, ParentImage FROM SysmonEvents WHERE EventID = 1 AND Image LIKE '%powershell%' AND (CommandLine LIKE '%-enc%' OR CommandLine LIKE '%-EncodedCommand%' OR CommandLine LIKE '%-w hidden%' OR CommandLine LIKE '%IEX%' OR CommandLine LIKE '%DownloadString%') // To decode a Base64 command found in results: // [System.Text.Encoding]::Unicode.GetString( // [System.Convert]::FromBase64String("<paste_string>")) -
4
Hunt LOLBin abuse — certutil for download.
certutil.exeis a legitimate Windows certificate utility frequently abused to download malicious files. Look for its use with-urlcacheor-decodeflags.SELECT TimeGenerated, Computer, User, CommandLine FROM SysmonEvents WHERE EventID = 1 AND Image LIKE '%certutil%' AND CommandLine LIKE ANY ( '%-urlcache%', '%-decode%', '%-decodehex%') -
5
Build a Sigma rule from your most reliable finding. Document it, test it against your log data, and submit it to your SIEM as a detection rule. Every successful hunt should produce at least one persistent detection.
title: Office Application Spawning Shell Interpreter status: stable logsource: category: process_creation product: windows detection: parent_office: ParentImage|endswith: - '\winword.exe' - '\excel.exe' - '\powerpnt.exe' child_shell: Image|endswith: - '\powershell.exe' - '\cmd.exe' - '\wscript.exe' - '\mshta.exe' condition: parent_office and child_shell level: high tags: - attack.execution - attack.t1059
🧠 Reflection questions
- Why is Sysmon preferable to native Windows logging for process hunting, and what specific data does Sysmon Event ID 1 provide that Event ID 4688 does not?
- An analyst says your Office macro rule is generating too many false positives because of a legitimate automation tool. How would you tune the rule without eliminating coverage?
- List three other LOLBins not covered in this lab and describe a malicious use case for each.
Learning objectives
- Deploy Elasticsearch, Logstash, and Kibana as a working SIEM backbone
- Ship Windows Event Logs and Sysmon data into Elasticsearch using Winlogbeat
- Write Kibana Query Language (KQL) and Elasticsearch DSL queries against real hunt data
- Build a Kibana dashboard and saved search for one of this workbook's earlier hunt hypotheses
Every SIEM query in Labs 1.1 and 1.2 was written in platform-agnostic pseudo-SQL. This lab makes it concrete: you will stand up a real Elasticsearch + Kibana stack, ship real Windows Event Log data into it, and rewrite the brute-force detection query from Lab 1.1 as an actual KQL query you can run and see results from.
-
1
Deploy Elasticsearch and Kibana via Docker Compose. The fastest path to a working ELK stack for lab purposes — no manual package installation needed.
# Create a working directory and docker-compose.yml # mkdir -p ~/labs/elk && cd ~/labs/elk # cat > docker-compose.yml << 'EOF' version: '3' services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0 environment: - discovery.type=single-node - xpack.security.enabled=false - "ES_JAVA_OPTS=-Xms1g -Xmx1g" ports: ["9200:9200"] kibana: image: docker.elastic.co/kibana/kibana:8.13.0 environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 ports: ["5601:5601"] depends_on: [elasticsearch] EOF # Bring up the stack (first run takes a few minutes to pull images) # docker compose up -d # Verify Elasticsearch is healthy # curl http://localhost:9200/_cluster/health?pretty # Open Kibana in your browser # URL: http://localhost:5601 — no login required (security disabled for lab use) -
2
Install Winlogbeat on your Windows VM to ship logs. Winlogbeat is the official lightweight Elastic agent for forwarding Windows Event Logs (including Sysmon) into Elasticsearch.
# Download Winlogbeat (run as Administrator) PS> Invoke-WebRequest -Uri "https://artifacts.elastic.co/downloads/beats/winlogbeat/winlogbeat-8.13.0-windows-x86_64.zip" ` -OutFile "$env:TEMP\winlogbeat.zip" PS> Expand-Archive "$env:TEMP\winlogbeat.zip" -DestinationPath "C:\Program Files\Winlogbeat" PS> cd "C:\Program Files\Winlogbeat\winlogbeat-8.13.0-windows-x86_64" # Edit winlogbeat.yml — point output to your ELK host (replace IP) # output.elasticsearch: # hosts: ["192.168.56.1:9200"] # winlogbeat.event_logs: # - name: Security # - name: Microsoft-Windows-Sysmon/Operational # Install and start the Winlogbeat service PS> .\install-service-winlogbeat.ps1 PS> Start-Service winlogbeat PS> Get-Service winlogbeat # confirm Status = Running -
3
Create the index pattern in Kibana. Once Winlogbeat is sending data, Kibana needs to know which index to query.
// In Kibana: 1. Left menu → Stack Management → Data Views → Create data view 2. Name: "winlogbeat-*" Index pattern: "winlogbeat-*" 3. Timestamp field: "@timestamp" → click Save data view to Kibana 4. Left menu → Discover → select the winlogbeat-* data view 5. You should now see live events streaming in as they arrive -
4
Rewrite the Lab 1.1 brute-force query in real KQL. This is the same hunt logic from Lab 1.1, Step 2 — now expressed as an actual query you run in Kibana's Discover or visualisation tools.
// Paste into the Kibana Discover search bar: event.code: "4625" and winlog.event_data.LogonType: "3" // To replicate the GROUP BY/HAVING aggregation from Lab 1.1, // switch to Kibana Lens (Visualize → Lens) and configure: // Bucket: Terms on winlog.event_data.TargetUserName // Bucket: Terms on source.ip // Metric: Count // Filter: event.code: "4625" // Then sort descending by Count and look for accounts/IPs above your threshold // Equivalent raw Elasticsearch DSL (for the Dev Tools console): GET winlogbeat-*/_search { "query": { "term": { "event.code": "4625" } }, "aggs": { "by_account": { "terms": { "field": "winlog.event_data.TargetUserName", "size": 20 } } } } -
5
Save the search and build a dashboard. Click
Saveon your Discover search, name it "Brute Force Hunt — 4625 Type 3", then add it to a new Kibana Dashboard alongside the Lens visualisation from Step 4. This becomes a reusable hunt asset your team can return to.
Before moving on, confirm: (1) Kibana is accessible at http://localhost:5601 and shows cluster health as green/yellow. (2) The winlogbeat-* data view shows live events in Discover. (3) Your KQL brute-force query returns results when run against EVTX-ATTACK-SAMPLES or live test failed-logon data. (4) A saved search and dashboard have been created.
🧠 Reflection questions
- How does KQL (Kibana Query Language) differ syntactically from the Azure Sentinel KQL used in Lab 7.2, despite sharing a similar name?
- What are the operational tradeoffs of running your own self-hosted ELK stack versus a managed SIEM (Splunk Cloud, Sentinel, Elastic Cloud) for a growing SOC team?
- Your Elasticsearch cluster runs out of disk space during a long hunt. What index lifecycle management (ILM) policies would you put in place to prevent this in production?
Endpoint telemetry & EDR hunting
Endpoint Detection and Response (EDR) tools provide deep visibility into host behaviour — process memory, file system changes, registry modifications, and network connections. This domain uses osquery and Velociraptor-style queries to hunt at the endpoint level.
Learning objectives
- Enumerate all persistence locations an attacker might use on Windows
- Use osquery to query live endpoint state for suspicious entries
- Identify malicious scheduled tasks, services, and registry run keys
- Map findings to MITRE T1053, T1543, T1547
After gaining initial access, an attacker has established persistence on one or more endpoints using a scheduled task or registry run key pointing to a malicious executable or script, allowing them to survive reboots.
-
1
Query scheduled tasks with osquery. List all scheduled tasks, their actions, and the principal running them. Look for tasks with random names, pointing to
%TEMP%,%APPDATA%, or PowerShell with encoded commands.SELECT name, action, path, enabled, last_run_time, next_run_time FROM scheduled_tasks WHERE action LIKE ANY ( '%powershell%', '%cmd%', '%wscript%', '%mshta%', '%regsvr32%', '%rundll32%', '%Temp%', '%AppData%') OR name REGEXP '[a-z0-9]{8,16}' -
2
Hunt registry run keys. These are the most common persistence location. Query all four primary autorun locations and look for entries pointing to unsigned executables, temp directories, or encoded commands.
SELECT key, name, data, type FROM registry WHERE key IN ( 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', 'HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 'HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce') ORDER BY name // Cross-reference data (executable path) against known-good software list -
3
Hunt malicious services. Attackers often install services with generic or system-like names. Query services looking for those with binary paths in unusual locations or that were created recently.
SELECT name, display_name, status, path, start_type, service_type FROM services WHERE (path LIKE '%Temp%' OR path LIKE '%AppData%' OR path LIKE '%Users%Public%') AND status = 'RUNNING' -
4
Verify suspicious entries. For each suspicious finding, check: Is the executable signed? Who is the publisher? Is the hash known-malicious on VirusTotal? Cross-reference with software installation records and change management logs.
🧠 Reflection questions
- An attacker uses a DLL hijacking technique to achieve persistence without touching any of the four run keys. What other persistence locations would you check?
- How would you detect a WMI subscription used for persistence (T1546.003)?
- Describe how you would automate this hunt to run across 500 endpoints simultaneously.
Learning objectives
- Understand process injection techniques: DLL injection, process hollowing, reflective loading
- Hunt for injected code in legitimate processes using memory artefacts
- Identify unbacked memory regions and anomalous thread start addresses
- Map to MITRE T1055 — Process Injection
A threat actor is injecting a Cobalt Strike beacon or similar C2 implant into a legitimate Windows process (e.g. svchost.exe, explorer.exe) to blend network traffic and evade process-based detection.
-
1
Hunt for processes making unexpected network connections. A svchost.exe instance that is beaconing to an external IP on port 443 every 60 seconds is a strong injection indicator. Use Sysmon Event 3 (Network Connection) correlated with Event 1.
SELECT Image, ProcessId, User, DestinationIp, DestinationPort, COUNT(*) AS connection_count FROM SysmonEvents WHERE EventID = 3 AND Image IN ('svchost.exe', 'explorer.exe', 'notepad.exe', 'calc.exe') AND DestinationIp NOT LIKE '10.%' AND DestinationIp NOT LIKE '192.168.%' GROUP BY Image, ProcessId, DestinationIp HAVING connection_count > 5 -
2
Look for unbacked memory regions. Injected code typically resides in memory regions with no corresponding file on disk (RWX permissions, no module backing). Use Volatility or a Velociraptor artifact to enumerate process memory maps.
# Dump and scan process list for anomalies $ vol.py -f memory.raw --profile=Win10x64 pslist # Hunt for injected code: look for executable, non-image backed pages $ vol.py -f memory.raw --profile=Win10x64 malfind \ --pid 1234 # pid of suspicious svchost # Output shows memory regions with: # Protection: PAGE_EXECUTE_READWRITE (0x40) — red flag # No VAD tag / no file backing — strong injection indicator # MZ header at region start — PE loaded in memory manually -
3
Hunt for Cobalt Strike beacon IOCs. CS beacons leave distinctive artefacts: named pipes (
\MSSE-<pid>-server), specific network patterns (default 60s sleep, malleable C2 headers), and default SSL certificate fingerprints.SELECT name, pid, path FROM named_pipes WHERE name REGEXP 'MSSE-[0-9]+-server' OR name LIKE '%postex%' OR name LIKE '%status_[0-9]%' OR name LIKE '%msagent_%' -
4
Extract and analyse. If malfind reveals injected code, dump the memory region:
vol.py malfind --dump-dir ./output/. Submit the dump to a sandbox (Any.run, Hybrid Analysis) for behavioural analysis and hash to VirusTotal.
🧠 Reflection questions
- What is the difference between DLL injection and process hollowing at the memory level, and how does each appear in Volatility output?
- An attacker using a custom C2 framework avoids all default Cobalt Strike IOCs. What behavioural indicators would you still be able to hunt?
- How does sleep masking in modern C2 frameworks evade memory scanning, and what emerging techniques do hunters use to counter it?
Learning objectives
- Understand Velociraptor's architecture — server, clients, hunts, and artifacts
- Write VQL (Velociraptor Query Language) to interrogate live endpoint state across a fleet
- Deploy a hunt across multiple endpoints simultaneously and collect results centrally
- Use built-in artifacts and write custom VQL for persistence, process, and network hunting
- Integrate Velociraptor hunt outputs with Sigma rules and threat intelligence
Velociraptor has become a core competency for threat hunters and IR teams. Unlike osquery (which queries static state) or SIEM (which queries historical logs), Velociraptor runs live forensic collections and custom VQL queries across thousands of endpoints simultaneously. Enterprise hunt pipelines now routinely generate Velociraptor VQL artifacts alongside Sigma rules as standard hunt outputs. It is the open-source alternative to commercial EDR platforms like CrowdStrike and SentinelOne for deep endpoint investigation.
An adversary has deployed a persistence mechanism across multiple endpoints in our environment. We need to hunt all endpoints simultaneously for suspicious scheduled tasks, registry run keys, and recently modified executables in writable directories — without rebooting or installing new agents.
-
1
Set up Velociraptor server and deploy clients. Download the single binary from the Velociraptor GitHub releases page. It acts as both server and client — no separate installation needed per component.
# Download latest Velociraptor binary (Linux server) $ wget https://github.com/Velocidex/velociraptor/releases/latest/download/velociraptor-v0.73-linux-amd64 $ chmod +x velociraptor-v0.73-linux-amd64 $ mv velociraptor-v0.73-linux-amd64 /usr/local/bin/velociraptor # Generate a self-signed server config (for lab use) $ velociraptor config generate -i # Answer prompts: deployment type=Self Signed SSL, hostname=localhost # Creates server.config.yaml and client.config.yaml # Start the server (runs web UI on https://localhost:8889) $ velociraptor --config server.config.yaml frontend -v # In a second terminal — enroll the local machine as a client $ velociraptor --config client.config.yaml client -v # Client registers with server — visible in Web UI under Clients -
2
Understand VQL basics. VQL is SQL-inspired but purpose-built for forensic artifact collection. Every query selects from a plugin (a data source) and can be filtered, transformed, and piped just like SQL. Plugins expose OS state: processes, files, registry, network connections, event logs.
-- List all running processes with their command lines SELECT Pid, Ppid, Name, CommandLine, Username, CreateTime FROM pslist() WHERE Name IN ('powershell.exe', 'cmd.exe', 'wscript.exe') -- List all network connections SELECT Pid, FamilyString, TypeString, LocalAddress, LocalPort, RemoteAddress, RemotePort, Status FROM netstat() WHERE Status = 'ESTABLISHED' AND RemoteAddress NOT IN private_addresses() -- Enumerate scheduled tasks SELECT Name, Command, Arguments, Enabled, NextRunTime, UserId FROM scheduled_tasks() WHERE Command =~ '(?i)(powershell|cmd|wscript|mshta)' -- Read Windows Event Log entries directly SELECT System.TimeCreated.SystemTime AS EventTime, System.EventID.Value AS EventID, UserData FROM parse_evtx(filename='C:/Windows/System32/winevt/Logs/Security.evtx') WHERE System.EventID.Value = 4625 LIMIT 100 -
3
Hunt persistence with built-in artifacts. Velociraptor ships with hundreds of pre-built forensic artifacts. Use the
Windows.Persistence.PersistenceSniperartifact to enumerate all persistence locations in one collection run — registry run keys, scheduled tasks, services, startup folders, WMI subscriptions, and more.-- Run in Velociraptor notebook or via Hunt -- Collect all persistence mechanisms in one shot SELECT * FROM Artifact.Windows.Persistence.PersistenceSniper() -- Filter results to only show non-Microsoft signed binaries SELECT Source, KeyPath, EntryName, EntryValue, Authenticode.Trusted, Authenticode.SubjectName FROM Artifact.Windows.Persistence.PersistenceSniper() WHERE Authenticode.Trusted != 'trusted' OR Authenticode.SubjectName !~ 'Microsoft' -- To launch as a hunt across ALL enrolled clients: -- Web UI → Hunt Manager → New Hunt → select artifact -- → Launch → results stream in as clients respond -
4
Write a custom VQL artifact for C2 beacon detection. Hunt for processes making periodic outbound connections — a beacon signature — by correlating netstat() with pslist() and filtering for processes making connections to non-RFC1918 addresses.
-- Custom artifact: processes with external connections -- excluding known browsers and system processes LET known_good = ('chrome.exe', 'firefox.exe', 'msedge.exe', 'svchost.exe') LET external_conns = SELECT Pid, RemoteAddress, RemotePort FROM netstat() WHERE Status = 'ESTABLISHED' AND RemoteAddress !~ '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)' SELECT p.Name, p.Pid, p.CommandLine, p.Exe, e.RemoteAddress, e.RemotePort, p.Username, p.CreateTime FROM pslist() AS p JOIN external_conns AS e ON p.Pid = e.Pid WHERE p.Name NOT IN known_good ORDER BY p.Name -
5
Timeline analysis — hunt recently created executables. Attackers frequently drop executables in writable directories (Temp, AppData, Public). Use VQL to find all PE files created or modified in the last 7 days in suspicious locations.
SELECT FullPath, Size, Mtime, Atime, Ctime, Authenticode.Trusted AS Signed, Authenticode.SubjectName AS Publisher, hash(path=FullPath).SHA256 AS SHA256 FROM glob(globs=[ 'C:/Users/*/AppData/**/*.exe', 'C:/Users/*/AppData/**/*.dll', 'C:/Windows/Temp/**/*.exe', 'C:/ProgramData/**/*.exe' ]) WHERE Mtime > now() - 7 * 24 * 3600 AND Signed != 'trusted' -- Hash results can be bulk-submitted to VirusTotal -- via the Artifact.Generic.Forensic.HashBulkLookup artifact -
6
Export findings and create a Sigma rule. Every VQL hunt that surfaces confirmed malicious activity should produce a Sigma detection rule as output — so the finding becomes a permanent automated detection rather than a one-time manual discovery.
osquery — best for continuous scheduled queries, configuration compliance, and lightweight fleet visibility. SQL syntax, easy to learn, broad OS support. Velociraptor VQL — best for active incident response, deep forensic artifact collection, memory analysis, and running complex multi-step hunts. VQL can parse binary file formats, compute hashes, decode base64, and collect raw forensic artefacts that osquery cannot access. In 2026 enterprise environments, both are often deployed together.
🧠 Reflection questions
- How does Velociraptor's client-server architecture differ from a traditional SIEM agent, and what are the security implications of deploying it in a production environment?
- A VQL hunt for unsigned executables in AppData returns 200 results across 50 endpoints. Describe your triage workflow to prioritise which findings to investigate first.
- How would you convert a confirmed VQL hunt finding into both a Sigma rule (for SIEM) and a Velociraptor artifact (for future fleet hunts)?
Network traffic analysis
Network hunting identifies C2 beaconing, data exfiltration, DNS tunnelling, and lateral movement across the wire. Tools include Zeek (formerly Bro), Suricata, Wireshark, and network flow data (NetFlow/IPFIX).
Learning objectives
- Understand C2 beaconing patterns and how they differ from normal traffic
- Use statistical methods (jitter, byte count, connection frequency) to identify beacons
- Analyse PCAP files with Wireshark and Zeek to extract flow metadata
- Map to MITRE T1071 (Application Layer Protocol) and T1573 (Encrypted Channel)
A compromised host is periodically reaching out to an attacker-controlled C2 server at regular intervals (beaconing) over HTTPS, using jitter to slightly randomise timing and evade simple frequency detection.
-
1
Extract flow data. From Zeek logs or NetFlow, extract all outbound connections grouped by source IP → destination IP pair. Calculate the time delta between successive connections.
# Using zeek-cut to extract relevant fields $ zeek-cut ts id.orig_h id.resp_h id.resp_p bytes \ < conn.log | sort -k1 > flows_sorted.tsv # Python: calculate connection intervals per destination import pandas as pd df = pd.read_csv('flows_sorted.tsv', sep='\t', names=['ts','src','dst','dport','bytes']) df['ts'] = pd.to_datetime(df['ts'], unit='s') df = df.sort_values(['src','dst','ts']) df['interval'] = df.groupby(['src','dst'])['ts'].diff() # Low standard deviation of interval = beaconing candidate beacons = df.groupby(['src','dst']).agg( count=('ts','count'), mean_interval=('interval','mean'), std_interval=('interval','std'), mean_bytes=('bytes','mean') ).query('count > 20 and std_interval.dt.seconds < 30') print(beacons.sort_values('std_interval')) -
2
Hunt DNS tunnelling. DNS tunnelling encodes data in DNS queries/responses. Indicators include: unusually long subdomain strings, high query volume for a single domain, and rare query types (TXT, NULL, MX used for data).
# Long subdomain query detection (>52 chars is suspicious) $ zeek-cut query qtype_name < dns.log | \ awk 'length($1) > 52 || $2 ~ /TXT|NULL/' | \ sort | uniq -c | sort -rn | head -20 # SIEM query equivalent SELECT query, qtype, COUNT(*) AS count, COUNT(DISTINCT src_ip) AS unique_sources FROM dns_logs WHERE LENGTH(query) > 52 OR qtype IN ('TXT', 'NULL', 'MX') GROUP BY query, qtype HAVING count > 50 ORDER BY count DESC -
3
Analyse suspicious PCAP in Wireshark. Filter by suspicious destination IP. Export HTTP objects (File → Export Objects → HTTP) to see transferred files. For HTTPS, look at TLS certificate fields — self-signed certs, suspicious Subject CN, or Cobalt Strike default JA3 hash
72a589da586844d7f0818ce684948eea.
🧠 Reflection questions
- If an attacker uses domain fronting over a legitimate CDN (e.g. Cloudflare), how would you identify the real destination of the C2 traffic?
- What is jitter in C2 frameworks, and how does it affect your statistical beacon detection? How would you adjust your algorithm?
- Describe how you would build a baseline of "normal" DNS query volume to improve your DNS tunnelling detection.
Learning objectives
- Identify east-west lateral movement in network flow data
- Detect SMB Admin Share access, WMI remote execution, and RDP hopping
- Build a network baseline and detect deviations using peer communication graphs
- Map to MITRE T1021 — Remote Services
An attacker with valid credentials is moving laterally between workstations and towards servers using SMB file shares and WMI remote command execution, staying below the threshold of automated alerts.
-
1
Map peer-to-peer SMB connections. In a healthy network, most workstations only talk to file servers — not to each other. Workstation-to-workstation SMB traffic is a lateral movement indicator. Build a connection matrix.
SELECT src_ip, dst_ip, COUNT(*) AS connections, SUM(bytes) AS total_bytes FROM netflow WHERE dst_port = 445 AND src_ip LIKE '10.%' AND dst_ip LIKE '10.%' AND dst_ip NOT IN (SELECT ip FROM known_file_servers) GROUP BY src_ip, dst_ip HAVING connections > 3 ORDER BY connections DESC -
2
Correlate with Windows Event 4624 Logon Type 3. Network logons (Type 3) to multiple machines from a single account within a short window are a strong lateral movement indicator. This is especially suspicious outside business hours.
-
3
Hunt WMI remote execution. Look for WmiPrvSE.exe (WMI Provider Host) spawning child processes on remote hosts — this is the telltale sign of WMIC remote execution or Invoke-WMIMethod.
SELECT TimeGenerated, Computer, User, ParentImage, Image, CommandLine FROM SysmonEvents WHERE EventID = 1 AND ParentImage LIKE '%WmiPrvSE.exe%' AND Image NOT IN ( 'scrcons.exe', 'mofcomp.exe', 'wmiadap.exe') // Any process other than the above being spawned // by WmiPrvSE is suspicious — especially cmd/powershell
🧠 Reflection questions
- How would you build a "normal communication graph" for your network and automate detection of new edges (new host-to-host connections)?
- Why is Logon Type 3 particularly useful for lateral movement hunting compared to other logon types?
- An attacker uses RDP through a jump server. How does this complicate your detection and what data sources would you add?
Learning objectives
- Understand Suricata's role as an IDS/IPS/NSM engine distinct from Zeek's log-generation approach
- Write and load custom Suricata rules in the standard Snort-compatible rule syntax
- Run Suricata against a PCAP and live interface, and interpret EVE JSON alert output
- Tune rules to reduce false positives and integrate Emerging Threats community rules
Zeek (Lab 3.1) generates rich descriptive logs of all network activity — it tells you what happened. Suricata is signature and anomaly-based — it tells you when something matches a known-bad pattern and can actively block it (IPS mode). Most production NSM stacks run both: Zeek for hunting and baselining, Suricata for real-time alerting on known threats.
An adversary's tooling will trigger known network-based signatures — exploit kit traffic, known C2 frameworks, or malware family communication patterns — that off-the-shelf community rules are built to catch, and our hunt must verify the alerting pipeline is actually catching them.
-
1
Install Suricata and update rule sources. Suricata ships with the Emerging Threats Open ruleset manager built in via
suricata-update.# Suricata is pre-installed on Kali, or install with: # apt install suricata -y # Update to the latest Emerging Threats Open ruleset # suricata-update # List enabled rule sources # suricata-update list-sources # Verify Suricata config and rule syntax before running # suricata -T -c /etc/suricata/suricata.yaml -v # Expected: "Configuration provided was successfully loaded" -
2
Run Suricata against a PCAP file. Use the same malware traffic PCAP from Lab 3.1 — this time looking for signature matches rather than statistical anomalies.
# Run Suricata in offline (PCAP) mode # mkdir -p ~/labs/suricata-output # suricata -c /etc/suricata/suricata.yaml \ -r ~/labs/pcaps/capture.pcap \ -l ~/labs/suricata-output/ # Suricata generates eve.json (structured alerts) and fast.log (plain text) # cat ~/labs/suricata-output/fast.log # Parse EVE JSON alerts with jq — show signature, severity, src/dst # cat ~/labs/suricata-output/eve.json | \ jq -r 'select(.event_type=="alert") | "\(.timestamp) | \(.alert.signature) | \(.alert.severity) | \(.src_ip) -> \(.dest_ip)"' -
3
Write a custom rule. Suricata rules use Snort-compatible syntax: action, header (protocol/IP/port), and options (content match, metadata). Write a rule to detect a specific C2 user-agent string or beacon URI pattern.
# /etc/suricata/rules/local.rules # Detect a suspicious User-Agent associated with a known C2 framework alert http any any -> any any ( msg:"THREAT HUNT - Suspicious C2 User-Agent String"; flow:established,to_server; http.user_agent; content:"Mozilla/4.0 (compatible; MSIE 6.0)"; classtype:trojan-activity; sid:1000001; rev:1; ) # Detect a beacon-style URI pattern (random alphanumeric path, fixed length) alert http any any -> any any ( msg:"THREAT HUNT - Possible C2 Beacon URI Pattern"; flow:established,to_server; http.uri; pcre:"/^\/[a-zA-Z0-9]{16}$/"; classtype:trojan-activity; sid:1000002; rev:1; ) # Reference local.rules in suricata.yaml under rule-files:, then reload # suricata -c /etc/suricata/suricata.yaml \ -r ~/labs/pcaps/capture.pcap -l ~/labs/suricata-output/ \ -S /etc/suricata/rules/local.rules -
4
Run Suricata live on an interface (IDS mode). For real-time alerting rather than offline PCAP analysis, run against a live network interface.
# Run live against an interface (requires root and promiscuous mode) # suricata -c /etc/suricata/suricata.yaml -i eth0 # Tail alerts in real time in a second terminal # tail -f /var/log/suricata/eve.json | \ jq -r 'select(.event_type=="alert") | "\(.alert.signature)"' -
5
Tune for false positives. A new rule that fires on legitimate traffic needs tuning — narrow the content match, add additional conditions, or use
thresholdrules to suppress repeat alerts within a time window. Document every rule's expected false-positive rate before deploying it to production.
🧠 Reflection questions
- Why might a hunt team prefer to run Suricata in IDS mode (alert only) rather than IPS mode (block) during the tuning phase of a new rule?
- An Emerging Threats rule for a specific malware family stops firing after the malware author changes their C2 URI pattern. How would Lab 3.1's statistical beaconing approach catch this attack even when the signature-based rule fails?
- How would you operationalise Suricata alerts into your SIEM, and what fields from the EVE JSON output are most valuable for a hunter triaging the alert?
Malware & artefact analysis
When a hunt surfaces a suspicious file or memory dump, hunters need basic static and dynamic analysis skills to quickly determine intent and build detection signatures without relying entirely on antivirus.
Learning objectives
- Perform static analysis on a suspicious binary without executing it
- Extract indicators: strings, imports, PE metadata, and entropy
- Write, test, and tune a YARA rule targeting the malware family
- Submit indicators to threat intelligence platforms
-
1
Safe environment first. Always analyse in an isolated VM with no network access or a sandbox. Take a snapshot before analysis. Use REMnux Linux (dedicated malware analysis distro) or a FlareVM Windows setup.
-
2
Initial triage. Get the hash, check it on VirusTotal, check file type with
file, and assess entropy (packed/encrypted files have entropy > 7.0).# Hash the sample $ sha256sum sample.exe && md5sum sample.exe # Check file type (don't trust the extension) $ file sample.exe # Calculate entropy (>7.0 = likely packed/encrypted) $ python3 -c " import math, sys data = open('sample.exe','rb').read() freq = {} for b in data: freq[b] = freq.get(b,0)+1 H = -sum((c/len(data))*math.log2(c/len(data)) for c in freq.values()) print(f'Entropy: {H:.4f}') " # Extract printable strings $ strings -n 8 sample.exe | grep -iE \ '(http|cmd|powershell|CreateRemoteThread|VirtualAlloc|socket)' -
3
PE header analysis with PEStudio or pefile. Examine imports (functions the binary calls) —
VirtualAllocEx,WriteProcessMemory,CreateRemoteThreadare injection APIs. Check the compile timestamp and compare it to when the file appeared on disk. -
4
Write a YARA rule. Select 2–4 unique, stable indicators from your analysis — not hashes. Test against known-clean files to measure false positive rate.
rule ThreatHunt_Dropper_Generic { meta: description = "Hunting rule for PS dropper with injection API" author = "Hunt Team" confidence = "high" mitre = "T1059.001, T1055" strings: $api1 = "VirtualAllocEx" ascii $api2 = "WriteProcessMemory" ascii $api3 = "CreateRemoteThread" ascii $ps = "IEX (New-Object" ascii nocase $mz = { 4D 5A } // MZ PE header at offset 0 condition: uint16(0) == 0x5A4D and filesize < 2MB and 2 of ($api*) and $ps } -
5
Test and tune. Run:
yara -r rule.yar /path/to/clean_files/to check false positives. Adjust conditions until you achieve high specificity. Deploy to EDR or SIEM for ongoing scanning.
🧠 Reflection questions
- Why are file hashes poor long-term YARA indicators, and what makes a string or byte sequence a good YARA condition?
- A packer obfuscates all strings in the binary. What alternative YARA conditions could you use (hint: think PE module, entropy, section names)?
Learning objectives
- Submit samples to sandboxes (Any.run, Cuckoo) and interpret behavioural reports
- Extract dynamic IOCs: C2 IPs, registry changes, dropped files, process trees
- Convert sandbox findings into hunt hypotheses and SIEM detections
- Understand sandbox evasion techniques and their implications for analysis
- 1
Submit to Any.run (free tier available). Use an interactive sandbox — you can click through the malware execution in real time. Enable
Fake Netto intercept C2 connections and prevent real exfiltration. - 2
Document the process tree. Screenshot the parent-child execution chain. Note every process spawned, every file dropped, every registry key written. This becomes the basis for your hunt queries.
- 3
Extract network IOCs. From the sandbox network tab, collect all C2 IPs, domains, URLs, and HTTP headers. Check JA3/JA3S fingerprints — search these in Shodan to find other C2 servers in the same campaign.
- 4
Hunt backwards. Take the IOCs and hunt your environment: did any host contact these IPs or domains? Did any host drop files with the same name or in the same path? This is the translation from malware analysis to active hunting.
- 5
Understand evasion. Modern malware checks: VM artifacts (VMware registry keys, screen resolution, lack of user activity), debugger presence (IsDebuggerPresent), and sleep timers to delay execution past sandbox timeout. Document any evasion behaviour observed.
Active Directory attack hunting
Active Directory is the primary target in most enterprise attacks. This domain covers detecting Kerberoasting, Pass-the-Hash, DCSync, and Golden Ticket attacks — the techniques most commonly used in ransomware and nation-state intrusions.
Learning objectives
- Understand how Kerberoasting and AS-REP Roasting extract crackable hashes from AD
- Detect both attacks using Windows Security Event IDs and Kerberos log analysis
- Identify high-value service accounts and reduce the attack surface
- Map to MITRE T1558.003 (Kerberoasting) and T1558.004 (AS-REP Roasting)
An attacker with a low-privilege domain account is requesting Kerberos service tickets for high-privilege service accounts (SPNs) in bulk, planning to crack the TGS hashes offline to obtain plaintext credentials.
| Attack | Event ID | Key indicator | Why it matters |
|---|---|---|---|
| Kerberoasting | 4769 | Ticket encryption type 0x17 (RC4) | RC4 tickets are easier to crack; modern environments should use AES (0x12) |
| Kerberoasting | 4769 | Many 4769s from same account in short window | Bulk SPN enumeration and ticket request pattern |
| AS-REP Roasting | 4768 | Pre-authentication not required flag | Account has "Do not require Kerberos preauthentication" set |
| Pass-the-Ticket | 4768+4769 | TGT from unusual IP, short ticket lifetime | Forged or stolen ticket being used |
-
1
Hunt bulk TGS requests with RC4 encryption. A single user requesting dozens of service tickets in minutes using RC4 encryption type is the core Kerberoasting signature.
SELECT SubjectUserName AS requesting_account, ServiceName, TicketEncryptionType, COUNT(*) AS ticket_count, MIN(TimeGenerated) AS first_request FROM SecurityEvents WHERE EventID = 4769 AND TicketEncryptionType = '0x17' -- RC4-HMAC AND ServiceName NOT LIKE '%$' -- exclude machine accounts AND TimeGenerated > DATEADD(hour,-1,NOW()) GROUP BY SubjectUserName, ServiceName, TicketEncryptionType HAVING ticket_count > 5 ORDER BY ticket_count DESC -
2
Hunt AS-REP Roastable accounts. Query AD for accounts with pre-authentication disabled. These are permanently vulnerable until the flag is removed — this hunt is about exposure, not just active attacks.
# Run on a domain-joined machine with AD module PS> Get-ADUser -Filter * -Properties DoesNotRequirePreAuth | Where-Object { $_.DoesNotRequirePreAuth -eq $true } | Select-Object Name, SamAccountName, Enabled, LastLogonDate | Format-Table -AutoSize # Any enabled account in this list is AS-REP roastable # Remediation: enable Kerberos pre-authentication # Set-ADAccountControl -Identity USERNAME -DoesNotRequirePreAuth $false -
3
Hunt DCSync attacks. DCSync abuses the Directory Replication Service to pull password hashes without running any code on the DC. Look for Event ID 4662 with Object Type "domainDNS" and "Replicating Directory Changes All" permission from a non-DC machine.
🧠 Reflection questions
- Why is Kerberoasting almost impossible to block entirely, and what compensating controls reduce its effectiveness?
- How would a Golden Ticket attack appear in your Windows Event Logs, and why is it particularly difficult to detect?
- Describe how you would use BloodHound data to prioritise which accounts to protect first from Kerberoasting.
Learning objectives
- Understand LSASS memory reading as the primary credential dumping vector
- Detect Mimikatz and its variants using process access events and memory indicators
- Identify credential dumping via Task Manager, ProcDump, and comsvcs.dll
- Map to MITRE T1003.001 — LSASS Memory
-
1
Hunt LSASS process access (Sysmon Event 10). Any process other than a handful of legitimate system processes opening LSASS with read-memory access is a credential dumping attempt.
SELECT TimeGenerated, Computer, User, SourceImage, GrantedAccess, CallTrace FROM SysmonEvents WHERE EventID = 10 AND TargetImage LIKE '%lsass.exe%' AND GrantedAccess IN ( '0x1010', '0x1410', '0x147a', '0x143a', '0x1438', '0x1fffff') AND SourceImage NOT IN ( 'C:\Windows\System32\svchost.exe', 'C:\Windows\System32\werfault.exe', 'C:\Windows\System32\taskmgr.exe') -
2
Hunt comsvcs.dll MiniDump technique. Attackers use the native
comsvcs.dllto dump LSASS without dropping Mimikatz, which often bypasses AV. The command:rundll32 comsvcs.dll, MiniDump <lsass_pid> lsass.dmp fullSELECT TimeGenerated, Computer, User, CommandLine FROM SysmonEvents WHERE EventID = 1 AND Image LIKE '%rundll32%' AND CommandLine LIKE '%comsvcs%' AND CommandLine LIKE ANY ( '%MiniDump%', '%minidump%') - 3
Hunt for LSASS dump files on disk. Even if the access is blocked, look for
.dmpfiles created in unusual locations (Desktop, Temp, root of C:) — Sysmon Event 11 (FileCreate) can catch this.
🧠 Reflection questions
- Microsoft introduced Protected Process Light (PPL) for LSASS. How does this affect credential dumping, and what are the attacker's bypass techniques?
- Besides Mimikatz and comsvcs.dll, name two other tools or techniques used to dump credentials and describe the detection approach for each.
Learning objectives
- Install BloodHound Community Edition and understand its graph-based attack path model
- Run SharpHound to collect Active Directory relationship data
- Identify privilege escalation paths to Domain Admin using BloodHound's built-in queries
- Hunt for evidence that an attacker has already run BloodHound/SharpHound against your environment
- Use BloodHound findings to prioritise which accounts and ACLs need hardening
BloodHound is the single most important AD attack path mapping tool used by both red teams and real adversaries. It models the entire domain — users, groups, computers, GPOs, and ACLs — as a graph, then runs pathfinding algorithms to reveal every route to Domain Admin. Defenders run the exact same tool proactively, for the same reason an attacker would: to find and close the paths before they're discovered.
Our Active Directory environment contains undiscovered privilege escalation paths from low-privilege user accounts to Domain Admin, caused by accumulated ACL misconfigurations and nested group memberships that no single admin is aware of.
-
1
Install BloodHound CE via Docker. BloodHound Community Edition runs as three containers (application server, PostgreSQL, Neo4j graph database) managed through the official BloodHound CLI wrapper around Docker Compose.
# Ensure Docker and Docker Compose are installed # apt install docker.io docker-compose -y # systemctl enable --now docker # Download and run the official BloodHound CLI installer # curl -L https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz -o bhcli.tar.gz # tar -xzf bhcli.tar.gz # chmod +x bloodhound-cli # ./bloodhound-cli install # Watch the terminal output for the randomly generated admin password # — copy it before it scrolls away # Once containers are up, browse to the web UI # URL: http://localhost:8080 # Username: admin Password: <the generated password from logs> # You will be forced to set a new password on first login -
2
Download SharpHound and collect AD data. SharpHound is the official collector — a Windows binary that queries Active Directory via LDAP and enumerates live sessions via SMB. It must run from a domain-joined Windows machine (does not require admin rights for standard collection).
# In the BloodHound CE web UI: click "Download Collectors" # in the left menu, then download SharpHound for your OS # Copy SharpHound.exe to your domain-joined Windows lab VM, then run: PS> .\SharpHound.exe -c All -OutputDirectory C:\Temp\ # Collection methods explained: # All — full collection (sessions, ACLs, group membership, trusts) # Session — only active logon sessions (lighter, stealthier) # LoggedOn — currently logged-on users per computer # SharpHound produces a timestamped ZIP of JSON files in C:\Temp\ # e.g. 20260615120000_BloodHound.zip -
3
Ingest data and run pathfinding queries. Drag the ZIP file into the BloodHound CE web UI (Upload Files button). Once ingested, use the built-in Cypher queries under the "Analysis" tab to find escalation paths.
-- In the BloodHound UI, these are available as pre-built buttons -- under Analysis tab. Their underlying Cypher logic: -- Find all Domain Admins MATCH p=(n)-[r:MemberOf*1..]->(g:Group) WHERE g.objectid ENDS WITH '-512' RETURN p -- Find shortest path from a specific user to Domain Admins MATCH p=shortestPath( (u:User {name:'JDOE@CORP.LOCAL'})-[*1..]->(g:Group {name:'DOMAIN ADMINS@CORP.LOCAL'}) ) RETURN p -- Find all Kerberoastable users (the same accounts hunted in Lab 5.1) MATCH (u:User) WHERE u.hasspn=true AND u.enabled=true RETURN u -- Find computers where Domain Users have local admin (lateral movement risk) MATCH p=(g:Group)-[:AdminTo]->(c:Computer) WHERE g.name STARTS WITH 'DOMAIN USERS' RETURN p -
4
Identify and document attack paths. For each path BloodHound surfaces from a low-privilege user to Domain Admin, document the specific edge types involved — common ones include
GenericAll,WriteDacl,ForceChangePassword, andAddMember. Prioritise remediation on paths with the fewest hops first — they're the easiest for an attacker to find and exploit. -
5
Hunt for evidence that an attacker already ran SharpHound against you. SharpHound's LDAP queries and SMB session enumeration generate a distinctive volume and pattern of traffic. Hunt your logs for the indicators below.
-- Hunt: bulk LDAP queries from a single workstation (not a DC or admin tool) SELECT SourceComputer, COUNT(*) AS ldap_query_count, COUNT(DISTINCT ObjectClass) AS unique_object_types FROM LdapQueryLogs WHERE TimeGenerated > DATEADD(hour, -1, NOW()) GROUP BY SourceComputer HAVING ldap_query_count > 1000 -- Hunt: Sysmon Event 1 — SharpHound.exe or known process name variants SELECT TimeGenerated, Computer, User, Image, CommandLine FROM SysmonEvents WHERE EventID = 1 AND (Image LIKE '%SharpHound%' OR CommandLine LIKE '%Invoke-BloodHound%' OR CommandLine LIKE '%CollectionMethod%') -- Hunt: a single host opening SMB sessions to an unusually high number -- of other computers in a short window (SharpHound's session enumeration) SELECT src_ip, COUNT(DISTINCT dst_ip) AS unique_targets FROM netflow WHERE dst_port = 445 AND TimeGenerated > DATEADD(minute, -15, NOW()) GROUP BY src_ip HAVING unique_targets > 50
🧠 Reflection questions
- Why does SharpHound not require administrative privileges for standard LDAP-based collection, and what does this imply about your ability to detect reconnaissance versus exploitation?
- You find a 3-hop attack path from a marketing department user account to Domain Admin via nested group membership. Describe the remediation options and their tradeoffs.
- How would you use BloodHound output to prioritise the Kerberoasting hardening work from Lab 5.1 — which accounts should be fixed first?
Threat intelligence integration
Threat intelligence transforms raw data into actionable hunt hypotheses. This domain covers consuming MISP feeds, pivoting on IOCs, and mapping adversary behaviour to MITRE ATT&CK to prioritise hunts.
Learning objectives
- Understand structured threat intelligence formats: STIX 2.1, TAXII, OpenIOC
- Consume and pivot on IOCs from MISP, VirusTotal, and Shodan
- Convert a threat report into a set of hunt hypotheses
- Build an intelligence-driven hunt campaign for a specific threat actor
-
1
Read a threat report and extract IOCs. Take a recent public report (e.g. CISA alert, Mandiant/Google TAG report, or Unit 42 blog). Extract: IP addresses, domains, file hashes, email addresses, user-agent strings, file paths, and registry keys mentioned. Structure them by type.
-
2
Enrich on VirusTotal. For each domain or IP IOC, use the VirusTotal API to get: detection ratio, passive DNS history, associated files, communicating samples, and related IOCs. Pivot to find infrastructure clusters.
import requests API_KEY = "your_vt_api_key" domain = "suspicious-domain.com" resp = requests.get( f"https://www.virustotal.com/api/v3/domains/{domain}", headers={"x-apikey": API_KEY} ) data = resp.json()['data']['attributes'] print("Malicious detections:", data['last_analysis_stats']['malicious']) print("Creation date:", data.get('creation_date')) print("Registrar:", data.get('registrar')) print("Categories:", data.get('categories',{})) # Then pivot: /domains/{domain}/communicating_files # /domains/{domain}/resolutions -
3
Pivot on Shodan for infrastructure clustering. Use SSL certificate serial numbers, favicon hashes, or HTTP response headers shared across C2 servers to find the full attacker infrastructure, not just the IOCs disclosed in the report.
# Find servers with the same SSL cert as a known C2 $ shodan search 'ssl.cert.serial:1234567890' \ --fields ip_str,port,org,hostnames # Find servers with identical Cobalt Strike default cert $ shodan search 'ssl.cert.subject.cn:"Major Cobalt Strike"' # Favicon hash pivot (identify same C2 panel on multiple IPs) $ shodan search 'http.favicon.hash:-1685456514' -
4
Hunt your environment. Take every enriched IOC and query your SIEM, DNS logs, proxy logs, and firewall logs for any historical or current contact. A match means you may already be compromised or have been targeted.
🧠 Reflection questions
- An IOC in a threat report is 6 months old. What is the risk of hunting it without further validation, and how would you assess its current relevance?
- Describe the concept of "diamond model" pivoting and how it expands a single IOC into a full adversary infrastructure map.
Learning objectives
- Deploy a MISP instance and understand its event/attribute data model
- Create a threat intelligence event manually from a CTI report
- Import a public MISP feed and correlate it against your own organisational IOCs
- Export IOCs in formats consumable by a SIEM (Sigma, STIX, plain IOC lists)
- Understand MISP's role as the hub connecting CTI, hunting, and detection engineering
Lab 6.1 used VirusTotal and Shodan for ad-hoc IOC enrichment — useful for a single pivot. MISP solves a different problem: it is the central, shared, structured repository where your organisation's IOCs, your hunt findings, and external threat feeds all live together and automatically correlate against each other. When you add a new IOC to MISP, it instantly checks it against every other event already stored — including ones from six months ago that you may have forgotten about.
-
1
Deploy MISP via Docker. The official MISP Docker image is the fastest path to a working instance for lab purposes.
# Clone the official MISP Docker repository # git clone https://github.com/MISP/misp-docker.git # cd misp-docker # Copy the example environment file and adjust as needed # cp template.env .env # Build and start all containers (MISP app, MySQL, Redis) # docker compose build # docker compose up -d # Wait 2-3 minutes for first-time database initialisation, then browse to: # URL: https://localhost:443 # Default credentials: admin@admin.test / admin # You will be forced to change the password on first login -
2
Create your first event manually. Take the IOCs you extracted from a threat report in Lab 6.1 and structure them as a proper MISP Event — this is how your own hunt findings get permanently stored and shared.
// In the MISP web UI: 1. Click "Event Actions" → "Add Event" 2. Set Event Info: "Hunt Finding - Suspected Lazarus C2 Infrastructure" 3. Set Threat Level, Analysis stage, and Distribution (keep "Your organisation only" for lab use) 4. Click "Add Attribute" for each IOC: - Category: Network activity | Type: ip-dst | Value: <the C2 IP> - Category: Network activity | Type: domain | Value: <the C2 domain> - Category: Payload delivery | Type: sha256 | Value: <malware hash> 5. Tag the event with MITRE ATT&CK techniques using the "galaxy" tagging feature — search "mitre-attack-pattern" and add T1071, T1059 etc. 6. Click "Publish Event" to make it active for correlation -
3
Import a public feed for correlation. MISP ships with pre-configured connections to free community feeds (CIRCL, abuse.ch, Botvrij.eu). Enable one and let it sync — every IOC it brings in will auto-correlate against your existing events.
// In the MISP web UI: 1. Navigate to "Sync Actions" → "List Feeds" 2. Find "abuse.ch ssl-ip-blacklist" or "CIRCL OSINT Feed" in the list 3. Toggle "Enable" on the feed, then click "Fetch and store all feed data" 4. Wait for the import to complete (progress shown in the UI) 5. Navigate to "Event Actions" → "List Events" and observe the new feed events now listed alongside your manual one 6. Click any IOC value and MISP shows a "Correlation" tab — any match against your own hunt event will appear here automatically -
4
Export IOCs for SIEM consumption. MISP can export any event or filtered IOC set in formats your SIEM or detection pipeline can ingest directly.
// Via web UI: open an event → "Download as" dropdown offers: // STIX 2.1, plain IOC list (.txt), Sigma rule, Suricata rules, CSV # Via REST API — pull all published IOCs from the last 24 hours # curl -k -H "Authorization: <your-api-key>" \ -H "Accept: application/json" \ "https://localhost/attributes/restSearch/last:1d" \ -o recent_iocs.json # Your API key is found under: My Profile → Auth Keys (top right menu)
Before considering this lab complete: (1) MISP web UI is accessible at https://localhost. (2) At least one manually created event with 3+ attributes exists. (3) At least one community feed has been enabled and synced. (4) You have successfully exported an event in at least one format (STIX, Sigma, or CSV).
🧠 Reflection questions
- A new IOC arrives via a community feed and MISP shows it correlates with an event you created three months ago that you had completely forgotten about. What does this tell you about the value of structured, persistent IOC storage versus ad-hoc spreadsheets?
- How would you decide which MISP distribution level (organisation only, community, connected communities, all) to use when publishing a hunt finding that involves a real attack against your organisation?
- Describe how MISP's MITRE ATT&CK galaxy tagging feature could feed directly into the ATT&CK Navigator coverage exercise from the Lab 6.3 capstone.
Learning objectives
- Synthesise skills from all domains — including endpoint, cloud, and AI-assisted hunting — into a single end-to-end campaign
- Select a real threat actor, map their TTPs, and design a targeted hunt
- Practise detection engineering as a formal discipline — not just an informal hunt byproduct
- Measure and visualise detection coverage using the MITRE ATT&CK Navigator
- Present findings as a formal hunt brief suitable for a SOC or CISO audience
Hunting and detection engineering are related but distinct. A hunt is a one-time investigation of a hypothesis. Detection engineering is the discipline of converting validated hunt findings into permanent, tuned, automated detection content — and tracking how that content maps to ATT&CK coverage over time. Modern hunt teams treat every successful hunt as raw material for the detection engineering pipeline: hunt finding → Sigma rule (or Velociraptor VQL artifact) → false-positive tuning → deployment → ATT&CK Navigator coverage update → periodic re-validation as the environment changes. This capstone requires you to complete the full pipeline, not just the hunt.
Choose one of the following threat actor profiles. Research their TTPs using public sources (MITRE ATT&CK groups, CISA advisories, vendor reports). Design a complete hunt campaign targeting their methods in a simulated enterprise environment — spanning endpoint, network, identity, and cloud where relevant. Produce a written hunt brief, a detection engineering pipeline, and an ATT&CK Navigator coverage layer.
Lazarus Group (APT38)
North Korean actor targeting financial institutions and crypto exchanges. Known for SWIFT fraud, destructive malware, and supply chain attacks.
Nation-stateBlackCat / ALPHV
Ransomware-as-a-service group. Uses Rust-based ransomware, exfiltration-before-encryption, triple extortion, and a dedicated Linux encryptor for VMware ESXi hosts (see Lab 7.3).
RansomwareAPT29 (Cozy Bear)
Russian SVR-linked actor. Masters of supply chain compromise (SolarWinds), living-off-the-land, cloud identity abuse, and long-dwell-time operations.
Espionage- 1
Intelligence gathering. Collect all publicly available TTP documentation for your chosen actor. Map every technique to a MITRE ATT&CK ID — including, where relevant, ESXi and Cloud platform techniques introduced in ATT&CK v17. Identify which TTPs your environment has logging coverage for.
- 2
Gap analysis with ATT&CK Navigator. Create an ATT&CK Navigator layer for your chosen actor. Colour-code each technique: green (full detection coverage), amber (partial/log-only coverage), red (no coverage). For every red or amber cell, document what data source would close the gap (e.g. "T1055 process injection — amber, have Sysmon Event 10 but no memory scanning — would need Velociraptor malfind artifact for full coverage").
- 3
Hunt design. Write 5 structured hunt hypotheses, each referencing a specific TTP, the data source needed, the query logic, and the expected true positive rate. Use an AI assistant to draft the initial query syntax, then validate and correct it manually — this mirrors the actual 2026 hunt workflow described in the AI-Assisted Hunting section.
- 4
Execute hunts. Run each hypothesis against your lab data (use EVTX samples from EVTX-ATTACK-SAMPLES, CloudGoat for AWS techniques, or KC7 Cyber for Azure KQL techniques, depending on which TTPs you're testing).
- 5
Detection engineering pipeline. For every confirmed finding, produce: (a) a tuned Sigma rule or Velociraptor VQL artifact, (b) a documented false-positive test against at least one known-clean dataset, and (c) an updated ATT&CK Navigator cell moved from red/amber to green.
- 6
Deliver the hunt brief. Write a 2-page executive summary covering: actor profile, hunt methodology, findings (confirmed / not observed / insufficient data), the detection engineering outputs produced, the before/after ATT&CK Navigator coverage comparison, and priority hardening actions.
🧠 Final capstone questions
- Which of the actor's TTPs posed the highest risk to your simulated environment, and why?
- How would your hunt strategy differ if you were operating in a cloud-native environment (AWS/Azure) rather than an on-premises Active Directory environment? Did this capstone require you to combine both?
- Describe what "detection coverage" means and how you used the ATT&CK Navigator to measure and communicate it before and after your capstone hunt.
- Where in your pipeline did an AI assistant save time, and where did it produce incorrect or hallucinated output that required manual correction?
AI-assisted threat hunting
AI is not replacing threat hunters — it is automating the repetitive analytical burden so hunters can focus on high-judgment decisions. Understanding where AI fits in the hunt workflow is now a literacy requirement for anyone entering the field in 2025–2026.
The traditional three-layer hunt stack (TIP → SIEM → EDR) places the entire analytical burden on human analysts: they write the queries, correlate the telemetry, build the hypotheses, and chase them manually. AI tools now automate specific steps in this chain — but the hunter still drives the process.
Natural language → SIEM query
Tools like Microsoft Copilot for Security, Elastic AI Assistant, and Splunk AI translate plain English hunt questions into SPL, KQL, or Lucene queries — lowering the barrier for junior analysts.
Query generationAutomated IOC enrichment
Platforms like Recorded Future AI and Mandiant Threat Intelligence automatically enrich raw IOCs with context — actor attribution, campaign history, infrastructure clusters — in seconds.
Intel enrichmentHypothesis generation from CTI
Tools like Rapid7's AI hunt pipeline ingest threat reports and automatically extract MITRE ATT&CK techniques, generating hunt hypotheses and detection content (Sigma, VQL, YARA) without manual mapping.
Hypothesis automationAI SOC agents (emerging)
Platforms like Dropzone AI deploy autonomous AI agents that triage alerts, run investigation playbooks, and escalate only confirmed findings to human analysts — handling tier-1 SOC workload.
Autonomous triageAI tools hallucinate, miss novel attack patterns not in training data, and cannot apply business context (e.g. "this unusual process is expected because of a deployment tonight"). Human hunters retain critical value in: forming creative hypotheses from sparse signals, contextualising findings against business operations, making final attribution judgments, and hunting zero-day techniques with no prior signature. The hunter's job is evolving — not disappearing.
Practical exercise: Take any hunt hypothesis from this workbook and use a free AI assistant (Claude, ChatGPT, or Microsoft Copilot) to: (1) translate the hypothesis into a SIEM query for your platform, (2) suggest three related techniques that should be hunted alongside it, and (3) generate a Sigma rule from your findings. Evaluate the output critically — does it match the platform syntax exactly? Does the logic hold? This is the workflow of a 2026 threat hunter.
These four labs follow the same four stops in the hunt loop shown above — query generation, hypothesis generation, detection engineering, and triage. Each one hands you real AI output that looks complete on the surface but has a genuine, verifiable gap built into it. Your job in every lab is the same: find the gap before you'd trust the output in production. That's the actual skill this section is teaching — not how to prompt an AI assistant, but how to supervise one.
This is the query-generation stage of the hunt loop — the step AI tools are best at, because it's mostly translation, not judgment. The point of this lab isn't to prove AI can write KQL. It's to show you that "syntactically correct" and "logically complete" are two different things, and that gap is exactly where a hunter's technique knowledge still has to do the work an AI can't.
Learning objectives
- Use a free AI assistant to translate a hunt hypothesis into a working SIEM query
- Identify a real adversary evasion technique (PowerShell argument abbreviation) that naive AI-generated detection logic typically misses
- Diagnose a schema mismatch between AI-assumed field names and your actual data source
- Practice the core 2026 hunter skill: verifying AI output against ground truth rather than trusting it on sight
Adversaries are using PowerShell with Base64-encoded commands to evade plaintext detection and logging. Hunt for encoded PowerShell execution across endpoint process creation logs.
Synthetic process-creation dataset — 12 events. Six are malicious. Do not read the verdict column until after you've run your AI-generated query.
| ID | Parent Process | Process | CommandLine | Verdict |
|---|---|---|---|---|
| 1 | explorer.exe | powershell.exe | powershell.exe -File C:\Scripts\backup.ps1 | Legit |
| 2 | outlook.exe | powershell.exe | powershell.exe -EncodedCommand SQBFAFgA... | Malicious |
| 3 | winword.exe | powershell.exe | powershell.exe -enc JABzAD0AT... | Malicious |
| 4 | services.exe | svchost.exe | svchost.exe -k netsvcs | Legit |
| 5 | cmd.exe | powershell.exe | powershell -e cwB0AGEAcgB0AC0AcAByAG8A... | Malicious — seeded gap |
| 6 | explorer.exe | powershell.exe | powershell.exe Get-Process | Legit |
| 7 | mshta.exe | powershell.exe | powershell -en dwByAGkAdABlAC0ATwB1AHQAcAB1AHQA... | Malicious — seeded gap |
| 8 | taskeng.exe | powershell.exe | powershell.exe -NoProfile -File C:\ProgramData\update.ps1 | Legit |
| 9 | rundll32.exe | powershell.exe | powershell.exe -nop -w hidden -encodedcommand JABzAGgAZQBsAGwA... | Malicious |
| 10 | winlogon.exe | userinit.exe | userinit.exe | Legit |
| 11 | wscript.exe | powershell.exe | powershell -ec YQBkAGQALQBtAHAAcgBlAGYAZQByAGUAbgBjAGUA... | Malicious — seeded gap |
| 12 | explorer.exe | powershell.exe | powershell.exe -Command "Get-ChildItem" | Legit |
-
1
Get the AI-generated query. Prompt Claude, ChatGPT, or Copilot for Security to translate the hunt hypothesis above into a KQL query (Defender/Sentinel
DeviceProcessEventsschema) or SPL query (Splunk). Copy the output exactly — do not edit it yet.// What most AI assistants produce on the first prompt DeviceProcessEvents | where ProcessCommandLine has_any ("-enc", "-EncodedCommand") | project Timestamp, DeviceName, ProcessCommandLine -
2
Run it against the dataset above. No SIEM sandbox available? Just check the query logic by hand against each
CommandLinevalue in the table. Mark which of the 12 rows your query would match. -
3
Reveal the verdicts and score your query. Compare your matches against the Verdict column. A query that only matches
-enc/-EncodedCommandwill catch rows 2, 3, and 9 — and silently miss rows 5, 7, and 11. That's a 50% false negative rate on a query that looked complete. -
4
Diagnose the root cause. PowerShell allows
-EncodedCommandto be abbreviated to any unambiguous prefix —-e,-en,-ec,-enco, and so on all execute identically. Adversaries deliberately use short or unusual abbreviations specifically because most detection content — human-written or AI-generated — only checks the two most "obvious" strings. This is a real, documented evasion technique, not an artificial trick. -
5
Correct the query — and weigh the tradeoff. A broader prefix match catches all six malicious rows, but risks flagging legitimate flags like
-ErrorActionor-Encodingthat also start with "e". Document how you'd tune around that.// Matches -e, -en, -enc ... -encodedcommand as a standalone argument // Tune the regex boundary to avoid matching -ErrorAction, -Encoding, etc. DeviceProcessEvents | where ProcessCommandLine matches regex @"(?i)\s-e(n(c(o(d(e(d(c(o(m(m(a(n(d)?)?)?)?)?)?)?)?)?)?)?)?\b" | project Timestamp, DeviceName, ProcessCommandLine -
6
Check the field name your AI assumed. This dataset uses
CommandLine(Sysmon convention). If your AI defaulted toProcessCommandLine(Defender convention) without you specifying a platform, note it. A logically perfect query against the wrong field name returns zero results — and "zero results" is easy to misread as "no threat found" instead of "wrong schema."
Write up: (1) how many of the 6 malicious rows your original AI query caught, (2) the specific technique that explains what it missed, (3) your corrected query with the false-positive tradeoff discussed, and (4) whether your AI tool assumed the correct schema. A clean, unedited AI-generated query submitted with no diagnosis scores zero on this lab — the artifact isn't the point, catching where it's wrong is.
🧠 Reflection questions
- If you were a junior analyst under time pressure, what would have made you stop and question the AI's query instead of trusting the first result?
- Name one other command-line tool (besides PowerShell) that supports argument abbreviation or aliasing an adversary could exploit the same way.
- What baseline knowledge did you need to already have in order to catch this gap? Could an analyst with zero PowerShell background have caught it just by reading the AI's query?
This is the hypothesis-generation stage — the highest-leverage and highest-risk use of AI in the hunt loop. Turning a CTI report into ATT&CK-mapped hypotheses in seconds is genuinely powerful. It's also where a wrong technique mapping does the most damage, because everything downstream — the query you write, the scope of the hunt, the response plan — inherits that mapping without anyone re-checking it. This lab trains you to re-check it.
Learning objectives
- Use an AI assistant to extract MITRE ATT&CK techniques from an unstructured threat report and generate hunt hypotheses
- Identify a technique the AI mis-mapped to a more commonly-documented alternative, and one it skipped over entirely
- Understand why the correct mapping changes the scope and response of the hunt, not just its label
Initial access was achieved via a spear-phishing email containing a malicious OneNote attachment. Execution of the attachment dropped an HTA loader, which established a command-and-control channel over HTTPS to a domain mimicking a legitimate CDN provider. The actor then used compromised domain admin credentials to modify a Group Policy Object, pushing a startup script to all domain-joined workstations that re-established the implant on every reboot. Lateral movement was carried out via WMI, and the actor staged collected files inside a hidden NTFS alternate data stream before exfiltrating them to a cloud storage bucket over port 443.
-
1
Extract techniques and hypotheses. Paste the report extract into Claude, ChatGPT, or Copilot and ask it to identify every MITRE ATT&CK technique present and generate a corresponding hunt hypothesis for each. Copy the full output.
-
2
Check your list against ground truth. The report describes seven techniques. Most AI assistants correctly identify five or six on the first pass. Reveal the table below and mark what your output got right, mis-mapped, or missed entirely.
Behaviour in report Correct ATT&CK technique Common AI error Spear-phishing OneNote attachment T1566.001 — Spearphishing Attachment Usually caught correctly HTA loader execution T1218.005 — Mshta Usually caught correctly C2 over HTTPS T1071.001 — Web Protocols Usually caught correctly GPO edit pushes startup script, re-persists on reboot T1484.001 — Group Policy Modification Frequently mis-tagged as T1053.005 (Scheduled Task) — reboot persistence pattern-matches to the more common technique Lateral movement via WMI T1047 — Windows Management Instrumentation Usually caught correctly Files staged in hidden ADS T1564.004 — Hide Artifacts: NTFS File Attributes Frequently skipped entirely — mentioned in a subordinate clause, easy to skim past Exfil to cloud storage over 443 T1567.002 — Exfiltration to Cloud Storage Usually caught correctly -
3
Explain why the GPO mis-mapping matters operationally, not just semantically. A Scheduled Task hunt scopes to the local host — you'd check Task Scheduler on FS02. Group Policy Modification is a domain-wide persistence mechanism — the correct hunt scopes to every domain-joined workstation and requires auditing GPO edit permissions and SYSVOL, not local task entries. Mapping this to the wrong technique means hunting the wrong footprint.
-
4
Write the corrected hypothesis. Draft a hunt hypothesis for T1484.001 specifically — for example: "An adversary with compromised domain admin credentials has modified a GPO to push malicious startup scripts. Hunt Windows Security Event ID 5136 (directory service object modified) scoped to GPO container objects, filtered to changes made outside change-management windows."
Submit your annotated version of the table above (what your AI output got right/wrong), a one-paragraph explanation of why the GPO vs. Scheduled Task distinction changes hunt scope, and your corrected T1484.001 hypothesis from step 4.
🧠 Reflection questions
- Why would an AI model default to the more commonly-documented technique (Scheduled Task) over a less common but textually-supported one (GPO Modification)?
- What real-world consequence follows from scoping this hunt to one host instead of the whole domain?
- If you didn't already know ATT&CK reasonably well, what in the AI's output would have tipped you off to check further?
This is the detection-engineering stage — turning a validated hunt finding into a rule that runs unattended, every day, without a human checking it each time. That makes it the least forgiving stage for errors. This lab chains directly off Lab AI.1: you already know your corrected query works. The question here is whether AI preserves that fix when it converts your query into a different format — or quietly reverts it.
Learning objectives
- Convert a validated detection query into a Sigma rule using an AI assistant
- Detect when a format conversion has silently dropped logic that was present in the source query
- Validate a Sigma rule's field names and logsource metadata against your actual data schema before treating it as deployable
-
1
Convert your Lab AI.1 fix. Take the corrected, abbreviation-aware KQL query from Lab AI.1 step 5 and ask your AI assistant to convert it into a Sigma rule. Copy the output exactly.
-
2
Compare against a typical first-pass conversion. Most AI assistants regress to a plain keyword list when converting to Sigma's YAML syntax, because the
containsmodifier doesn't map cleanly onto a regex without being explicitly told to preserve it:# The abbreviation-handling regex from Lab AI.1 has silently disappeared title: Encoded PowerShell Command Execution status: experimental logsource: category: process_creation product: windows detection: selection: CommandLine|contains: - '-enc' - '-EncodedCommand' condition: selection level: highRun this rule against the Lab AI.1 dataset by hand again. Rows 5, 7, and 11 slip through a second time — the exact gap you already fixed once, reintroduced by the conversion step.
-
3
Fix the regression. Sigma supports a regex modifier that can carry your original logic across. Explicitly prompt for it, or write it yourself:
title: Encoded PowerShell Command Execution (Abbreviation-Aware) status: experimental logsource: category: process_creation product: windows detection: selection: CommandLine|re: '(?i)\s-e(n(c(o(d(e(d(c(o(m(m(a(n(d)?)?)?)?)?)?)?)?)?)?)?)?\b' condition: selection level: highNote the tradeoff either way: the regex form is precise but harder for other analysts to read at a glance; an enumerated list (
-e,-en,-enc... spelled out individually) is more readable but easy to leave incomplete. Document which you chose and why. -
4
Validate the schema, not just the logic. A Sigma rule's
logsourceblock only means something once it's run through a backend pipeline (e.g. pySigma) that mapscategory: process_creationto your actual product's field names and event IDs. Confirm — using the Sigma project's ownsigma converttool or your platform's pipeline docs — thatCommandLinemaps to a field that actually exists in your data source. A rule that's logically perfect but points at a field your schema doesn't have will deploy silently and catch nothing.
Submit both Sigma rules (the regressed version and your corrected version), a one-line note on which modifier approach you chose and its tradeoff, and confirmation that you checked the logsource/field mapping against a real backend pipeline rather than assuming it was correct.
🧠 Reflection questions
- Why would converting between two correct, well-documented formats (KQL and Sigma) silently drop working logic?
- What's the operational risk of deploying a Sigma rule you generated but never re-tested against ground truth?
- Name one other rule format (YARA, Suricata) where this same conversion-regression risk could occur.
This is the capstone, and it's deliberately different from the first three. Labs AI.1–AI.3 all trained you to catch AI being technically wrong. This one is about the thing the "what AI cannot replace" box earlier in this section names directly: business context. There's no query fix or regex here — the exercise is deciding, and justifying, a judgment call an AI agent structurally cannot make on its own. It also carries a twist: the human-provided context you're trusting can itself be wrong or fabricated, so the exercise doesn't end at "the AI missed context" — it ends at "did you verify the context too."
Learning objectives
- Recognize why an AI triage agent will flag a benign, business-justified alert the same way it flags a genuine incident
- Make and justify an informed override decision using business context an AI agent doesn't have access to
- Independently corroborate the context artifact itself, rather than trusting it by default
Same underlying technical alert, two scenarios. Read both before deciding.
02:14 AM — PSEXESVC.exe created on FS02, spawned by admin account j.ramirez from workstation WKS-114. Followed by net use \\FS02\ADMIN$ and access to \\FS02\Finance$\Q3_Reports\.
-
1
Scenario A — no additional context. Prompt an AI assistant to triage the alert above as if it were an AI SOC agent (e.g. "Is this alert malicious? Should it be escalated or closed?"). Record its recommendation.
-
2
Scenario B — with a change ticket. Re-run the same triage prompt, this time including: "CHG0004521 — approved maintenance window 01:00–04:00, scope: patch deployment to FS02 via PsExec, performed by j.ramirez, approved by IT Manager." Record whether the AI's recommendation changes, and how confidently.
-
3
Decide Scenario B for yourself. Would you close this as benign? Write your justification — and notice whether you're leaning on the ticket alone, or on something more.
-
4
Now corroborate the ticket itself. The change ticket is also just an artifact — it could be forged, or a genuine ticket could exist while the account executing it is separately compromised. Before closing the alert, name at least one independent check you'd run: confirming the ticket's status directly in the ITSM system rather than trusting a pasted description, checking j.ramirez's normal login hours and behavioural baseline, verifying the approval chain, or confirming PsExec is your organization's sanctioned deployment tool for this kind of change.
Submit both AI triage outputs (Scenario A and B), your closure decision for Scenario B with written justification, and the specific independent corroboration step you'd take before actually closing the ticket — not just "I'd trust the change ticket."
🧠 Reflection questions
- Is trusting an AI's triage recommendation a different kind of risk than trusting a human-provided artifact the AI can't verify? Why or why not?
- Could an attacker who has compromised a helpdesk or ITSM account defeat this entire exercise? What would catch that?
- Per your organization's escalation policy, where should the final closure decision sit for an alert like this — with a human, an AI agent, or a specific role? Why?
Cloud threat hunting
Cloud environments introduce entirely new attack surfaces — identity-based attacks, misconfigured storage, API abuse, and serverless function exploitation — that traditional endpoint and network hunting tools cannot see. This domain covers hunting in AWS and Azure, the two dominant enterprise cloud platforms.
In on-premises environments, the attacker needs to compromise an endpoint. In the cloud, the attacker can achieve full environment compromise by stealing a single IAM credential or API key — without ever touching an endpoint. There is no "process injection" in S3. The primary data sources shift from endpoint telemetry to API call logs, identity logs, and resource configuration changes.
On-premises hunting
Cloud hunting
Learning objectives
- Understand AWS CloudTrail as the primary hunt data source and its log structure
- Detect IAM credential theft, privilege escalation, and lateral movement via AssumeRole
- Hunt for S3 bucket data exfiltration and unusual GetObject/ListBuckets patterns
- Use AWS GuardDuty findings to trigger and guide hunt hypotheses
- Map cloud attack techniques to MITRE ATT&CK for Cloud
An attacker has compromised an IAM access key (via exposed .env file, GitHub leak, or phishing) and is using it to enumerate permissions, escalate privileges via AssumeRole, and exfiltrate data from S3 buckets.
Use CloudGoat by Rhino Security Labs — a free, deliberately vulnerable AWS environment designed for learning cloud attack and hunt techniques. Deploy it with Terraform into your own AWS free-tier account. Alternatively, use CloudTrail log samples from the aws-cloudtrail-lake-workshop GitHub repository for offline analysis without an AWS account.
-
1
Enable and understand CloudTrail. CloudTrail records every API call made to your AWS account — who called what, from where, when, and with what result. Ensure CloudTrail is enabled in all regions with S3 log delivery. For hunting, ingest CloudTrail logs into AWS Athena or your SIEM.
# CloudTrail JSON record — key hunt fields { "eventTime": "2025-06-01T02:14:33Z", // when "eventSource": "iam.amazonaws.com", // which AWS service "eventName": "CreateAccessKey", // what action "userIdentity": { "type": "IAMUser", "userName": "svc-deploy", // who "arn": "arn:aws:iam::123456789:user/svc-deploy" }, "sourceIPAddress": "185.220.101.47", // from where (Tor exit!) "userAgent": "aws-cli/2.13.0", "errorCode": "AccessDenied", // result "requestParameters": { "userName": "admin" } // target } -
2
Hunt IAM enumeration — attacker reconnaissance. After stealing a credential, an attacker's first action is to determine what permissions it has. Bulk IAM enumeration calls from a single identity in a short window is a high-confidence initial access indicator.
-- Hunt: many IAM read calls from one identity in short window SELECT useridentity.arn, useridentity.username, sourceipaddress, COUNT(*) AS api_calls, COUNT(DISTINCT eventname) AS unique_actions, MIN(eventtime) AS first_seen, MAX(eventtime) AS last_seen, array_agg(DISTINCT eventname) AS actions_taken FROM cloudtrail_logs WHERE eventsource = 'iam.amazonaws.com' AND eventname IN ( 'ListUsers', 'ListRoles', 'ListPolicies', 'GetUser', 'GetRole', 'ListAttachedUserPolicies', 'SimulatePrincipalPolicy', 'GetAccountAuthorizationDetails') AND eventtime > date_add('hour', -1, NOW()) GROUP BY useridentity.arn, useridentity.username, sourceipaddress HAVING unique_actions > 5 ORDER BY api_calls DESC -
3
Hunt privilege escalation via AssumeRole. AssumeRole lets an identity temporarily become another role — including higher-privileged ones. Attackers chain AssumeRole calls to hop from a low-privilege compromised role to an admin role. Hunt for unusual cross-account or cross-role assumptions.
-- Hunt: AssumeRole into high-privilege roles from unexpected sources SELECT eventtime, useridentity.arn AS caller, requestparameters.roleArn AS assumed_role, sourceipaddress, useragent, errorcode FROM cloudtrail_logs WHERE eventname = 'AssumeRole' AND (requestparameters.roleArn LIKE '%Admin%' OR requestparameters.roleArn LIKE '%PowerUser%' OR requestparameters.roleArn LIKE '%FullAccess%') AND useridentity.type = 'IAMUser' -- humans, not services AND eventtime > date_add('day', -7, NOW()) ORDER BY eventtime DESC -
4
Hunt S3 data exfiltration. Mass GetObject calls — especially to buckets containing sensitive data, from an unusual IP or user agent — indicate data exfiltration. Look for high byte-count downloads from service accounts or off-hours access.
-- Hunt: bulk S3 GetObject from unusual identity or IP SELECT useridentity.arn, sourceipaddress, requestparameters.bucketName AS bucket, COUNT(*) AS get_requests, SUM(CAST(additionaleventdata.bytesTransferredOut AS BIGINT)) AS total_bytes_out FROM cloudtrail_logs WHERE eventsource = 's3.amazonaws.com' AND eventname = 'GetObject' AND eventtime > date_add('hour', -24, NOW()) GROUP BY useridentity.arn, sourceipaddress, requestparameters.bucketName HAVING get_requests > 500 OR total_bytes_out > 1073741824 -- 1 GB ORDER BY total_bytes_out DESC -
5
Use GuardDuty findings as hunt triggers. AWS GuardDuty provides ML-based anomaly detection for CloudTrail, VPC Flow Logs, and DNS logs. High-severity GuardDuty findings (e.g.
UnauthorizedAccess:IAMUser/TorIPCaller,Recon:IAMUser/UserPermissions) should immediately trigger a hunt using the queries above to understand the full scope of activity.
🧠 Reflection questions
- An attacker uses an EC2 instance metadata service (IMDS) to steal the IAM role credentials attached to a compromised EC2 instance. What CloudTrail events would you see, and how does the sourceIPAddress field differ from an external attacker?
- How would you build a baseline of "normal" AssumeRole patterns to reduce false positives in your detection, given that legitimate DevOps tools also frequently use AssumeRole?
- Describe the MITRE ATT&CK Cloud techniques involved in a full attack chain: leaked access key → IAM enumeration → AssumeRole escalation → S3 exfiltration.
Learning objectives
- Navigate Microsoft Sentinel as a cloud-native SIEM and hunt platform
- Write KQL (Kusto Query Language) queries for Azure AD sign-in anomalies
- Detect OAuth application abuse — a primary Azure AD attack vector in 2025–2026
- Hunt for impossible travel, password spray, and MFA fatigue attacks in Azure AD
- Use Sentinel hunting queries and workbooks for structured hunts
An adversary has compromised an Azure AD account via password spray or phishing and is using it to register a malicious OAuth application, granting persistent access to mailboxes and SharePoint data even after the password is reset.
Microsoft provides a free Sentinel training environment via Microsoft Sentinel Training Lab on GitHub (Azure/Azure-Sentinel). Deploy with one ARM template into a free Azure trial account — it pre-loads sample logs including Azure AD sign-in data, Office 365 audit logs, and simulated attack events. Alternatively use the KC7 Cyber platform which provides free KQL hunting exercises against pre-loaded Azure log datasets.
-
1
Understand key Azure log sources. Microsoft Sentinel ingests multiple log tables. The most critical for identity hunting are
SigninLogs,AADNonInteractiveUserSignInLogs, andAuditLogs.Table Contains Key hunt use SigninLogs Interactive Azure AD sign-ins Password spray, impossible travel, MFA patterns AADNonInteractiveUserSignInLogs App and service sign-ins OAuth token abuse, service principal anomalies AuditLogs Azure AD directory changes New app registrations, role assignments, MFA changes OfficeActivity M365 Exchange, SharePoint, Teams Mail forwarding rules, bulk downloads, DLP events AzureActivity Azure resource CRUD operations VM creation, NSG changes, storage access -
2
Hunt password spray in Azure AD. Password spray against Azure AD produces many failed sign-ins (ResultType != 0) across many accounts from the same IP, with low failure count per account. KQL makes this easy to express with summarise and aggregation operators.
// Hunt: password spray — many accounts, one IP, low per-account failures SigninLogs | where TimeGenerated > ago(1h) | where ResultType != "0" // failed sign-ins only | summarize FailedAttempts = count(), UniqueAccounts = dcount(UserPrincipalName), UniqueUserAgents = dcount(UserAgent), AccountList = make_set(UserPrincipalName, 20) by IPAddress | where UniqueAccounts > 15 and (FailedAttempts / UniqueAccounts) < 3 | sort by UniqueAccounts desc -
3
Hunt impossible travel. A user signing in from London and then Lagos within 30 minutes is physically impossible. This is a strong indicator of credential sharing or compromise. KQL can calculate the time between consecutive sign-ins and flag geographic impossibilities.
// Hunt: impossible travel — same user, different country, short window SigninLogs | where TimeGenerated > ago(24h) | where ResultType == "0" // successful sign-ins only | project TimeGenerated, UserPrincipalName, IPAddress, Location, CountryOrRegion = tostring(LocationDetails.countryOrRegion) | sort by UserPrincipalName asc, TimeGenerated asc | extend PrevCountry = prev(CountryOrRegion), PrevTime = prev(TimeGenerated), PrevUser = prev(UserPrincipalName) | where UserPrincipalName == PrevUser and CountryOrRegion != PrevCountry and CountryOrRegion != "" and PrevCountry != "" and datetime_diff('minute', TimeGenerated, PrevTime) < 60 | project UserPrincipalName, PrevCountry, CountryOrRegion, PrevTime, TimeGenerated, IPAddress -
4
Hunt malicious OAuth application registration. After compromising an account, attackers register a new Azure AD application with broad Graph API permissions (Mail.Read, Files.ReadWrite.All) to maintain access even after password reset. This is one of the most common persistence techniques in Microsoft 365 environments in 2025.
// Hunt: new app registrations with high-sensitivity permissions AuditLogs | where TimeGenerated > ago(7d) | where OperationName in ( "Add application", "Add service principal", "Add delegated permission grant", "Add app role assignment to service principal") | extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName), AppName = tostring(TargetResources[0].displayName), Permissions = tostring(TargetResources[0].modifiedProperties) | where Permissions has_any ( "Mail.ReadWrite", "Files.ReadWrite.All", "Directory.ReadWrite.All", "RoleManagement.ReadWrite") | project TimeGenerated, InitiatedBy, AppName, OperationName, Permissions | sort by TimeGenerated desc // Follow-up: correlate InitiatedBy with SigninLogs // to see if the registering account had suspicious sign-ins // before the app was registered -
5
Hunt MFA fatigue attacks. MFA fatigue (also called MFA bombing or push harassment) floods a user with MFA approval requests until they accidentally approve one. Look for users with many MFA denials followed by a success — especially outside business hours.
// Hunt: many MFA denials then success — MFA fatigue pattern SigninLogs | where TimeGenerated > ago(24h) | where AuthenticationRequirement == "multiFactorAuthentication" | summarize MFA_Denials = countif(ResultType == "500121"), MFA_Success = countif(ResultType == "0"), FirstAttempt = min(TimeGenerated), LastAttempt = max(TimeGenerated) by UserPrincipalName, IPAddress | where MFA_Denials > 5 and MFA_Success > 0 | extend AttackDuration = datetime_diff( 'minute', LastAttempt, FirstAttempt) | where AttackDuration < 60 // all within 1 hour | sort by MFA_Denials desc -
6
Build a Sentinel hunting query. In Microsoft Sentinel, navigate to Hunting → Queries → New Query. Save your most useful KQL hunts here with MITRE ATT&CK technique tags — they become reusable hunt assets for your team and integrate with Sentinel's coverage reporting.
🧠 Reflection questions
- An attacker uses a legitimate VPN service to make impossible travel impossible to detect geographically. What alternative signals in SigninLogs would you use to identify the anomaly?
- How does hunting in Azure AD differ from hunting in on-premises Active Directory at the data model level? What event IDs or log tables are equivalent between the two?
- A new OAuth application is registered by a legitimate developer. How would you tune your detection to distinguish legitimate app registrations from malicious ones without generating excessive false positives?
Learning objectives
- Understand why ESXi is a high-value ransomware and nation-state target
- Know the four new ESXi-specific techniques introduced in MITRE ATT&CK v17 (April 2025)
- Hunt for ESXi admin CLI abuse, VM snapshot deletion, and datastore encryption
- Detect lateral movement from a compromised Windows host onto ESXi infrastructure
VMware ESXi hypervisors are prime ransomware targets: compromise one ESXi host and you can encrypt hundreds of virtual machines simultaneously. Ransomware groups including BlackCat/ALPHV, Royal, and ESXiArgs have developed Linux-based encryptors specifically for ESXi. MITRE added ESXi as a new platform in ATT&CK v17 (April 2025) with 34 adapted techniques and 4 new ESXi-specific ones, reflecting heavy real-world adversary focus on virtualisation infrastructure.
| ATT&CK v17 ESXi technique | ID | What the attacker does |
|---|---|---|
| ESXi Administration Control | T1651 | Abuses ESXi management interfaces (ESXCLI, vSphere API) to execute commands directly on the hypervisor |
| Inhibit System Recovery — Snapshot Deletion | T1490 | Deletes all VM snapshots before encrypting to prevent recovery |
| Data Encrypted for Impact — VMFS | T1486 | Encrypts VMFS datastore files (.vmdk, .vmx) rendering all VMs unbootable |
| Hypervisor CLI Execution | T1059.008 | Uses esxcli, vim-cmd, or esxcfg commands to control VMs at the hypervisor layer |
-
1
Enable ESXi logging and syslog forwarding. By default ESXi logs are local. Forward them to a central syslog/SIEM before an incident occurs — you cannot retrieve them after an attacker has encrypted the host.
# Configure ESXi to forward logs to your SIEM (run in ESXi shell) [root@esxi:~] esxcli system syslog config set --loghost=udp://192.168.1.100:514 [root@esxi:~] esxcli system syslog reload # Key ESXi log files to monitor # /var/log/auth.log — SSH logins and sudo # /var/log/shell.log — ESXi shell commands executed # /var/log/hostd.log — vSphere API calls (VM power, snapshot ops) # /var/log/vpxa.log — vCenter communication # /var/log/vobd.log — hardware and VM events # Verify SSH is logged [root@esxi:~] esxcli system auditrecords local get -
2
Hunt ESXi shell commands — T1059.008. Legitimate ESXi administration rarely involves direct shell access. Any interactive SSH session to ESXi followed by esxcli, vim-cmd, or find/chmod commands should be investigated immediately.
-- Hunt suspicious ESXi shell commands from shell.log SELECT timestamp, hostname, user_id, command, source_ip FROM esxi_shell_logs WHERE command LIKE ANY ( '%vim-cmd vmsvc/snapshot.removeall%', -- snapshot deletion '%for vmid in%', -- VM enumeration loop '%esxcli vm process kill%', -- VM shutdown before encrypt '%chmod +x%', -- making dropped binary executable '%openssl enc%', -- encryption tool '%find / -name *.vmdk%') -- locating VM disk files ORDER BY timestamp DESC -- Also hunt: new files created in /vmfs/volumes/ — T1486 SELECT timestamp, filename, file_path, size_bytes FROM esxi_file_events WHERE file_path LIKE '%/vmfs/volumes/%' AND filename LIKE ANY ('%.args%', '%.key%', '%.lock%') -
3
Hunt VM snapshot deletion — T1490. The most reliable pre-ransomware indicator on ESXi is bulk snapshot deletion. Ransomware operators delete all snapshots first so victims cannot restore VMs without paying. This produces a burst of
RemoveSnapshot_Taskevents in hostd.log.-- Hunt: many RemoveSnapshot events in short window = imminent encryption SELECT timestamp, user_name, source_ip, vm_name, operation, COUNT(*) AS snapshot_removals FROM esxi_hostd_logs WHERE operation IN ( 'RemoveSnapshot_Task', 'RemoveAllSnapshots_Task') AND timestamp > DATEADD(minute, -10, NOW()) GROUP BY timestamp, user_name, source_ip, vm_name, operation HAVING snapshot_removals > 5 -- CRITICAL: If this fires, immediately isolate the ESXi host -- from vCenter and block all incoming SSH and API connections -
4
Detect lateral movement from Windows onto ESXi. Attackers typically pivot from a compromised Windows host (often a vCenter server or admin workstation) to ESXi. Hunt for new SSH connections from internal Windows IPs to ESXi management interfaces — especially if those IPs don't normally manage ESXi.
-
5
Hardening as a hunt output. Every ESXi hunt should produce hardening recommendations: disable SSH when not in use, restrict ESXi shell timeout, enforce vCenter role-based access for all VM operations, enable lockdown mode, and ensure all API access goes through vCenter (not directly to ESXi).
🧠 Reflection questions
- Why do ransomware groups target ESXi specifically rather than individual Windows VMs, and how does this affect the impact versus complexity tradeoff for the attacker?
- ESXi uses a custom VMkernel OS. How does this change your ability to deploy standard EDR agents, and what compensating monitoring controls do you have?
- Describe a detection rule that would alert on the pre-attack reconnaissance phase — before the attacker starts deleting snapshots — using only vCenter and ESXi logs.
Threat hunter's toolkit
Platform-agnostic tool categories. All free/open-source unless noted.
Sysmon
Windows system activity monitoring — the single highest-value free endpoint telemetry tool.
osquery
Query live endpoint state with SQL. Cross-platform. Excellent for fleet-wide hunting.
Velociraptor
Open-source DFIR and hunt platform. Deploys agents, runs VQL hunts across thousands of endpoints.
Zeek (Bro)
Network analysis framework. Generates rich JSON logs (conn, dns, http, ssl, files) from PCAP or live traffic.
Suricata
IDS/IPS/NSM engine. Runs Emerging Threats and custom rules against live traffic or PCAP.
YARA
Pattern matching for malware hunting — file-based, memory-based, and network-based rules.
Volatility 3
Memory forensics framework. Hunt injected code, rootkits, and malware artefacts in memory dumps.
BloodHound
AD attack path visualisation. Identifies privilege escalation paths and high-value targets.
MISP
Open-source threat intelligence platform. Share IOCs, import feeds, and correlate with environment.
Sigma
Generic SIEM detection rule format. Write once, convert to SPL/KQL/Lucene/AQL automatically.
ELK Stack
Elasticsearch + Logstash + Kibana. Free SIEM backbone for ingesting and querying logs at scale.
Security Onion
All-in-one platform bundling Zeek, Suricata, ELK, and osquery. Ideal lab environment.
AWS GuardDuty
ML-based threat detection for AWS CloudTrail, VPC Flow Logs, and DNS logs. Triggers cloud hunt hypotheses.
Microsoft Sentinel
Cloud-native SIEM using KQL. Ingests Azure AD, M365, and Defender telemetry for unified hunting.
CloudGoat
Deliberately vulnerable AWS environment for practising cloud attack and hunt techniques safely.
ATT&CK Navigator
Visualise and track detection coverage against MITRE ATT&CK techniques across your environment.
Microsoft Copilot for Security
AI assistant that translates natural language into KQL queries and summarises incidents.
Dropzone AI
Autonomous AI SOC agent that triages alerts and runs investigation playbooks automatically.
This workbook teaches the fundamentals — these platforms provide live, gamified environments to keep practising afterwards. Each entry below includes exactly how to create an account, the specific challenge or path to start with, and how to navigate to it.
Hack The Box acquired LetsDefend in September 2025, combining offensive HTB Academy labs with LetsDefend's realistic SOC alert-triage simulator into one account. You now sign up once and get access to both the attacker-side learning content and the defender-side SOC simulation.
- 1
Create an account. Go to
academy.hackthebox.comand click "Sign Up" (top right). A free account gives access to the introductory modules of every path. - 2
Navigate to the exercise. After logging in, go to
academy.hackthebox.com/path/preview/soc-analyst— this is the "SOC Analyst Job Role Path". Click "Continue" or "Enroll" to begin. - 3
Start with this specific module. Within the path, open the module named "Detecting Attacker Behavior with Built-in Windows Logging" — it directly extends this workbook's Lab 1.2 (Sysmon LOLBin hunting) with HTB's own guided exercises and a scored final assessment.
- 4
Access the SOC simulator (LetsDefend side). From your HTB dashboard, look for the "LetsDefend" tile, or go directly to
app.letsdefend.ioand log in with the same account. Click "VIP+ for Free" to unlock a 7-day trial of the full SOC alert environment, then navigate to "SOC146 — Brute Force Attack" under Monitoring → Investigate — a guided alert triage scenario matching this workbook's Lab 1.1.
CyberDefenders runs three services: BlueRing (live CTF events), BlueDemy (paid training courses), and BlueYard — over 84 free practice labs spanning malware analysis, threat intelligence, threat hunting, and digital forensics, each built around a real captured incident dataset.
- 1
Create an account. Go to
cyberdefenders.organd click "Sign Up". No payment details are required for the free BlueYard labs. - 2
Navigate to the labs. From the top menu select "Blue Team CTF Challenges", or go directly to
cyberdefenders.org/blueteam-ctf-challenges. Use the left-hand filter panel to filter by category — select "Threat Hunting" and sort by difficulty. - 3
Start with this specific challenge. Open the lab named "Boss of the SOC v1" (a free Splunk-based dataset) to directly extend this workbook's Domain 1 log analysis hunts using a real Splunk environment rather than pseudo-SQL. For network hunting practice extending Domain 3, try "Malware Traffic Analysis 4".
- 4
Submit answers. Each lab presents a series of investigation questions in the right-hand panel — answer them based on the provided evidence files (PCAP, logs, memory dumps) to earn points and track completion.
Blue Team Labs Online (BTLO) gives free players access to all 265+ investigation labs and challenges — including memory dumps, phishing emails, packet captures, and log files. Each completed investigation earns points based on its difficulty rating, with no paywall on the core challenge library.
- 1
Create an account. Go to
blueteamlabs.onlineand click "Sign Up" — the free tier requires no payment method. - 2
Navigate to challenges. From the dashboard, click "Challenges" in the top navigation, then use the category filter to select "Threat Intel" or "Log Analysis" to match this workbook's Domain 6 and Domain 1 content.
- 3
Start with this specific challenge. Open "Pcapinator" for a hands-on network forensics exercise extending Lab 3.1 (C2 beaconing), or "Volana" for a memory forensics challenge extending Lab 2.2 (process injection hunting).
- 4
Download the evidence and work locally. Most BTLO challenges provide a downloadable ZIP of evidence files — download it, open it in your REMnux or Kali VM from this workbook's environment setup, and answer the in-browser questions as you investigate.
KC7 (short for "Kill Chain 7") is a free, browser-based KQL training platform built by Microsoft security engineers. It loads pre-built network and identity log datasets directly into a real KQL query interface — no Azure subscription or sign-up cost required.
- 1
Create an account. Go to
kc7cyber.comand click "Play Now" — sign in with a Google or Microsoft account, no separate registration form needed. - 2
Navigate to the campaign. From the main menu select "Campaigns", then choose "Operation Frequent Flyer" — the standard introductory scenario that walks through identity-based attack hunting end to end.
- 3
Apply queries from this workbook. The in-browser query editor accepts standard KQL — reuse the password spray and impossible travel queries from Lab 7.2 directly against KC7's loaded dataset to see them return real matching rows.
- 4
Progress through the storyline. KC7 presents each campaign as a narrative investigation with specific questions to answer using KQL — completing all questions in a campaign unlocks the next one in the sequence.
AttackIQ Academy is a free educational platform with no paywalled tier — all courses are free, self-paced, and taught by practitioners, with (ISC)² CPE credits available on completion. It directly supports the detection engineering workflow introduced in this workbook's capstone (Lab 6.3).
- 1
Create an account. Go to
academy.attackiq.comand click "Sign Up" — entirely free, no credit card requested at any point. - 2
Navigate to the course. From the course catalog, open "Foundations of Operationalizing MITRE ATT&CK" — this course directly extends the ATT&CK Navigator coverage-mapping exercise used in Lab 6.3.
- 3
Follow up with the detection engineering course. After completing the foundations course, take "Building a Threat-Informed Defense Program" — it walks through the same hunt → detection → coverage validation loop this workbook teaches, from the perspective of a full security program rather than a single hunt.
- 4
Earn the badge. Each course ends with a graded assessment; passing unlocks a digital badge and certificate you can add to a CV or LinkedIn profile.
TryHackMe's SOC Level 1 path is one of the most widely recommended free starting points for security analysts. It covers SIEM fundamentals (Splunk and ELK), Wireshark/Suricata network analysis, phishing investigation, and MITRE ATT&CK — each module pairs theory with a hands-on lab in a browser-based VM, no local setup required. A limited number of rooms are free; the full path requires a low-cost subscription.
- 1
Create an account. Go to
tryhackme.comand click "Sign Up" — the free tier gives access to a rotating set of beginner rooms. - 2
Navigate to the path. Click "Paths" in the top navigation, then select "SOC Level 1" — or go directly to
tryhackme.com/path/outline/soc-level-1. - 3
Start with this specific room. Open the room named "Intro to Logs" first if you are new to log analysis, then progress to "Splunk: Search and Investigate" — which extends this workbook's pseudo-SQL queries (Labs 1.1, 1.2) into the real Splunk Search Processing Language (SPL).
- 4
Deploy the room's VM. Click the green "Start Machine" button at the top of each room — TryHackMe spins up a temporary VM you access either via browser-based split-screen or your own VPN connection (OpenVPN config downloadable from your account settings).
- 5
Progress to SOC Level 2. After completing Level 1, the SOC Level 2 path covers more advanced detection engineering, malware analysis, and digital forensics — a natural follow-on to this workbook's Domain 4 and Domain 5 content.