Skip to content
Live feed Loading threat feed…

BloodBash vs DCSync in a Ludus AD Lab (s12)

BloodBash vs DCSync in a Ludus AD Lab (s12)
Anthony Russell, SquidSec

Written by

Anthony Russell

☣️ Mr. The Plague ☣️

Founder & Lead Penetration Tester OSCP+ | GWAPT

Anthony Russell is a Senior Cyber Security Engineer specializing in Application Security, with 13+ years of professional experience blending deep full-stack software engineering expertise and offensive security skills.

Full bio on the team page

Hey everyone, Mr. The Plague here from SquidSec. Engineering expanded the Ludus s12 write-up: BloodBash on a planted SharpHound zip, DCSync on the domain root, no Neo4j. Commands and outputs below are theirs. Lab only.

Lab only. Point BloodBash at the planted SharpHound zip. GetChanges plus GetChangesAll on LAB.LOCAL is the finding.

LAB-ONLY. Authorized lab scenario from the public SquidSec/BloodBash repo, ludus-env-data/ accuracy corpus. Fictional hosts (LAB.LOCAL, SS-HOP01, dcsync_user). Not a client engagement. No real targets.

BloodBash is an offline SharpHound/AzureHound analyzer. No Neo4j. Point it at JSON or a zip and it graphs AD/Entra misconfig. It is heuristic. Prefer BloodHound CE when you need path parity (README). This write-up is one planted path: DCSync on the domain root, scenario s12.

01 Artifacts

Artifact Path
Ground truth ludus-env-data/scenarios/s12_dcsync.md
Plant playbook ludus-env-data/ansible/scenarios/s12_dcsync.yml
SharpHound zip ludus-env-data/collections/s12.zip
Lab notes ludus-env-data/README.md, ludus-env-data/RESULTS.md
Cookbook docs/cookbook.md

02 What the lab plants

s12_dcsync.md:

# s12_dcsync
## Config
- dcsync_user GetChanges+All on domain
## Expect
- DCSync

Ansible (s12_dcsync.yml) runs on the DC. It creates dcsync_user in CN=Users,DC=lab,DC=local and grants on DC=lab,DC=local:

  • 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2 DS-Replication-Get-Changes
  • 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2 DS-Replication-Get-Changes-All

That pair is DCSync. Chain: control of DCSYNC_USER@LAB.LOCAL → DCSync against LAB.LOCAL. No extra hops in this scenario.

Lab password in the corpus playbook is Sync!Pass1. Corpus-only. Do not reuse it outside this corpus.

README: DCSync is GetChanges plus GetChangesAll. Nested DA/EA is expected. --quick-wins flags unexpected DCSync.


03 How you run BloodBash

From ludus-env-data/README.md:

bloodbash collections/s12.zip --all --fast
bloodbash /path/to/json --quick-wins
bloodbash ./sharpout --from-user alice --from-user-export
bloodbash /path/to/json --all --fast
python3 BloodBash.py DIR --dcsync --adcs --dangerous-permissions
bloodbash collections/s02.zip --all --fast
bloodbash collections/s01.zip --from-user domainuser --shortest-paths

RESULTS.md on the s12 zip (SharpHound --RebuildCache as domainadmin):

  • size: 32101
  • users include DCSYNC_USER@LAB.LOCAL
  • ground-truth hit: DCSync|GetChanges|DCSYNC: YES

04 Flags

Flag Notes from Engineering
--all Full pass on the collection
--fast Faster graph walk
--quick-wins Unexpected DCSync and similar
--dcsync DCSync-focused check
--from-user Start user for paths
--shortest-paths Shortest paths from that user
--all-findings Dump findings
--rebuild-cache Rebuild cache (SharpHound / analyzer as documented)
--help CLI help

05 What is in s12.zip

SharpHound: RebuildCache as domainadmin schtask. Collection 2026-07-19 03:57.

20260719035706_computers.json
20260719035706_users.json
20260719035706_groups.json
20260719035706_containers.json
20260719035706_domains.json
20260719035706_gpos.json
20260719035706_ous.json

On domain object LAB.LOCAL in 20260719035706_domains.json, SharpHound stored ACEs for SID S-1-5-21-1707202772-3147005431-673785926-1123 (DCSYNC_USER@LAB.LOCAL):

{
  "PrincipalSID": "S-1-5-21-1707202772-3147005431-673785926-1123",
  "PrincipalType": "User",
  "RightName": "GetChanges",
  "IsInherited": false
}
{
  "PrincipalSID": "S-1-5-21-1707202772-3147005431-673785926-1123",
  "PrincipalType": "User",
  "RightName": "GetChangesAll",
  "IsInherited": false
}

Same pair the playbook wrote. BloodBash matches those rights on the domain. Other GetChanges* on DCs/Admins is expected.

Users in the zip (RESULTS.md / users JSON): DCSYNC_USER@LAB.LOCAL, DOMAINUSER@LAB.LOCAL, DOMAINADMIN@LAB.LOCAL, plus built-ins.


06 Why this is Domain Admin in the lab

GetChanges + GetChangesAll on the domain lets the principal request replication of directory secrets (including DA and krbtgt material) from a DC. In this lab that principal is a dedicated user, not Domain Admins. That is the s12 scoring finding.

This corpus is cleanup → plant → SharpHound → BloodBash. Planted accuracy corpus. Not a live-client playbook.


  • s01_helpdesk_fcp.md: HelpDesk ForceChangePassword on hopadmin, local Admin on HOP01; bloodbash collections/s01.zip --from-user domainuser --shortest-paths
  • s02: Kerberoast SVC_SQL YES; bloodbash collections/s02.zip --all --fast
  • s03: AS-REP ASREP_USER YES
  • s05_localadmin_path.md: PATH_USER LocalAdmin on SS-HOP01 (RESULTS: YES)

s12 is the clean DCSync case. Use the zip and markdown that already ship.

Repo: https://github.com/SquidSec/BloodBash

Mr. The Plague / SquidSec
U.S. Veteran-Owned. Cleveland.

On this page