Chapter 36: Purple Team Operations — Continuous Detection Improvement¶
Overview¶
Purple teaming is the structured, collaborative methodology where offensive (red) and defensive (blue) teams work together in real-time to measure, validate, and improve detection and response capabilities. Unlike traditional red-vs-blue engagements, purple team operations are transparent, iterative, and outcome-focused — the goal is not to expose gaps secretly but to close them immediately. This chapter covers purple team frameworks, VECTR-based tracking, detection engineering feedback loops, atomic testing with Atomic Red Team, and purple team program maturity.
Learning Objectives¶
- Distinguish purple team operations from traditional red team engagements
- Design and execute a structured purple team exercise using VECTR
- Run Atomic Red Team tests and map results to detection gaps
- Build a detection engineering feedback loop from purple team findings
- Implement continuous purple team automation with Caldera and Atomic
- Measure purple team program effectiveness with detection coverage metrics
Prerequisites¶
- Chapter 5 (Detection Engineering)
- Chapter 17 (Red Team Operations)
- Chapter 9 / 28 (Incident Response)
- Familiarity with SIEM query languages (Sigma, KQL, SPL)
Why Purple Teams Fail
Most purple team programs fail because findings never get converted into detection rules. Red team identifies a technique, blue team says "yes we missed that," and the exercise ends. Without a structured feedback loop converting every missed technique into a new detection, the program delivers no lasting security improvement. This chapter focuses on the feedback loop above all else.
36.1 Purple Team vs. Red Team¶
flowchart LR
subgraph Red["Traditional Red Team"]
R1[Silent assessment\nno blue team\nawareness] --> R2[Final report\n6-8 weeks] --> R3[Findings list\nno fix timeline]
end
subgraph Purple["Purple Team"]
P1[Collaborative\nexecution] --> P2[Real-time detection\nvalidation] --> P3[Immediate rule\ndevelopment] --> P4[Re-test &\nvalidate fix] --> P1
end
style Red fill:#ff7b7222,stroke:#ff7b72
style Purple fill:#3fb95022,stroke:#3fb950 | Dimension | Red Team | Purple Team |
|---|---|---|
| Blue team awareness | No | Yes — collaborative |
| Finding disclosure | End of engagement | Real-time |
| Detection development | Out of scope | Core deliverable |
| Cadence | Annual/quarterly | Weekly to continuous |
| Primary output | Vulnerabilities | Detection rules |
| ROI measurement | Exposure found | Detection coverage delta |
| ATT&CK coverage | Measured post-hoc | Measured continuously |
36.2 Purple Team Frameworks¶
TIBER-EU / TIBER-XX¶
TIBER (Threat Intelligence-Based Ethical Red Teaming) is the European Central Bank's framework for financial sector purple teaming, adopted by EU member states. It mandates threat-intelligence-driven scenarios based on named threat actors relevant to the institution.
TIBER-EU phases: 1. Preparation — Scope definition, NDA, test team selection 2. Testing — Threat intelligence phase → red team test phase (12+ weeks) 3. Closure — Purple team remediation phase, attestation
CBEST (UK) / CORIE (Australia)¶
Similar intelligence-led frameworks for financial sector regulators. All share the requirement that scenarios be based on genuine threat actor intelligence specific to the industry.
PTES (Penetration Testing Execution Standard)¶
More generic framework adaptable to purple team use with added detection tracking.
36.3 VECTR — Tracking Purple Team Exercises¶
VECTR is an open-source platform for tracking red and purple team exercises, mapping them to ATT&CK, and measuring detection coverage over time.
# Deploy VECTR with Docker Compose
git clone https://github.com/SecurityRiskAdvisors/VECTR
cd VECTR
docker compose up -d
# Default access: http://localhost:8081
# Admin credentials set in docker-compose.yml
VECTR Workflow:
sequenceDiagram
participant RT as Red Team
participant BT as Blue Team
participant VECTR
RT->>VECTR: Create campaign (e.g., "APT29 emulation Q2")
RT->>VECTR: Add test cases (ATT&CK techniques)
RT->>BT: Execute technique
BT->>VECTR: Record detection outcome
Note over VECTR: Detected / Not Detected / Blocked
BT->>BT: Write detection rule for gaps
BT->>RT: Request re-test
RT->>BT: Re-execute technique
BT->>VECTR: Update outcome → Detected
VECTR->>VECTR: Update ATT&CK coverage metrics VECTR outcome states:
| Outcome | Definition | Next Action |
|---|---|---|
| Detected & Blocked | Prevention control stopped execution | Document and maintain |
| Detected | Alert fired; SOC aware | Tune for confidence/fidelity |
| Not Detected | No alert generated | Write detection rule |
| Detected Post-Hoc | Found in log review, no alert | Convert to real-time rule |
| N/A | Technique not applicable to environment | Document exemption reason |
36.4 Atomic Red Team — Atomic Testing¶
Atomic Red Team is a library of small, focused tests (atomics) mapped to ATT&CK techniques. Each atomic is the minimal implementation to exercise a technique.
# Install Invoke-AtomicRedTeam (PowerShell)
Install-Module -Name invoke-atomicredteam -Scope CurrentUser -Force
# Import and install prerequisites
Import-Module Invoke-AtomicRedTeam
Invoke-AtomicTest All -GetPrereqs
# List tests for a technique
Invoke-AtomicTest T1003.001 -ShowDetailsBrief
# Execute LSASS dump test (Test 1 only)
Invoke-AtomicTest T1003.001 -TestNumbers 1
# Check for generated artifacts
Invoke-AtomicTest T1003.001 -CheckPrereqs
# Cleanup after test
Invoke-AtomicTest T1003.001 -Cleanup
Automated purple team script — test entire tactic:
#!/usr/bin/env python3
"""
Purple team automation: run Atomic tests, check SIEM for alerts,
report coverage gaps.
"""
import subprocess
import time
import json
import requests
from datetime import datetime, timedelta
TECHNIQUES_TO_TEST = [
"T1003.001", # LSASS Memory
"T1558.003", # Kerberoasting
"T1053.005", # Scheduled Task
"T1059.001", # PowerShell
"T1550.002", # Pass the Hash
"T1490", # Inhibit System Recovery
]
SIEM_API = "https://sentinel.example.com/api/query"
SIEM_TOKEN = "Bearer <token>"
WAIT_SECONDS = 90 # Time to wait for alert propagation
def run_atomic(technique: str) -> dict:
result = subprocess.run(
["pwsh", "-Command",
f"Import-Module Invoke-AtomicRedTeam; "
f"Invoke-AtomicTest {technique} -TestNumbers 1"],
capture_output=True, text=True, timeout=120
)
return {"technique": technique, "executed": result.returncode == 0,
"output": result.stdout[:500]}
def check_siem_alert(technique: str, start_time: datetime) -> bool:
"""Query SIEM for alerts related to this ATT&CK technique."""
query = f"""
SecurityAlert
| where TimeGenerated > datetime('{start_time.isoformat()}')
| where ExtendedProperties contains '{technique}'
or Tactics contains '{technique[:2]}'
| count
"""
resp = requests.post(SIEM_API,
headers={"Authorization": SIEM_TOKEN},
json={"query": query})
count = resp.json().get("tables", [{}])[0].get("rows", [[0]])[0][0]
return count > 0
results = []
for tech in TECHNIQUES_TO_TEST:
print(f"\n[*] Testing {tech}...")
start = datetime.utcnow()
exec_result = run_atomic(tech)
print(f" Executed: {exec_result['executed']}")
print(f" Waiting {WAIT_SECONDS}s for SIEM alert propagation...")
time.sleep(WAIT_SECONDS)
detected = check_siem_alert(tech, start)
outcome = "DETECTED" if detected else "GAP"
print(f" Outcome: {outcome}")
results.append({"technique": tech, "executed": exec_result["executed"],
"detected": detected, "outcome": outcome})
# Cleanup
subprocess.run(["pwsh", "-Command",
f"Import-Module Invoke-AtomicRedTeam; Invoke-AtomicTest {tech} -Cleanup"],
capture_output=True)
# Report
gaps = [r for r in results if r["outcome"] == "GAP"]
detected = [r for r in results if r["outcome"] == "DETECTED"]
print(f"\n{'='*50}")
print(f"Purple Team Results — {datetime.utcnow().strftime('%Y-%m-%d')}")
print(f"Detected: {len(detected)}/{len(results)} ({len(detected)/len(results)*100:.0f}%)")
print(f"Gaps: {len(gaps)}")
for g in gaps:
print(f" GAP: {g['technique']} — Create detection rule")
print(json.dumps(results, indent=2))
36.5 Detection Engineering Feedback Loop¶
The core value of purple team operations is the automatic generation of detection rules for every gap found.
flowchart TD
EXEC[Execute Atomic\nTechnique] --> CHECK{Alert\nGenerated?}
CHECK -->|Yes| TUNE[Review fidelity\nReduce FP rate]
CHECK -->|No| HUNT[Threat Hunt\nfor artifacts]
HUNT --> FOUND{Evidence\nFound?}
FOUND -->|Yes| RULE[Write Detection\nRule from Artifacts]
FOUND -->|No| TELEMETRY[Check telemetry\ngaps — log source?]
TELEMETRY --> INGEST[Add missing\nlog source]
INGEST --> RULE
RULE --> SIGMA[Convert to\nSigma format]
SIGMA --> TEST[Test rule against\nhistorical data]
TEST --> DEPLOY[Deploy to SIEM\nproduction]
DEPLOY --> RETEST[Re-run Atomic\n48h later]
RETEST --> CHECK
TUNE --> CLOSE[Close in VECTR\nDetected ✓]
style RULE fill:#58a6ff22,stroke:#58a6ff
style CLOSE fill:#3fb95022,stroke:#3fb950 Sigma Rule from Purple Team Finding¶
Scenario: Atomic T1003.001 (LSASS dump via ProcDump) was not detected.
Step 1 — Hunt for artifacts:
# Splunk: find ProcDump LSASS access
index=wineventlog EventCode=10 TargetImage="*lsass.exe"
| stats count by SourceImage, TargetImage, CallTrace
# KQL (Sentinel)
SecurityEvent
| where EventID == 4656
| where ObjectName contains "lsass"
| where ProcessName !in ("C:\\Windows\\System32\\werfault.exe",
"C:\\Windows\\System32\\taskmgr.exe")
Step 2 — Write Sigma rule:
title: LSASS Memory Access via ProcDump or Sysinternals
id: c3b4f1e2-8a7d-4c9b-b5e1-f2a3d4e5f6g7
status: stable
description: Detects LSASS memory access by non-system processes, indicating credential dumping
references:
- https://attack.mitre.org/techniques/T1003/001/
author: Purple Team — Q2 Exercise
date: 2026-03-17
tags:
- attack.credential_access
- attack.t1003.001
logsource:
category: process_access
product: windows
detection:
selection:
TargetImage|endswith: '\lsass.exe'
GrantedAccess|contains:
- '0x1010'
- '0x1410'
- '0x1438'
- '0x143a'
- '0x1418'
filter_legit:
SourceImage|startswith:
- 'C:\Windows\System32\'
- 'C:\Windows\SysWOW64\'
- 'C:\Program Files\CrowdStrike\'
- 'C:\Program Files\SentinelOne\'
condition: selection and not filter_legit
falsepositives:
- Legitimate monitoring tools (tune filter_legit per environment)
- EDR products (add vendor paths to filter)
level: high
Step 3 — Backtest against historical data:
# Validate no false positives in last 30 days
sigma convert -t splunk rules/lsass-access.yml | \
xargs -I{} splunk search {} earliest=-30d | wc -l
# If >0, review and tune filter_legit paths
36.6 ATT&CK Coverage Measurement¶
#!/usr/bin/env python3
"""
Calculate detection coverage against ATT&CK Enterprise matrix.
Uses VECTR API or local CSV export.
"""
import csv
import json
from collections import defaultdict
# Load VECTR exercise results
VECTR_EXPORT = "vectr_results.csv"
# Load ATT&CK Enterprise techniques (download from MITRE CTI)
ATTACK_FILE = "enterprise-attack-techniques.json"
def load_vectr(path):
results = {}
with open(path) as f:
for row in csv.DictReader(f):
tid = row.get("Technique ID", "").strip()
outcome = row.get("Outcome", "").strip()
if tid:
results[tid] = outcome
return results
def coverage_report(vectr_results, attack_techniques):
tactic_coverage = defaultdict(lambda: {"total": 0, "detected": 0, "tested": 0})
for tech in attack_techniques:
tid = tech["external_id"]
for tactic in tech["tactics"]:
tactic_coverage[tactic]["total"] += 1
if tid in vectr_results:
tactic_coverage[tactic]["tested"] += 1
if vectr_results[tid] in ("Detected", "Detected & Blocked"):
tactic_coverage[tactic]["detected"] += 1
print(f"\n{'Tactic':<30} {'Tested':>8} {'Detected':>10} {'Coverage':>10}")
print("-" * 62)
for tactic, stats in sorted(tactic_coverage.items()):
pct = (stats["detected"] / stats["total"] * 100) if stats["total"] else 0
print(f"{tactic:<30} {stats['tested']:>8} {stats['detected']:>10} {pct:>9.1f}%")
# Example output:
# Tactic Tested Detected Coverage
# ----------------------------------------------------------
# Credential Access 8 6 75.0%
# Defense Evasion 12 4 33.3%
# Lateral Movement 6 5 83.3%
36.7 Continuous Purple Teaming with CALDERA¶
MITRE CALDERA is an adversary emulation platform enabling automated continuous purple team testing.
# CALDERA ability definition (YAML) — Kerberoasting
id: f3b7c2e1-4d8a-9b5c-e2f1-a3b4d5e6f7g8
name: Kerberoast service accounts
description: Request TGS tickets for all SPNs in the domain
tactic: credential-access
technique:
attack_id: T1558.003
name: Kerberoasting
platforms:
windows:
psh:
command: |
Import-Module ActiveDirectory;
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName |
ForEach-Object {
$spn = $_.ServicePrincipalName[0];
Add-Type -AssemblyName System.IdentityModel;
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn
};
klist
cleanup: klist purge
parsers:
- module: app.parsers.kerberoast
parserconfigs:
- source: host.collected.kerberos_tickets
# Deploy CALDERA
git clone https://github.com/mitre/caldera.git --recursive
cd caldera
pip install -r requirements.txt
python server.py --insecure # Use TLS in production
# API: create operation programmatically
curl -X POST http://localhost:8888/api/v2/operations \
-H "Authorization: Bearer $CALDERA_API_KEY" \
-d '{
"name": "Purple Team - Lateral Movement",
"adversary": {"adversary_id": "apt29-profile"},
"group": "blue-team-endpoints",
"auto_close": true,
"obfuscator": "plain-text",
"visibility": 51
}'
36.8 Purple Team Report Template¶
# Purple Team Exercise Report
**Date:** YYYY-MM-DD | **Duration:** X days | **Analyst:** Name
## Executive Summary
- Techniques tested: N
- Detected: N (N%)
- Detection gaps closed: N
- New Sigma rules created: N
- MITRE ATT&CK coverage delta: +N%
## Test Results Summary
| Technique | Name | Outcome | Rule Written |
|-----------|------|---------|--------------|
| T1566.001 | Spearphishing | Detected | N/A |
| T1003.001 | LSASS Dump | Not Detected | ✓ lsass-access.yml |
| T1558.003 | Kerberoasting | Detected Post-Hoc | ✓ kerberoast-tgs.yml |
## Detection Gaps and Remediations
### GAP-001: LSASS Memory Access (T1003.001)
- **Finding:** No alert for ProcDump accessing lsass.exe
- **Root Cause:** Sysmon Event 10 not collected for this host group
- **Fix Applied:** Sysmon config updated; Sigma rule deployed
- **Re-test Result:** Detected ✓
- **VECTR Updated:** 2026-03-17
## ATT&CK Coverage Heatmap
[Insert VECTR navigator export]
## Recommendations
1. Enable Sysmon on all server endpoints (currently only workstations)
2. Increase log retention for process creation events (currently 14 days → 90 days)
3. Tune credential access alerts — current FP rate 40% (target: <5%)
Exam Prep & Certifications¶
Relevant Certifications
The topics in this chapter align with the following certifications:
Nexus SecOps Benchmark Controls¶
| Control ID | Description | Validation |
|---|---|---|
| Nexus SecOps-PT-01 | Purple team exercises conducted quarterly with VECTR tracking | VECTR campaign records; outcomes documented |
| Nexus SecOps-PT-02 | Every detection gap generates a Sigma rule within 5 business days | Sigma rule repository; VECTR re-test confirmation |
| Nexus SecOps-PT-03 | Atomic Red Team baseline coverage ≥ 60% of applicable techniques | Automated atomic test report; SIEM alert evidence |
| Nexus SecOps-PT-04 | ATT&CK coverage measured and reported to leadership monthly | Coverage dashboard; tactic-level heatmap |
| Nexus SecOps-PT-05 | Detection rules backtested on 30-day historical data before deploy | FP rate ≤ 5% for new detection rules |
| Nexus SecOps-PT-06 | CALDERA or equivalent enables continuous automated testing | Automated test scheduler; weekly coverage report |
Key Terms¶
Atomic Red Team — Library of small, focused ATT&CK-mapped test cases enabling repeatable technique execution; maintained by Red Canary.
CALDERA — MITRE's open-source adversary emulation platform supporting autonomous and manual operation execution.
Detection Coverage — The percentage of ATT&CK techniques for which reliable detection rules exist and have been validated.
False Positive Rate — The proportion of alerts fired on benign activity; a key quality metric for detection rules (target: <5%).
Feedback Loop — The process converting purple team findings into detection rules, re-testing, and confirming closure.
Purple Team — Collaborative offensive/defensive exercise focused on improving detection and response rather than exposing vulnerabilities.
Sigma — Open-source generic signature format for SIEM rules; convertible to Splunk SPL, KQL, Elastic EQL, and others.
VECTR — Open-source purple team tracking platform mapping exercises to ATT&CK and measuring detection coverage over time.