shellkraft/Ledger

GitHub: shellkraft/Ledger

Stars: 27 | Forks: 1

# Ledger — Operational Change Tracker Aggressor Script Ledger is a Cobalt Strike aggressor script that tracks every operational change made during an engagement. Every service you enable, firewall rule you punch through, account you create, or registry key you touch gets logged with a risk score, operator attribution, and cleanup status. At the end of the engagement you have a complete audit trail of what was changed and what still needs to be cleaned up. ## Why Red team engagements leave artifacts. Services get enabled, accounts get created, firewall rules get opened, registry keys get modified. Without a structured log these are easy to forget — especially across long engagements or when multiple operators are working simultaneously. Ledger gives you a running journal with: - Risk scoring per entry and per host - Cleanup tracking so nothing gets left behind - Per-operator attribution via the Cobalt Strike event log - Export to JSON or plain text for after-action reports - Automatic dead-beacon warnings when uncleaned changes are still pending ## Installation 1. Copy `ledger.cna` to your Cobalt Strike scripts directory. 2. In the menu bar: **Cobalt Strike → Script Manager → Load** → select `ledger.cna`. 3. A **Ledger** menu will appear in the menu bar. 4. The `dirty` alias is now available in every Beacon console. ## Usage All commands run from a Beacon console using the `dirty` alias. ### Log a change (no execution) dirty [comment] [score] `comment` and `score` are optional. If omitted, sensible defaults are used based on the category. dirty RPC "sql-enablerpc lon-db-1 lon-db-2" dirty DEFENDER "add-exclusion C:\windows\temp" "Payload staging" 8 dirty GROUP "net group 'Domain Admins' svc_backup /add /domain" dirty USER "net user backdoor P@ssw0rd! /add" dirty SCHEDULED_TASK "schtasks /create /tn updater /tr C:\temp\beacon.exe /sc onlogon" image ### Execute and log in one step dirty exec [comment] [score] Logs the change and immediately executes the command on the beacon — one step instead of two. dirty exec RPC "sql-enablerpc lon-db-1 lon-db-2" dirty exec USER "net user backdoor P@ssw0rd! /add" dirty exec DEFENDER "sc config WinDefend start= disabled" dirty exec FIREWALL "netsh advfirewall set allprofiles state off" **Limitations of `dirty exec`** `dirty exec` uses `brun` internally, which executes a binary directly without a `cmd.exe /c` wrapper. This means: - Works for real executables: `net`, `sc`, `reg`, `nltest`, `whoami`, `ipconfig`, etc. - Does **not** work for Beacon built-ins: `sleep`, `cd`, `ls`, `pwd`, `download`, `upload`, `execute-assembly`, `inject`, etc. For those, run the Beacon command normally and use `dirty ` separately to log it. - Does **not** work for shell built-ins that require `cmd.exe`: `dir`, `echo`, `set`, `type`, pipes (`|`), redirects (`>`), etc. Log those manually with `dirty CATEGORY "shell "`. - Custom BOF aliases loaded from other `.cna` files will not dispatch correctly through `dirty exec`. ### View the journal dirty show dirty show DEFENDER dirty show DESKTOP-ABC123 Shows all logged entries. The optional filter matches against command, comment, category, hostname, and username. image ### Score summary dirty score Shows a per-host risk summary with aggregate score, pending cleanup count, and a visual bar. Hosts are sorted highest score first. ### Mark entries as cleaned dirty clean dirty clean all dirty clean host Hostname matching is case-insensitive and supports partial matches — `DESKTOP` matches `DESKTOP-FGN4LPG`. ### Export dirty export text dirty export json dirty export text DEFENDER dirty export json DESKTOP-ABC Exports are written to the directory containing `ledger.cna` and include a host score summary at the top followed by the full change log. The **Ledger** menu bar buttons trigger unfiltered exports directly. ### Help dirty help ## Categories and Default Scores | Category | Default Score | Default Comment | |----------------|:-------------:|--------------------------------| | REGISTRY | 2 | Registry modified | | FIREWALL | 3 | Firewall rule modified | | SERVICE | 3 | Service configuration changed | | RPC | 4 | Changes in RPC made | | WINRM | 4 | WinRM enabled | | SMB | 4 | SMB signing changed | | DCOM | 4 | DCOM enabled | | RDP | 5 | RDP enabled | | SCHEDULED_TASK | 5 | Scheduled task created | | DEFENDER | 6 | Defender configuration changed | | GROUP | 6 | Group membership modified | | USER | 7 | User account modified | | ACL | 8 | ACL modified | | SPN | 8 | SPN modified | | DOMAIN_ADMIN | 9 | Domain admin group modified | | TRUST | 9 | Trust relationship modified | Any unlisted category is accepted with a default score of 3. ## Risk Thresholds **Per entry** | Label | Score | |--------|--------| | LOW | < 5 | | MEDIUM | 5 – 7 | | HIGH | 8+ | **Aggregate (per host)** | Label | Score | |----------|---------| | LOW | < 5 | | MEDIUM | 5 – 9 | | HIGH | 10 – 14 | | CRITICAL | 15+ | ## Dead Beacon Warning When a beacon goes dead with uncleaned ledger entries still pending, Ledger fires a red warning to the Cobalt Strike Event Log visible to all connected operators: image The warning fires once per beacon and resets automatically if the beacon recovers and checks in again. Linked (child) beacons and beacons explicitly killed by an operator are excluded. Warning timing scales with the beacon's sleep setting — a 60s sleep triggers after ~2 minutes, a 5m sleep after ~10 minutes. ## Export Format ### Text LEDGER EXPORT -- 2026-05-21 19:50:34 HOST SCORE SUMMARY ================================================================================ Host Risk Score Pending Bar -------------------------------------------------------------------------------- DESKTOP-RLP4KBJ (sally *) CRITICAL +21 2 pend [##########] DESKTOP-FGN4LPG (Admin) CRITICAL +18 0 pend [#########] ================================================================================ CHANGE LOG ================================================================================ [000002] 2026-05-21 19:22:56 | neo | GROUP | MEDIUM +6 | CLEANED Host : DESKTOP-FGN4LPG User : Admin Process : HTTP Listener_x64.exe (PID 4716) Command : net group 'Domain Admins' svc_backup /add /domain Comment : Added svc_backup to Domain Admins for lateral movement ### JSON { "exported": "2026-05-21 19:53:19", "host_summary": [ { "host": "DESKTOP-FGN4LPG (Admin)", "risk": "CRITICAL", "score": 18, "pending": 0 }, { "host": "DESKTOP-RLP4KBJ (sally *)", "risk": "CRITICAL", "score": 21, "pending": 2 } ], "entries": [ { "id": "000004", "timestamp": "2026-05-21 19:31:36", "operator": "neo", "beacon_id": "1607712302", "computer": "DESKTOP-RLP4KBJ", "beacon_user": "sally *", "beacon_process": "HTTP Listener_x64.exe (PID 11540)", "functionality": "USER", "command": "net user svc_backup P@ssw0rd123! /add /domain", "comment": "Created service account for persistence", "score": 7, "risk": "MEDIUM", "cleaned": false } ## Multi-Operator Usage Every logged and cleaned entry is broadcast to the Cobalt Strike Event Log via `elog`, so all connected operators see each other's changes in real time. The journal lives in teamserver memory for the duration of the session. ## Notes - The journal is **in-memory only** and does not persist across teamserver restarts. Export before shutting down. - Exports are written to the directory containing `ledger.cna`. - Score overrides are supported: `dirty USER "net user ..." "my comment" 9` — the final argument sets an explicit score. - Loading the script twice (e.g. once via Script Manager and once manually) will register duplicate event handlers. Check **Script Manager** if you see doubled output.