Enumeration

Create a Domain Map. Repeat enumeration for each new access.

Identify:

  • Network (Active hosts)

  • AD Key Services (Kerberos, NetBIOS, LDAP, DNS)

  • AD computers

  • AD users

  • Vulnerabilities

Automated

BloodHound

Install Docker

sudo apt install docker.io && sudo apt install docker-compose
sudo usermod -aG docker $USER

Install Bloodhound

curl -L https://ghst.ly/getbhce  docker-compose.yml
sudo docker-compose pull

Install Bloodhound

docker-compose up
sudo docker-compose down -v

Start neo4j

sudo neo4j start

Neo4j: http://localhost:7474 Default credentials: neo4j:neo4j Will ask to change password after first login.

Bloodhound: http://localhost:8080 Default credentials: admin:<PROMPT_IN_LOG_DOCKER> Will ask to change password after first login.

Remotely

Try with "guest":"" or "":"" (and *:* for LDAP auth)

Tool
Details

Enumeration with SMB (Null Session) and LDAP (Anonymous Binds) nxc smb <IP> -u <USER> -p <PASS> [-d <DOMAIN>] --users --groups --loggedon-users --pass-pol --rid-brute nxc ldap <IP> -u <USER> -p <PASS> [-d <DOMAIN>] --users --groups [--query "(sAMAccountName=*)" ""]

LDAP Anonymous Binds ldapsearch -H ldap://<IP> -x -b "DC=goole,DC=com" -s sub "*"

Enumeration with SMB enum4linux -u <USER> -p <PASS> <IP> -a

Detailed enumeration with specific queries rpcclient -U [<DOMAIN>/]<USER>[%<PASS>] <IP> >> <QUERY>

Active Directory information dumper via LDAP ldapdomaindump -u '<DOMAIN>\<USER>' -p '<PASSWORD>' <IP> -o dump

Enumeration with LDAP query windapsearch --dc-ip <IP_DC> -u <USER>@<DOMAIN> -p <PASSWORD> -G -U -C -PU --da

Enumerate all DNS records in a domain using a valid domain user account. adidnsdump -u <DOMAIN>\\<USER> ldap://<DC> [-r]

-r attempt to resolve unknown records by performing an A query.

Manually

The ActiveDirectory PowerShell module is a set of PowerShell cmdlets for administering an Active Directory environment. Before using it, we need to make sure it is imported with Get-Module.

Get-Module
Import-Module ActiveDirectory

Domain

Get-ADDomain
echo %USERDOMAIN%
echo %logonserver%  # DC
netdom query /domain:<DOMAIN> dc

We get domain information through PowerShell, using LDAP to communicate with AD and extract information.

$domainObj = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$PDC = $domainObj.PdcRoleOwner.Name
$DN = ([adsi]'').distinguishedName 
$LDAP = "LDAP://$PDC/$DN"
$direntry = New-Object System.DirectoryServices.DirectoryEntry($LDAP)
$dirsearcher = New-Object System.DirectoryServices.DirectorySearcher($direntry)
$dirsearcher.filter="samAccountType=805306368"   # enumerate all users in the domain
# $dirsearcher.filter="name=jeffadmin"    # takes a specific user and instead of printing $prop, it prints $prop.memberof
$result = $dirsearcher.FindAll()
Foreach($obj in $result)
{
 Foreach($prop in $obj.Properties)
 {
 $prop
 }
 Write-Host "-------------------------------"
}

Workstation

netdom query /domain:<DOMAIN> workstation

Users

All users

Get-ADUser -Filter *
net user /domain

Info about specific user

Get-ADUser -Identity <USER> [-Properties *]
net user <USER> /domain

Groups

All groups

Get-ADGroup -Filter *
net group /domain

Info about specific group

Get-ADGroup -Identity <GROUP> [-Properties *]
Get-ADGroupMember -Identity <GROUP>
net group "<GROUP>" /domain 
# User members only

Share

net share
net use x: \<COMPUTER>\<SHARE>

Policy Password

net accounts [/domains]
Get-ADDefaultDomainPasswordPolicy

Deleted AD Objects

Get-ADObject -Filter 'isDeleted -eq $true -and objectClass -eq "user"' -IncludeDeletedObjects -Properties objectSid, lastKnownParent, ObjectGUID | Select-Object Name, ObjectGUID, objectSid, lastKnownParent | Format-List

Restore with (if you have permissions):

Restore-ADObject -Identity '<GUID>'

Trust

netdom query /domain:<DOMAIN> trust
Get-ADTrust -Filter *

Tickets Kerberos

klist

SPN

setspn.exe -Q */*

ACL

Get-ADUser -Filter * | Select-Object -ExpandProperty SamAccountName > ad_users.txt
foreach($line in [System.IO.File]::ReadLines("C:\<PATH>\ad_users.txt")) {get-acl  "AD:\$(Get-ADUser $line)" | Select-Object Path -ExpandProperty Access | Where-Object {$_.IdentityReference -match '<DOMAIN>\\<USER>'}}
$guid= "00299570-246d-11d0-a768-00aa006e0529" # GUID to decode
Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).ConfigurationNamingContext)" -Filter {ObjectClass -like 'ControlAccessRight'} -Properties * |Select Name,DisplayName,DistinguishedName,rightsGuid| ?{$_.rightsGuid -eq $guid} | fl

CN=<VALUE> take from ActiveDirectoryRights

PowerView

It is a PowerSploit script and there are two versions: Old and New (maintained by Empire)

Import-Module .\PowerView.ps1
Get-NetDomain # basic domain info
Get-NetUser # user info
Get-NetGroup # group info
Get-NetComputer # machine info
Get-DomainPolicy # password policy info
Find-LocalAdminAccess # machines where user has administrator privileges
Get-DomainTrust # trust
Get-DomainTrustMapping # trust relationships
Get-DomainUser * -spn # SPN
Get-DomainSID # SID domain
# Etc.

Description Field

Get-DomainUser * | Select-Object samaccountname,description |Where-Object {$_.Description -ne $null}

PASSWD_NOTREQD Field

Enumerating accounts with this flag set and testing each to see if no password is required

Get-DomainUser -UACFilter PASSWD_NOTREQD | Select-Object samaccountname,useraccountcontrol

ACL

$sid = Convert-NameToSid <USER>
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $sid}

RDP

Get-NetLocalGroupMember -ComputerName <PC_NAME> -GroupName "Remote Desktop Users"
$computers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
foreach ($computer in $computers) {
    Get-NetLocalGroupMember -ComputerName $computer -GroupName "Remote Desktop Users"
}

WinRM

Get-NetLocalGroupMember -ComputerName <PC_NAME> -GroupName "Remote Management Users"
$computers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
foreach ($computer in $computers) {
    Get-NetLocalGroupMember -ComputerName $computer -GroupName "Remote Management Users"
}

SYSVOL

The SYSVOL share can be a treasure trove of data, especially in large organizations. We may find many different batch, VBScript, and PowerShell scripts within the scripts directory, which is readable by all authenticated users in the domain. It is worth digging around this directory to hunt for passwords stored in scripts.

ls \\<DOMAIN/DC>\SYSVOL\

GPP Passwords

When a new Group Policy Preferences is created, an .xml file is created in the SYSVOL share. These files can contain an array of configuration data and defined passwords. The cpassword attribute value is AES-256 bit encrypted, but Microsoft published the AES private key on MSDN, which can be used to decrypt the password.

The gpp-decrypt utility can be used to decrypt the cpassword

gpp-decrypt <VALUE>

You can also use several tools to locate the GPP and return the decrypted cpassword value. Get-GPPPassword.ps1, the GPP Metasploit Post Module, other Python/Ruby scripts, CrackMapExec, etc.

It is also possible to find passwords in files such as Registry.xml when autologon is configured via Group Policy. We can use CrackMapExec or Get-GPPAutologon.ps1.

crackmapexec smb <IP> -u <USER> -p <PASS> -M gpp_autologin

Cypher Query Bloodhound

WinRM

MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:CanPSRemote*1..]->(c:Computer) RETURN p2

SQLAdmin

MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:SQLAdmin*1..]->(c:Computer) RETURN p2

Kerberos Double Hop Problem

When connecting to a remote system using tools like Evil-WinRM, the user's Kerberos TGT is not forwarded to the remote session, but only the TGS (see with klist command). This means the remote system can authenticate the user for the initial session, but it cannot access other resources in the domain on behalf of the user because the TGT is missing. As a result, commands that require access to additional domain resources, like querying Active Directory with PowerView, fail since there's no way to prove the user's identity beyond the initial connection. If unconstrained delegation is enabled on a server, it is likely we won't face the "Double Hop" problem. In this scenario, when a user sends their TGS ticket to access the target server, their TGT ticket will be sent along with the request.

Workaround with PSCredential Object

We can also connect to the remote host via host A and set up a PSCredential object to pass our credentials again.

$SecPassword = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('<DOMAIN>\<USER>', $SecPassword)
# Now we can use it 
import-module .\PowerView.ps1
get-domainuser -spn -credential $Cred | select samaccountname

Workaround with Register PSSession Configuration

Here we have another option to change our setup to be able to interact directly with the DC or other hosts/resources without having to set up a PSCredential object and include credentials along with every command (which may not be an option with some tools).

# WinRM session on the remote host
Enter-PSSession -ComputerName <PCName> -Credential <DOMAIN>\<USER>
Register-PSSessionConfiguration -Name <myNameSess> -RunAsCredential <DOMAIN>\<USER>
Restart-Service WinRM
# This will kick us out, so we'll start a new PSSession using myNameSess
Enter-PSSession -ComputerName <PCName> -Credential <DOMAIN>\<USER> -ConfigurationName  <myNameSess>
# Now we can run command without PSCredential 
get-domainuser -spn | select samaccountname
Note!

We cannot use Register-PSSessionConfiguration from an evil-winrm shell because we won't be able to get the credentials popup. Furthermore, if we try to run this by first setting up a PSCredential object and then attempting to run the command by passing credentials like -RunAsCredential $Cred, we will get an error because we can only use RunAs from an elevated PowerShell terminal. Therefore, this method will not work via an evil-winrm session as it requires GUI access and a proper PowerShell console. Furthermore, we could not get this method to work from PowerShell on a Parrot or Ubuntu attack host due to certain limitations on how PowerShell on Linux works with Kerberos credentials. This method is still highly effective if we are testing from a Windows attack host and have a set of credentials or compromise a host and can connect via RDP to use it as a "jump host" to mount further attacks against hosts in the environment.

We can also use other methods such as CredSSP, port forwarding, or injecting into a process running in the context of a target user (sacrificial process).

Useful Tools

Tool
Details

Powershell tool to automate Active Directory enumeration. Import-Module .\adPEAS.ps1 Invoke-adPEAS Invoke-adPEAS -Module [Domain/Rights/GPO/ADCS/Creds/Delegation/Accounts/Computer/Bloodhound -Scope All]

Allows you to see which users are connected to a specified computer. For this to work, the machine must have Remote Registry enabled. (we can get false positives because we are not sure that Remote Registry is enabled on the target) .\PsLoggedon.exe \<COMPUTER_NAME>

Tool to acquire credentials or other sensitive data in an Active Directory environment by searching between shares. Snaffler.exe -s -d <DOMAIN> -o <OUTPUT_FILE.log> -v data

A tool purpose-built to find vulnerabilities in Active Directory associated Group Policy. group3r.exe -f <OUTPUT_FILE.log>

Powerful tool that evaluates the security posture of an AD environment and provides us the results in several different maps and graphs. PingCastle.exe --help (Terminal User Interface)

Tool which gathers information about the Active Directory and generates a report which can provide a holistic picture of the current state of the target AD environment. .\ADRecon.ps1

Last updated

Was this helpful?