black electronics

Active Directory

Active Directory Enumeration

Active Directory Enumeration

Active Directory is the backbone of most enterprise networks, and enumerating its configuration, trusts and privileged access often reveals the most direct paths to full domain compromise. This section covers tools and techniques for identifying misconfigurations, excessive privileges and other weaknesses within an AD environment.

BloodHound

BloodHound is an Active Directory security tool that maps relationships between users, groups, computers, sessions, permissions and other objects within an Active Directory environment.

Rather than looking at individual configuration weaknesses in isolation, BloodHound allows us to look at Active Directory as a graph. Objects such as users and computers become nodes, while relationships such as group membership, administrative privileges and active sessions become edges connecting those nodes.

This becomes extremely useful during an internal penetration test because seemingly insignificant permissions can sometimes be chained together to create a path to a highly privileged account.

For example, a compromised user may not be a Domain Administrator, but they may control another account, which is a member of a group that has administrative access to a server where a Domain Administrator has an active session.

BloodHound helps identify these relationships and potential attack paths. You can find it here: https://github.com/SpecterOps/BloodHound

You can find a comprehensive BloodHound cheat sheet on this site covering collection methods and useful Cypher queries in more detail.

How BloodHound Works

BloodHound itself does not magically know what exists inside the target Active Directory environment. Data first needs to be collected from the domain and then imported into BloodHound.

Several collectors can be used depending on where we are operating from.

From Windows, SharpHound is commonly used.

From Linux, BloodHound.py can collect much of the same Active Directory information without requiring a Windows host.

For Azure / Entra ID environments, AzureHound can be used to collect cloud identity information.

SharpHound

SharpHound is the official Active Directory data collector used by BloodHound.

If using the PowerShell collector, first import SharpHound:

Terminal window
cd BloodHound-master\BloodHound-master\Ingestors\
Import-Module .\SharpHound.ps1

We can then perform a broad collection:

Terminal window
Invoke-BloodHound -CollectionMethod All

If we only want to collect currently logged-on users:

Terminal window
Invoke-BloodHound -CollectionMethod LoggedOn -Verbose

A specific domain can also be targeted:

Terminal window
Invoke-BloodHound -Domain example.local -CollectionMethod All

If we know the Domain Controller:

Terminal window
Invoke-BloodHound -Domain example.local -DomainController 10.10.10.10 -CollectionMethod All

Credentials can also be explicitly supplied:

Terminal window
Invoke-BloodHound -CollectionMethods All `
-Domain example.local `
-LdapUsername 'username' `
-LdapPassword 'password'

Excluding Domain Controllers

Depending on the environment and the collection methods being used, we may want to exclude Domain Controllers:

Terminal window
Invoke-BloodHound -CollectionMethod All -ExcludeDC

This can reduce some potentially noisy collection activity against Domain Controllers and may be useful where monitoring products are present.

The appropriate collection method should always be selected according to what information is actually required rather than automatically performing the broadest possible collection.

Running SharpHound as Another Domain User

Sometimes we have valid domain credentials but our current Windows session is not running as that user.

runas with /netonly allows us to start a process where the supplied credentials are used for remote network authentication:

Terminal window
runas.exe /netonly /user:EXAMPLE\username "powershell.exe"

Alternatively:

Terminal window
runas /netonly /user:[email protected] "powershell"

SharpHound can then be executed from the newly opened PowerShell session.

This is particularly useful when testing from a workstation that is not joined to the target domain.

Session Collection

Active sessions are particularly valuable in BloodHound because they can reveal where privileged users are currently logged in.

SharpHound can repeatedly collect session information:

Terminal window
.\SharpHound.exe --CollectionMethods Session --Loop --LoopDuration 00:45:00 --Domain example.local

Credentials can also be supplied:

Terminal window
.\SharpHound.exe --CollectionMethods Session `
--Loop `
--LoopDuration 00:45:00 `
--Domain example.local `
--ldapusername 'username' `
--ldappassword 'password'

A shorter collection loop can also be performed:

Terminal window
.\SharpHound.exe -c All --Loop --LoopDuration 00:10:00 --Domain example.local

Or:

Terminal window
.\SharpHound.exe --collectionmethods All `
--Loop `
--LoopDuration 00:05:00 `
--domain example.local `
--ldapusername 'username' `
--ldappassword 'password'

Looping is useful because sessions are temporary.

A privileged administrator may not be logged into an interesting server when the initial collection occurs, but may establish a session several minutes later.

Repeated session collection can therefore reveal attack paths that would not appear in a single snapshot.

BloodHound.py

If we are testing from Linux, BloodHound.py can collect Active Directory information without requiring SharpHound to execute on a Windows system.

A typical collection using NTLM authentication is:

Terminal window
bloodhound-python \
-p 'password' \
-c All \
--zip \
-d example.local \
-dc dc01.example.local \
-ns 10.10.10.10 \
-gc dc01.example.local \
--auth-method ntlm

The important values here are:

-u Username
-p Password
-c Collection methods
--zip Create a ZIP ready for BloodHound
-d Domain
-dc Domain Controller
-ns DNS server
-gc Global Catalog

Another example:

Terminal window
bloodhound-python \
-u username \
-p password \
-c All \
--zip \
-d example.local \
-dc dc01.example.local \
-ns 10.10.10.10 \
-gc dc01.example.local \
--auth-method ntlm

Kerberos authentication can also be used:

Terminal window
bloodhound-python \
-u 'username' \
-p 'password' \
-d example.local \
-c All \
--zip \
-dc dc01.example.local \
-ns 10.10.10.10 \
-gc dc01.example.local \
--auth-method kerberos

Where we do not need to explicitly specify the Domain Controller or Global Catalog, a shorter command may be sufficient:

Terminal window
bloodhound-python \
-u username \
-p password \
-c All \
--zip \
-d example.local \
-ns 10.10.10.10 \
--auth-method ntlm

BloodHound.py is particularly useful during internal testing from Kali or another Linux attack host where we have valid domain credentials and network access to the required Active Directory services.

Importing the Data

Once SharpHound or BloodHound.py has completed, the resulting data can be imported into BloodHound.

Depending on the version being used, the exact interface differs, but the overall process remains the same.

After importing the data, BloodHound can begin displaying relationships and calculating attack paths.

Legacy BloodHound and Neo4j

Older versions of BloodHound use a locally installed Neo4j database.

Although newer BloodHound releases have changed the architecture, it can still be useful to maintain a legacy BloodHound environment when working with older tooling, custom queries or existing datasets.

Starting Neo4j from PowerShell

Navigate to the Neo4j installation:

Terminal window
cd D:\Pentest\CRTP\Tools\neo4j-community-4.1.1\bin

Import the Neo4j management module:

Terminal window
Import-Module .\neo4j-management.psd1

Start Neo4j:

Terminal window
Invoke-Neo4j console

Running Neo4j as a Service

Alternatively, install Neo4j as a Windows service:

Terminal window
cd \neo4j-community-4.1.1-windows\neo4j-community-4.1.1\bin
neo4j.bat install-service
neo4j.bat start

The Neo4j browser can then be accessed locally:

http://localhost:7474

The historical default credentials are:

neo4j:neo4j

On first login, change the default password.

Once Neo4j is running, start BloodHound and upload the ZIP or JSON data generated by the collector.

Setting Up Legacy BloodHound

For legacy BloodHound:

  1. Download Neo4j Desktop for Windows or Linux.
  2. Download a legacy BloodHound release.
  3. Create a local Neo4j database.
  4. For the environment documented here, Neo4j 4.4.26 was used.
  5. Start the database and launch BloodHound.
  6. Import the collected SharpHound data.

Legacy BloodHound releases:

https://github.com/SpecterOps/BloodHound-Legacy/releases

When running the legacy BloodHound client on Kali, GPU-related issues can sometimes be avoided with:

Terminal window
./BloodHound --disable-gpu --use-gl=swiftshader

Querying BloodHound

BloodHound provides built-in queries for common Active Directory attack paths, but we can also query the underlying graph directly.

Legacy BloodHound uses Neo4j and the Cypher query language.

This becomes useful when we want to answer very specific questions about the environment that are not covered by the default BloodHound queries.

Finding Domain Administrators

To retrieve members of the Domain Admins group:

MATCH (u:User)-[:MemberOf]->(g:Group {name: 'DOMAIN [email protected]'})
RETURN u.name

The results can then be exported from the Neo4j browser as CSV.

This provides a quick way of producing a list of highly privileged accounts for further investigation.

Enumerating Group Members

Return all users belonging to a specific group:

MATCH (g:Group {name: 'IT [email protected]'})<-[:MemberOf]-(u:User)
RETURN u.name AS UserName

This is useful when an interesting security group has been identified and we want to determine which accounts inherit its privileges.

Find Users with Password Not Required

Search for enabled users where the passwordnotreqd property is set:

MATCH (n:User {enabled: True, passwordnotreqd: True})
RETURN n

These accounts warrant further investigation as the PASSWD_NOTREQD account flag can indicate weak account configuration.

The presence of the flag does not by itself prove that the account currently has a blank password, so the result should be validated rather than automatically treated as an empty-password account.

Searching Object Descriptions

Active Directory descriptions are often overlooked during security assessments.

Administrators sometimes place operational information, account details or even credentials into user and computer descriptions.

Find Users with Descriptions

MATCH (c:User)
WHERE c.description IS NOT NULL
RETURN c.name,c.description

Find Computers with Descriptions

MATCH (c:Computer)
WHERE c.description IS NOT NULL
RETURN c.name,c.description

We can also search user descriptions for specific keywords:

MATCH (u:User)
WHERE u.description CONTAINS "pass"
RETURN u.name, u.displayname, u.description, u.group

Keywords worth investigating may include:

pass
password
pwd
admin
service
temp
VPN

Any interesting values should be manually reviewed before determining whether sensitive information has actually been exposed.

Exporting Users and Email Addresses

Sometimes we simply want to use BloodHound’s collected data as a convenient source of Active Directory users.

Return all usernames:

MATCH (u:User)
RETURN u.name

Return email addresses:

MATCH (u:User)
RETURN u.email

When using Neo4j Desktop Browser, the results can then be downloaded as CSV.

This can be useful for producing user lists for other authorised enumeration activities.

Finding Owned Users in a Group

BloodHound allows nodes to be marked as Owned when an account or system has been compromised during the assessment.

Once compromised users have been marked, we can query those relationships.

For example, find all owned users belonging to a particular VPN access group:

MATCH (g:Group {name: 'VPN ACCESS [email protected]'})<--(u:User)
WHERE u.owned = true
RETURN u.name AS OwnedUser,
u.objectid AS ObjectID,
g.name AS GroupName

This can quickly reveal whether a compromised account also has access to sensitive services or security groups.

Finding Systems a Group Administers

To identify computers where a particular group has local administrative privileges:

MATCH (g:Group {name: 'DOMAIN [email protected]'})-[:AdminTo]->(c:Computer)
RETURN g.name AS GroupName, c.name AS ComputerName

This becomes particularly interesting when broad groups such as Domain Users have administrative access to systems.

If a compromised account belongs to the group, those systems may represent immediate opportunities for lateral movement.

Custom BloodHound Queries

BloodHound can be extended with collections of custom Cypher queries.

Useful resources include:

https://github.com/hausec/Bloodhound-Custom-Queries
https://github.com/CompassSecurity/BloodHoundQueries/blob/master/BloodHound_Custom_Queries/customqueries.json

For older Windows BloodHound installations, custom queries can be downloaded into the user’s BloodHound configuration directory:

Terminal window
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/CompassSecurity/BloodHoundQueries/master/BloodHound_Custom_Queries/customqueries.json" `
-OutFile "$env:USERPROFILE\AppData\Roaming\bloodhound\customqueries.json"

On Linux:

Terminal window
curl -o ~/.config/bloodhound/customqueries.json \
"https://raw.githubusercontent.com/CompassSecurity/BloodHoundQueries/master/BloodHound_Custom_Queries/customqueries.json"

Custom queries can dramatically expand what can be investigated from an existing BloodHound dataset without requiring additional collection.

What Should We Look For?

Collecting BloodHound data is only the beginning.

During an Active Directory assessment we should use the resulting graph to investigate questions such as:

  • Which accounts have paths to Domain Admin?
  • Which computers have privileged users logged into them?
  • Which users or groups have local administrator access?
  • Are broad groups privileged over large numbers of computers?
  • Which accounts can modify privileged groups?
  • Which users can reset another user’s password?
  • Are there exploitable delegation relationships?
  • Are there dangerous ACL relationships?
  • Are compromised accounts members of interesting groups?
  • Can an owned principal reach a Tier 0 object?
  • Are sensitive credentials present in object descriptions?
  • Are there unexpected paths between different privilege tiers?

The objective is not simply to produce a colourful BloodHound graph. We want to determine whether the relationships represented by the graph can be turned into a practical attack path.

Using Owned Accounts

As accounts and systems are compromised during an assessment, mark them as owned in BloodHound.

This changes BloodHound from being purely an Active Directory visualisation tool into something that can help guide the next stage of the penetration test.

Rather than repeatedly asking:

“What can reach Domain Admin?”

we can ask the much more useful question:

“What can I currently control reach?”

This can dramatically reduce the amount of irrelevant information when working with a large Active Directory environment.

AzureHound

BloodHound can also be used to analyse relationships within Azure / Entra ID environments.

AzureHound performs the data collection role for Azure environments in much the same way that SharpHound does for Active Directory.

Preparing PowerShell

Install the Azure PowerShell modules:

Terminal window
Install-Module -Name Az -AllowClobber
Install-Module -Name AzureADPreview -AllowClobber

Authenticate:

Terminal window
Connect-AzureAD
Connect-AzAccount

The authentication window will prompt for the required credentials.

PowerShell AzureHound

Import AzureHound:

Terminal window
Import-Module .\AzureHound.ps1

Collect the Azure data:

Terminal window
Invoke-AzureHound

The resulting data can then be imported into a compatible BloodHound environment.

AzureHound Binary

AzureHound can also be run directly:

Terminal window
.\azurehound.exe list \
-p "password" \
-t "example.onmicrosoft.com" \
-o example.json

The tenant name can be identified through other Entra ID enumeration techniques if it is not already known.

Querying Azure Data

Once AzureHound data has been imported, Cypher queries can be used to investigate Azure relationships.

For example:

MATCH p =(n)-[r:AZGlobalAdmin*1..]->(m)
RETURN p

This can be used to investigate relationships involving the Global Administrator role within compatible BloodHound/AzureHound datasets.

Azure attack paths can be particularly valuable because privilege does not always come from direct role assignment. Group membership, application ownership, service principals and other relationships can potentially create indirect paths to privileged resources.

PingCastle

PingCastle is an Active Directory security assessment tool used to quickly identify common configuration weaknesses, privilege risks, outdated systems, trust relationships and other security issues within an AD environment. You can find it here: https://github.com/netwrix/pingcastle

You can find a comprehensive PingCastle cheat sheet on this site covering installation and additional commands in more detail.

Health Check

PingCastle generates an HTML report containing identified risks, affected objects and recommendations. Once I have credentials I always run this to get a great overview of the Active Directory health and what components to focus on for the penetration test.

Terminal window
.\PingCastle.exe --healthcheck # Run a health check against the current domain
.\PingCastle.exe --healthcheck --server dc01.domain.local # Target a specific domain controller or domain
.\PingCastle.exe --server domain.local --user username --password password --healthcheck # Specify credentials
.\PingCastle.exe --healthcheck --server domain.local --level Full # Run a detailed, full assessment
.\PingCastle.exe --healthcheck --server domain.local --privileged --level Full # Run with privileged checks for additional detail where suitable credentials are available

Domain and Forest Mapping

PingCastle can quickly map interconnected domains and trusts without performing a full health check, which is useful early in an engagement to understand the overall AD topology before testing in detail.

Terminal window
.\PingCastle.exe --carto # Map interconnected domains, trusts and forests
.\PingCastle.exe --healthcheck --reachable # Assess all reachable domains
.\PingCastle.exe --healthcheck --server * # Scan all reachable domains in the forest
.\PingCastle.exe --healthcheck --server domain.local --explore-trust # Explore domain trusts
.\PingCastle.exe --healthcheck --server domain.local --explore-forest-trust # Explore forest trusts

Targeted Scanners

PingCastle also includes several scanners that can be run independently of the full health check. If I need to target a specific service like SMB I use the following.

Terminal window
.\PingCastle.exe --scanner <scanner> --server domain.local
ScannerDescription
smbChecks SMB versions and whether SMB signing is enforced (NTLM relay exposure)
shareEnumerates network shares, including those accessible to broad groups
localadminEnumerates local administrator group memberships
laps_bitlockerChecks whether LAPS and BitLocker are deployed
computerversionIdentifies obsolete or unsupported operating systems
antivirusIdentifies systems where an antivirus product can’t be detected
spoolerChecks whether the Print Spooler service is remotely accessible
nullsession / nullsession-trustChecks for null-session access, including trust enumeration
oxidbindingsEnumerates network interfaces via the DCOM OXID Resolver (no authentication required)
smb3querynetworkEnumerates network interfaces via SMB3 (authentication required)
remoteIdentifies remote access software installed on domain computers
zerologonChecks domain controllers for the ZeroLogon vulnerability
smbhotfixChecks for MS17-010/EternalBlue indicators
kerberoschecksumhotfixChecks for the MS14-068 Kerberos checksum vulnerability patch

Entra ID Assessment

PingCastle can also assess Entra ID. Launch it interactively with .\PingCastle.exe, select entraid, then authenticate with useprt (using an available Primary Refresh Token) or askcredential.

Once complete, I use the following jq command to extract the MFA status from the generated JSON report.

Terminal window
jq -r '.Roles[].members[] | [.MFAStatus[], .EmailAddress, .DisplayName] | @csv' pingcastlecloud_domain.onmicrosoft.com.json

Consolidating and Regenerating Reports

Terminal window
.\PingCastle.exe --hc-conso # Consolidate multiple health check reports, useful across multiple domains or forests
.\PingCastle.exe --regen-report report.xml # Regenerate an HTML report from an existing XML report
Useful LinksPentest PayloadsCheat Sheets