AD enumeration
PingCastle
Quickly identify misconfigurations, vulnerabilities, and risks within Active Directory and Entra ID environments using PingCastle.
- Download the Syslifters compiled version of PingCastle.exe
- Add license into
appsettings.console.jsonfile next to thePingCastle.exefile to run the program with the correct license. Retrieve the file or license key from your password manager / internal vault. - Run
pingcastle.exein a terminal.
Bloodhound
Map and assess Active Directory related attack paths in Active Directory and Entra ID environments.
Download the Syslifters compiled Sharphound.exe collector
Collect data
Cheatsheet: SharpHound cheat sheet (external link)
For non-admin users:
./SharpHound.exeWith domain admin, we will also want to collect sessions:
./SharpHound.exe --c AllCollect data with all attributes:
sharphound.exe -c all --collectallproperties
- Import the
.zipfile into the hosted BloodHound instance. Credentials and host info should be stored in your password manager / internal vault.
Pyldap
If BloodHound is unavailable or fails, you can achieve similar results using pyldap, a tool for manual LDAP queries that supports BloodHound-compatible output.
- Download pyldap
- Run an LDAP query, e.g.:
.\--main--.exe operation\user:<password> '(objectClass=*)' - Transform with bofhound to ingest into a BloodHound instance.
Cipher queries
Here are some practical BloodHound Cypher queries for extracting valuable information about the target environment or handling nodes.
Use these in the Neo4j web interface after data ingestion (credentials available in your password manager / internal vault).
Some queries were based on Handy BloodHound Cypher queries.
Bulk mark as owned
Tags one or more users as compromised by appending owned to their system_tags, which surfaces them as starting points in attack-path queries. The CASE block keeps the operation idempotent: it avoids duplicate tags and handles a NULL system_tags value.
MATCH (u:User)
WHERE u.samaccountname IN ["user1", "user2"]
SET u.system_tags =
CASE
WHEN u.system_tags IS NULL THEN ["owned"]
WHEN "owned" IN u.system_tags THEN u.system_tags
ELSE u.system_tags + ["owned"]
END
RETURN u.samaccountname AS updated_users, u.system_tags AS new_tags;Delete a single computer
Removes a node and all of its incoming and outgoing relationships from the graph via DETACH DELETE. Handy for cleaning up decommissioned hosts, duplicate entries or unwanted nodes. Adjust the label (:User, :Computer, :Group, ...) to match the object you want to drop.
MATCH p=(c:User)
WHERE c.name = "COMPUTER@DOMAIN.LOCAL"
detach delete pDelete a relationship between a user and another object
Useful for pruning false positives or unwanted edges (e.g. stale HasSession, irrelevant MemberOf) from the graph. Replace the edge type after r: with the relationship you want to remove, or omit it (-[r]->) to delete every relationship between the two nodes.
MATCH (u:User {name: "USER@DOMAIN.LOCAL"})-[r:HasSession]->(o)
WHERE o.name = "TARGET@DOMAIN.LOCAL"
DELETE rGet all sensitive users
Lists user accounts flagged as Account is sensitive and cannot be delegated. These are typically high-value identities (admins, service accounts handling secrets) and good candidates for further enumeration or targeting.
match (u:User) where u.sensitive = True return uGet owned users
Returns every user already marked as owned (u.owned = True), together with any captured password stored in u.pw and their distinguished name. Useful for a quick recap of which accounts you have credentials for during an engagement.
MATCH (u:User)
WHERE u.owned = True
RETURN u.samaccountname, u.pw, u.distinguishedname
ORDER BY u.nameGet all users with outbound object control
Counts, per enabled user, how many objects they can directly control via dangerous AD/ADCS rights, both directly and transitively through group membership (up to 10 hops). Results are bucketed by target type (computers, users, groups, OUs, GPOs, domains, containers, ADCS objects) and ordered by total, making it easy to spot over-privileged accounts or the best escalation candidates.
CYPHER runtime=parallel
CALL {
MATCH (u:User)-[:Owns|OwnsLimitedRights|WriteDacl|WriteOwner|WriteOwnerLimitedRights|GenericAll|GenericWrite|AllExtendedRights|ForceChangePassword|AddMembers|AddSelf|WriteSPN|AddKeyCredentialLink|ReadLAPSPassword|SyncLAPSPassword|ReadGMSAPassword|AddAllowedToAct|WriteAccountRestrictions|HasSIDHistory|WriteGPLink|DCSync|GetChanges|GetChangesAll|GetChangesInFilteredSet|ManageCA|ManageCertificates|Enroll|AutoEnroll|EnrollOnBehalfOf|WritePKIEnrollmentFlag|WritePKINameFlag|WriteCertificateMappingAccess|WriteCertificateEnrollmentFlag]->(tgt)
WHERE u <> tgt
AND coalesce(u.enabled, true) = true
RETURN u, tgt
UNION
MATCH (u:User)-[:MemberOf*1..10]->(:Group)-[:Owns|OwnsLimitedRights|WriteDacl|WriteOwner|WriteOwnerLimitedRights|GenericAll|GenericWrite|AllExtendedRights|ForceChangePassword|AddMembers|AddSelf|WriteSPN|AddKeyCredentialLink|ReadLAPSPassword|SyncLAPSPassword|ReadGMSAPassword|AddAllowedToAct|WriteAccountRestrictions|HasSIDHistory|WriteGPLink|DCSync|GetChanges|GetChangesAll|GetChangesInFilteredSet|ManageCA|ManageCertificates|Enroll|AutoEnroll|EnrollOnBehalfOf|WritePKIEnrollmentFlag|WritePKINameFlag|WriteCertificateMappingAccess|WriteCertificateEnrollmentFlag]->(tgt)
WHERE u <> tgt
AND coalesce(u.enabled, true) = true
RETURN u, tgt
}
WITH u,
COUNT(DISTINCT tgt) AS total,
COUNT(DISTINCT CASE WHEN tgt:Computer THEN tgt END) AS computers,
COUNT(DISTINCT CASE WHEN tgt:User THEN tgt END) AS users,
COUNT(DISTINCT CASE WHEN tgt:Group THEN tgt END) AS groups,
COUNT(DISTINCT CASE WHEN tgt:OU THEN tgt END) AS ous,
COUNT(DISTINCT CASE WHEN tgt:GPO THEN tgt END) AS gpos,
COUNT(DISTINCT CASE WHEN tgt:Domain THEN tgt END) AS domains,
COUNT(DISTINCT CASE WHEN tgt:Container THEN tgt END) AS containers,
COUNT(DISTINCT CASE WHEN tgt:CertTemplate OR tgt:EnterpriseCA
OR tgt:RootCA OR tgt:AIACA
OR tgt:NTAuthStore THEN tgt END) AS adcs
RETURN u.name AS user, total, computers, users, groups, ous, gpos, domains, containers, adcs
ORDER BY total DESCGet all certificates with modification rights other than DA / EA / Built-In Administrators
Finds non-administrative principals that have Owns, WriteOwner, WriteDacl, GenericAll or GenericWrite over objects under the Public Key Services container (certificate templates, CAs, NTAuthStore, ...). Domain Admins (-512), Enterprise Admins (-519) and Built-in Administrators (-544) are filtered out so only unexpected privileges remain. These are common starting points for AD CS abuse (ESC1 to ESC13).
MATCH p = (n:Base)-[:Owns|WriteOwner|WriteDacl|GenericAll|GenericWrite]->(m:Base)
WHERE m.distinguishedname CONTAINS "PUBLIC KEY SERVICES"
AND NOT n.objectid ENDS WITH "-512" // Domain Admins
AND NOT n.objectid ENDS WITH "-519" // Enterprise Admins
AND NOT n.objectid ENDS WITH "-544" // Administrators
RETURN p
LIMIT 1000Shortest path from owned users to DA (GUI functional)
Returns the shortest attack path from any owned user (system_tags CONTAINS "owned") to the Domain Admins group (SID ending in -512). The edge list mirrors what the BloodHound GUI understands, so the result can be opened and explored visually instead of just printed as raw paths.
MATCH p=shortestPath((n:User)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|Contains|GPLink|AllowedToDelegate|TrustedBy|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC5|ADCSESC6a|ADCSESC6b|ADCSESC7|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|DCFor*1..]->(m:Group))
WHERE n.system_tags CONTAINS "owned" AND m.objectid ENDS WITH "-512"
RETURN pShortest path from owned computers to DA (GUI functional)
Same as the previous query but starting from owned computers instead of users. Useful for visualizing escalation paths reachable through compromised hosts (e.g. via machine-account abuse, sessions or delegation) up to Domain Admins.
MATCH p=shortestPath((n:Computer)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|Contains|GPLink|AllowedToDelegate|TrustedBy|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC5|ADCSESC6a|ADCSESC6b|ADCSESC7|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|DCFor*1..]->(m:Group))
WHERE n.system_tags CONTAINS "owned" AND m.objectid ENDS WITH "-512"
RETURN pADRecon
Use ADRecon to gather comprehensive details about the Active Directory environment and generate an Excel (.xlsx) report for a holistic overview of the target environment.
- Execute
.\ADRecon.ps1in PowerShell. An Excel report will be generated automatically if Microsoft Office is installed. - If Office is not available, create an Excel report from the CSV files on another host using:
.\ADRecon.ps1 -GenExcel C:\ADRecon-Report-<timestamp>
Kerberoasting
Identify all service accounts with Service Principal Names (SPNs) configured that are vulnerable to Kerberoasting. Check for accounts with RC4 enabled.
# Kerberoast and write hashes to file
Rubeus.exe kerberoast /outfile:hashes.txt /nowrapAS-Rep Roasting
Find all user accounts with pre-authentication disabled, making them vulnerable to AS-Rep Roasting.
Rubeus.exe asreproast /outfile:asrephashes.txt /format:hashcat /nowrapRSAT tools
The Remote Server Administration Tools (RSAT) ship the PowerShell modules and MMC snap-ins used throughout AD enumeration: the ActiveDirectory module (Get-ADUser, Get-ADComputer, ...), DNSServer, DHCPServer, GroupPolicy, the AD CS console, and more.
- On modern Windows 10/11 clients they are optional capabilities and must be added before most
Get-AD*cmdlets will work. - On Windows servers, they are optional features. Use
Get-WindowsFeatureinstead ofGet-WindowsCapabilitythere.- E.g.,
Get-WindowsFeature RSAT-AD-PowerShell
- E.g.,
Run PowerShell as Administrator for all commands.
List installed / available RSAT capabilities:
Get-WindowsCapability -Name RSAT* -OnlineInstall everything at once:
Get-WindowsCapability -Name RSAT* -Online | Add-WindowsCapability -OnlineInstall only what you need. The AD, DNS, DHCP, Group Policy and AD CS modules cover the vast majority of engagements:
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
Add-WindowsCapability -Online -Name Rsat.Dns.Tools~~~~0.0.1.0
Add-WindowsCapability -Online -Name Rsat.DHCP.Tools~~~~0.0.1.0
Add-WindowsCapability -Online -Name Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0
Add-WindowsCapability -Online -Name Rsat.CertificateServices.Tools~~~~0.0.1.0
Add-WindowsCapability -Online -Name Rsat.FileServices.Tools~~~~0.0.1.0
Add-WindowsCapability -Online -Name Rsat.ServerManager.Tools~~~~0.0.1.0