Zion Boggan
repos/purple-team-lab

purple-team-lab

Emulate adversary techniques, then prove the detections fire. This is the validation half of detection-as-code: I run ATT&CK techniques against an instrumented Ubuntu endpoint enrolled in my SOC automation lab, and confirm each one raises the alert it's supposed to - mapped to...

3 commits First commit May 29, 2026 Last commit Jun 22, 2026 (43 minutes ago)
Markdown 68.0%Shell 20.7%YAML 11.2%
Files 9 entries
README.md

Purple-Team Lab

Emulate adversary techniques, then prove the detections fire. This is the validation half of detection-as-code: I run ATT&CK techniques against an instrumented Ubuntu endpoint enrolled in my SOC automation lab, and confirm each one raises the alert it's supposed to - mapped to the right technique, at a severity that would actually page someone.

Writing a detection is a hypothesis. This is the test.

Emulated techniques detected in Wazuh

Every row is an atomic I executed on the endpoint and the rule that caught it - five of the six are detections I wrote (100410-100413) plus the brute-force rule, all on the purple-target agent, all ATT&CK-tagged.

How it's wired

flowchart LR
    A[Atomic Red Team atomics<br/>run on purple-target VM] --> B[Wazuh agent<br/>auth log + real-time FIM]
    B -->|1514/tcp| C[Wazuh manager<br/>analysisd: built-in + custom rules]
    C --> D[Indexer]
    D --> E[Dashboard<br/>ATT&CK-mapped alerts]
    F[MITRE Caldera<br/>adversary emulation] -.-> B

The target is a dedicated Ubuntu 22.04 VM (not a container - kernel-level telemetry needs a real kernel). It runs the Wazuh agent shipping auth logs and real-time file integrity monitoring on the paths attackers use for persistence. Caldera is available for graph-based adversary emulation; the day-to-day validation uses Atomic Red Team because it maps cleanly one-atomic-to-one-detection.

Validation matrix

Each technique was executed on the endpoint and confirmed in the SIEM:

Technique Atomic Telemetry Rule Level Result
T1110 Brute Force 18 invalid SSH logins auth log 5712 (built-in) 10 ✅ detected
T1053.003 Cron persistence drop job in /etc/cron.d FIM 100410 (custom) 10 ✅ detected
T1543.002 Systemd persistence create .service unit FIM 100411 (custom) 10 ✅ detected
T1098.004 SSH authorized_keys append attacker key FIM 100412 (custom) 12 ✅ detected
T1543 Tooling drop binary into /usr/local/bin FIM 100413 (custom) 10 ✅ detected
T1078 / T1548.003 login + sudo to root auth log 5501 / 5402 3 ✅ (informational baseline)

The custom rules are in rules/local_purple_rules.xml; the atomics that exercise them are in atomics/run_atomics.sh.

Why FIM for persistence

The persistence detections key off file integrity monitoring, not syscall auditing. That's deliberate: FIM is Wazuh-native and works everywhere - including containers and hardened hosts where the kernel audit framework isn't available to you - whereas auditd execve rules silently do nothing on a host that boots with audit disabled. The auditd ruleset I'd layer on a host that does have kernel auditing is included in agent/auditd-purple.rules, but the validated detections above don't depend on it.

Run it

On the endpoint (enrolled Wazuh agent + the FIM config from agent/):

sudo bash atomics/run_atomics.sh          # execute the technique set

Then in the Wazuh dashboard, filter Threat Hunting → Events to rule.id:(100410 or 100411 or 100412 or 100413 or 5712) and confirm the hits.

Caldera (adversary-emulation UI, optional):

cd caldera && docker compose up -d         # http://localhost:8888

Layout

rules/local_purple_rules.xml   custom FIM detections (deploy to the manager)
agent/fim-directories.xml      real-time FIM config for the agent's syscheck block
agent/auditd-purple.rules      auditd rules for hosts with kernel auditing
atomics/run_atomics.sh         the ATT&CK technique set
caldera/docker-compose.yml     MITRE Caldera server
docs/validation-matrix.md      the matrix above, with notes per technique