Skip to content

Repository files navigation

AtomicLoop — Atomic Red Team Test Runner and Detection Validator

Part of the Nebula Forge security tools suite.

AtomicLoop closes the purple team validation loop: simulate an attack technique, capture endpoint events, and immediately validate whether your Sigma/Wazuh rules fire. No need for the full Atomic Red Team framework.

versionportpythonframeworkMITRE%20ATT%26CKpart%20oflicense

Write Sigma rule → Simulate attack (AtomicLoop) → Capture events (LogNorm)
→ Validate detection (DriftWatch) → Fix gap → Repeat

Pipeline Position

Nebula Forge pipeline — AtomicLoop highlighted

purple-loop:AtomicLoop → LogNorm → ClusterIQ → HuntForge → DriftWatch → repeat


Screenshots

Dashboard

Technique Browser


Core Features

  • 20 embedded MITRE ATT&CK techniques — curated tests for T1059.001 through T1190, no internet or framework required
  • Safety controls — dry_run preview + explicit confirm flag prevents accidental execution
  • Local execution — PowerShell, cmd, and bash executors with configurable timeout
  • WinRM remote execution — run atomic tests on remote Windows hosts via PS Remoting (T1021.006); optional credential support
  • Event capture — reads Windows Security + Sysmon event logs during the test window
  • LogNorm integration — normalizes captured events to ECS-lite format (port 5006)
  • DriftWatch integration — validates Sigma rules against captured events (port 5008)
  • Gap analysis — explains exactly why a detection fired or missed
  • Persistent history — SQLite (default, zero-config) or PostgreSQL run library with search, export, and delete
  • CLI — offline operation without the web UI

Quick Start

cd AtomicLoop
pip install -r requirements.txt
cp config.example.yaml config.yaml # optional
python app.py

Open http://127.0.0.1:5011


Docker (Nebula Forge suite)

This tool runs as a containerized service in the Nebula Forge suite. The recommended way to start everything together:

# From the Nebula-Forge repo root
cp .env.example .env # add secrets (NVD_API_KEY, ATOMICLOOP_API_KEY, POSTGRES_PASSWORD — all required)
docker compose up -d # starts all services including atomicloop

Access:http://localhost:5011

Standalone container:

docker build -t atomicloop .
docker run -p 5011:5011 \
-e DATABASE_URL=postgresql://nebula:changeme@localhost:5432/nebula_forge \
-e ATOMICLOOP_API_KEY=your-key-here \
atomicloop

Usage

Web UI

  1. Browse techniques in the left panel (grouped by tactic).
  2. Click a technique to expand its test list.
  3. Select a test to see command preview, expected artifacts, and input arguments.
  4. Toggle Dry Run to preview the command without executing.
  5. When ready: disable Dry Run, check the confirm checkbox, set timeout.
  6. Click Execute Test — results appear in the right panel.
  7. Paste a Sigma rule in the Detection Validation panel and click Validate Detection.

CLI

# List all techniques
python cli.py --list
# Show tests for a technique
python cli.py --technique T1059.001
# Dry run (preview command only)
python cli.py --technique T1059.001 --test 1 --dry-run
# Execute with confirmation
python cli.py --technique T1059.001 --test 1 --confirm
# Execute and validate against a Sigma rule
python cli.py --technique T1059.001 --test 1 --confirm --validate --sigma rule.yml
# Custom input arguments
python cli.py --technique T1059.001 --test 2 --confirm --arg target_url=http://127.0.0.1:8080
# Save output to file
python cli.py --technique T1059.001 --test 1 --confirm --output result.md
# List saved runs
python cli.py --results

API Reference

MethodEndpointDescription
GET/api/healthHealth check
GET/api/atomicsList all techniques
GET/api/atomics/<technique_id>Get tests for a technique
POST/api/runExecute an atomic test (engine path) — API key required.
POST/api/validateValidate Sigma rule against events
GET/api/resultsList past runs (paginated)
GET/api/result/<run_id>Get a single run
DELETE/api/result/<run_id>Delete a run
GET/api/result/<run_id>/exportExport run (JSON or Markdown)
POST/executeDirect command execution — local or WinRM remote (API key protected)

POST /api/run

{
"technique_id": "T1059.001",
"test_number": 1,
"confirm": true,
"dry_run": false,
"capture_events": true,
"normalize": true,
"timeout": 30,
"input_arguments": {"target_url": "http://127.0.0.1:8080"}
}

Response:

{
"success": true,
"run_id": "uuid",
"technique_id": "T1059.001",
"test_name": "PowerShell Encoded Command Execution",
"executed_at": "2025-01-01T12:00:00Z",
"exit_code": 0,
"duration_ms": 1240,
"event_count": 12,
"events": [{...ECS-lite...}],
"raw_output": "AtomicTest T1059.001-1: Encoded execution"
}

POST /execute

Executes an allowlisted atomic command directly — locally or on a remote Windows host via WinRM. Protected by ATOMICLOOP_API_KEY — required at startup (see Environment variables).

Request headers (required):

X-API-Key: <your-key>
Content-Type: application/json

Request body:

FieldTypeRequiredDefaultDescription
commandstringYesAtomic test command to execute. Must match a command in the embedded allowlist.
executor_typestringNo"powershell"Executor used for allowlist lookup and local dispatch: powershell, cmd, bash.
target_hoststringConditionalRemote host (hostname or IPv4/IPv6). Required when transport is "winrm".
transportstringNoSet to "winrm" to execute on target_host via PS Remoting. Omit for local execution.
credentialobjectNo{"username": "DOMAIN\\user", "password": "secret"}. Passed as -Credential to New-PSSession. Only used when transport is "winrm".
timeoutintegerNo30Seconds before the process or remote session is killed.
dry_runbooleanNofalseIf true, returns the command that would be run without executing it.

Local execution example:

{
"command": "Get-Process",
"executor_type": "powershell",
"timeout": 30,
"dry_run": false
}

WinRM remote execution example:

{
"command": "Get-Process",
"executor_type": "powershell",
"target_host": "192.168.1.50",
"transport": "winrm",
"credential": {"username": "CORP\\svctest", "password": "hunter2"},
"timeout": 60,
"dry_run": false
}

Dry-run example (no execution, no API key required logic applies normally):

{
"command": "Get-Process",
"target_host": "192.168.1.50",
"transport": "winrm",
"dry_run": true
}

Response:

{
"success": true,
"exit_code": 0,
"stdout": "...",
"stderr": "",
"duration_ms": 1340,
"timed_out": false,
"dry_run": false,
"command": "Get-Process",
"error": null
}

Error responses:

StatusBodyCause
400{"success": false, "error": "command is required"}Empty or missing command field
400{"success": false, "error": "target_host is required when transport is 'winrm'"}transport=winrm with no target_host
200{"success": false, "error": "Command is not in the embedded atomic allowlist."}Command does not match any embedded atomic test
200{"success": false, "error": "Invalid target_host: ..."}target_host contains characters outside hostname/IP character set
401{"error": "unauthorized"}X-API-Key header missing or incorrect

POST /api/validate

{
"run_id": "uuid",
"sigma_rule": "title: Detect PowerShell Encoded Command\ndetection:\n ..."
}

Response:

{
"success": true,
"detection_fired": true,
"matched_events": [{...}],
"match_count": 3,
"gap_analysis": "Validated via DriftWatch. Detection FIRED: Sigma rule matched 3 of 12 captured events.",
"source": "driftwatch"
}

Embedded Technique Library

TechniqueNameTactic
T1059.001PowerShellExecution
T1059.003Windows Command ShellExecution
T1055Process InjectionDefense Evasion
T1003OS Credential DumpingCredential Access
T1082System Information DiscoveryDiscovery
T1083File and Directory DiscoveryDiscovery
T1057Process DiscoveryDiscovery
T1069Permission Groups DiscoveryDiscovery
T1021.001Remote Desktop ProtocolLateral Movement
T1021.002SMB/Windows Admin SharesLateral Movement
T1547.001Registry Run KeysPersistence
T1053.005Scheduled TaskPersistence
T1070.001Clear Windows Event LogsDefense Evasion
T1112Modify RegistryDefense Evasion
T1027Obfuscated FilesDefense Evasion
T1562.001Impair DefensesDefense Evasion
T1566.001Spearphishing AttachmentInitial Access
T1078Valid AccountsDefense Evasion
T1110.001Password GuessingCredential Access
T1190Exploit Public-Facing ApplicationInitial Access

WinRM Prerequisites

The /execute route with transport=winrm uses PowerShell Remoting (New-PSSession / Invoke-Command). The following must be true on the target host before remote execution will succeed.

Target host (Windows)

# Enable PS Remoting (run as Administrator)Enable-PSRemoting-Force
# Confirm WinRM is listening
winrm enumerate winrm/config/listener
# If the source host is not domain-joined, add it to TrustedHosts on the source# (run on the AtomicLoop host, not the target)Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.50"-Force

Network

PortProtocolDirectionPurpose
5985HTTPSource → TargetWinRM (unencrypted, lab use)
5986HTTPSSource → TargetWinRM over TLS (recommended for non-lab)

Credentials

Pass credentials via the credential field in the request body. The account must have permission to create PS sessions on the target (local Administrator or a delegated WinRM user).

Note: Credentials are transmitted in the JSON request body and embedded in a PowerShell -Command string. Use HTTPS between your client and the AtomicLoop server, and rotate test credentials after exercises.

AtomicLoop host

PowerShell (Windows: powershell.exe) or PowerShell Core (Linux/macOS: pwsh) must be installed and on PATH. The executor is selected automatically based on the OS AtomicLoop is running on.


Configuration

config.yaml

KeyDefaultDescription
port5011HTTP port
db_path./atomicloop.dbSQLite file path (used when DATABASE_URL is not set)
execution.timeout30Default execution timeout (seconds)
execution.require_confirmtrueRequire explicit confirm flag
execution.auto_savetruePersist every run automatically
integrations.lognorm_urlhttp://127.0.0.1:5006LogNorm endpoint
integrations.driftwatch_urlhttp://127.0.0.1:5008DriftWatch endpoint

Environment variables

VariableRequiredDescription
ATOMICLOOP_API_KEYYesRequired. Shared secret for the X-API-Key header on POST /execute and POST /api/run. The app will not start if this variable is unset. Set it in your .env file for Docker or as an environment variable for standalone runs.
DATABASE_URLNoPostgreSQL connection string (e.g. postgresql://user:pass@host:5432/db). When unset, AtomicLoop uses the SQLite file specified by db_path in config.yaml.
# Example — set before starting the serverexport ATOMICLOOP_API_KEY="change-me-before-exposing-to-a-network"
python app.py

When the key is configured, every POST /execute call must include the header:

X-API-Key: <your-key>

Requests with a missing or incorrect header receive 401 {"error": "unauthorized"}.

Key rotation:ATOMICLOOP_API_KEY is read once at process startup (module import time). Changing the environment variable has no effect on a running server — the process must be restarted to pick up a new value.


Safety Controls

AtomicLoop includes several controls to prevent accidental execution:

  1. confirm: true — required in every POST /api/run body to execute. Without it, the request is rejected.
  2. dry_run: true — shows the command without executing. Always safe. Supported on both /api/run and /execute.
  3. require_confirm: true (config) — server-enforced gate on all live executions.
  4. Timeout — hard kill after N seconds (default 30). Applied to both local processes and WinRM sessions.
  5. Atomic allowlist/execute only dispatches commands that appear verbatim in the embedded MITRE technique library. Arbitrary commands are rejected.
  6. ATOMICLOOP_API_KEY — required to start the server. Both /execute and /api/run require a matching X-API-Key header. The app exits at startup if this variable is not set.
  7. API key setup — set ATOMICLOOP_API_KEY in your .env file (Docker) or as a terminal environment variable (standalone). Generate a key with: python -c "import secrets; print(secrets.token_hex(32))"
  8. cleanup_command — each test includes a cleanup command. Run it after testing.

Nebula Forge Integration

Add to nebula-dashboard/config.yaml:

tools:
atomicloop:
label: "AtomicLoop"url: "http://127.0.0.1:5011"health_path: "/api/health"description: "Atomic Red Team test runner and detection validator"category: "Detection"

License

This project is licensed under the MIT License — see the LICENSE file for details.

Built by Rootless-Ghost

Part of the Nebula Forge security tools suite.

About

Atomic Red Team Test Runner & Detection Validator — execute, capture, validate | Part of Nebula Forge

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages