In order to obtain information about our target domain we need to enumerate it. There are several ways to enumerate the domain with some kali tools, but in this section we are going to use PowerShell and the .NET framework.
- Domain Class:
$ADClass = [System.DirectoryServices.ActiveDirectory.Domain]
$ADClass::GetCurrentDomain()
Exists multiple scripts to enumerate the domain.
- PowerView.ps1: https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1
- ADModule: https://docs.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps
- SharpView: https://github.com/tevora-threat/SharpView
- ADSearch: https://github.com/tomcarver16/ADSearch
Powerview on Linux
There are some alternatives based on linux systems.
First we need to obtain a TGT, to do that task we can use impacket-getTGT
.
impacket-getTGT domain/user:pass -dc-ip 10.10.10.10
Use klist
to get the info about the ticket.
klist example.ccache
We can save the ticket on a variable or we can specify it on each command:
Note: pywerview needs the FULL hostname in SPN to work properly.
export KRB5CCNAME=example.ccache
ython3 pywerview.py get-netcomputer -t srv-ad.contoso.com -u stormtroopers -k
KRB5CCNAME=example.ccache python3 pywerview.py get-netcomputer -t srv-ad -u stormtroopers -k
Importing the module
- PowerView:
First of all the module needs to be imported. Normally is not detected by AV, in case of detection, AMSI will need be evaded.
Import-Module .\PowerView.ps1
. .\PowerView.ps1
- ADModule:
Its important to import first a .dll
file if RSAT is not installed on the machine.
Import-Module .\Microsoft.ActiveDirectory.Management.dll
Import-Module .\ActiveDirectory\ActiveDirectory.psd1
Current Domain
- PowerShell:
$env:USERDNSDOMAIN
Identify current user domain
(Get-ADDomain).DNSRoot
Identify current computer domain
(Get-WmiObject Win32_ComputerSystem).Domain
- PowerView:
Get-NetDomain
- PowerView (dev):
Get-Domain
- ADModule:
Get-ADDomain
Another Domain
- PowerView:
Get-NetDomain -Domain corp.local
- PowerView (dev):
Get-Domain -Identity corp.local
- ADModule:
Get-ADDomain -Identity corp.local
Domain SID
- PowerView:
Get-DomainSID
- ADModule:
We can find the SID inside the
Get-ADDomain
output.
(Get-ADDomain).DomainSID
Get-ADDomain | select DNSRoot,NetBIOSName,DomainSID
Domain Policy
- PowerView:
Get-DomainPolicy (Get-DomainPolicy)."system access" (Get-DomainPolicy -Domain corp.local)."system access"
- PowerView (dev):
Get-DomainPolicyData | select -ExpandProperty SystemAccess
Domain Controllers
- PowerView:
Get-NetDomainController Get-NetDomainController -Domain corp.local
- PowerView (dev):
Get-DomainController Get-DomainController -Domain corp.local
- ADModule:
Get-ADDomainController Get-ADDomainController -DomainName corp.local
Users & their Properties / Attributes
- PowerView:
Get-NetUser Get-NetUser -Domain corp.local Get-NetUser -Username <user> Get-NetUser -SPN Get-UserProperty Get-UserProperty -Properties pwdlastset
- PowerView (dev):
Get-DomainUser Get-DomainUser -Identity <user> Get-DomainUser -Properties pwdlastset
- ADModule:
Get-ADUser -Filter * -Properties * Get-ADUser -Server corp.local -Filter * -Properties * Get-ADUser -Identity <username> -Properties * Get-ADUser -Filter * -Properties * | select -First 1 | Get-Member -MemberType *Property | select Name Get-ADUser -Filter * -Properties * | select name,@{expression={[datetime]::fromFileTime($_.pwdlastset)}}
Note: Some sysadmins paste the password on the description field.
Note: Service accounts stores the password on the LSAS in clear text.
Search a particular string in users’s attributes
Valuable info can be found in user’s attributes such as description.
- PowerView:
Find-UserField -SearchField Description -SearchTerm "built"
- ADModule:
Get-ADUser -Filter 'Description -like "*built*"' -Properties Description | select name,Description
Computers in the domain
- PowerView:
Get-NetComputer Get-NetComputer -OperatingSystem "*Server 2016*" Get-NetComputer -Ping Get-NetComputer -FullData
- PowerView (dev):
Get-DomainComputer Get-DomainComputer -Properties DnsHostName
- ADModule:
Get-ADComputer -Filter * | select Name Get-ADComputer -Filter 'OperatingSystem -like "*Server 2016*"' -Properties OperatingSystem | select Name,OperatingSystem Get-ADComputer -Filter * -Properties DNSHostname | %{Test-Connection -Count 1 -ComputerName $_.DNSHostName} Get-ADComputer -Filter * -Properties *
Domain Groups
- PowerView:
Get-NetGroup Get-NetGroup -Domain <targetdomain> Get-NetGroup -FullData
Note: It is also possible search for all groups containing a word:
Get-NetGroup *admin*
- PowerView (dev):
Get-DomainGroup Get-Domain | where Name -like "*Admins*"
- ADModule:
Get-ADGroup -Filter * | select Name Get-ADGroup -Filter * -Properties *
Note: It is also possible search for all groups containing a word:
Get-ADGroup -Filter 'Name -like "*admin*"' | select Name
Find memberships
- PowerView:
Get-NetGroupMember -GroupName "Domain Admins" -Recurse Get-NetGroup -UserName "username"
- PowerView (dev):
Get-DomainGroupMember -Identity "Domain Admins"
- ADModule:
Get-ADGroupMember -Identity "Domain Admins" -Recursive Get-ADPrincipalGroupMembership -Identity username
Local Groups
To do that task needs administrator privs on non-dc machines.
- PowerView:
Get-NetLocalGroup -ComputerName dc01.corp.local -ListGroups Get-NetLocalGroup -ComputerName filesrv1.corp.local -ListGroups
The following command shows the members of all the local groups on a machine.
Get-NetLocalGroup -ComputerName filesrv1.corp.local -ListGroups -Recurse
Logged Users (User has a session on)
Like local groups to do that task needs administrator privs on non-dc machines.
- PowerView:
Get actively logged users on a computer (needs local admin rights on the target)
Get-NetLoggedon -ComputerName filesrv1.corp.local
Get locally logged users on a computer (needs remote registry on the target (by default))
Get-LoggedonLocal -ComputerName filesrv1.corp.local
Get the last logged user on a computer (needs local admin rights and remote registry on the target (by default))
Get-LastLoggedOn -ComputerName filesrv1.corp.local
Find important targets
Shares
- PowerView:
Invoke-ShareFinder -Verbose Invoke-ShareFinder -ExcludeStandard
- PowerView (dev):
Find-DomainShare Find-DomainShare -CheckShareAccess
Sensitive Files
- PowerView:
Invoke-FileFinder -Verbose
- PowerView (dev):
Find-InterestingDomainShareFile -Include *.doc*, *.xls*, *.csv, *.ppt*
File servers
- PowerView:
Get-NetFileServer
Group Policy (GPO)
Group Policy provides the ability to manage configuration and changes easily and centrally in active directory.
- PowerView:
Get-NetGPO Get-NetGPO -ComputerName machine01.corp.local Get-NetGPO Group
- PowerView (dev):
Get-DomainGPO Get-DomainGPO -Properties DisplayName
- ADModule:
Get-GPO -All Get-GPResultantSetOfPolicy -ReportType Html -Path c:\windows\temp\report.html
NOTE: We can get more infomration with:
gpresult /R /V
Users on Localgroups
We can also get users which are in a local group of a machine using GPO.
- PowerView:
Find-GPOComputerAdmin -Computer machine01.corp.local
- PowerView (dev):
Get-DomainGPOLocalGroup | select GPODisplayName, GroupName
Or we can find machines where a user is member of a specific group.
- PowerView:
Find-GPOLocation -UserName <user> -Verbose
- PowerView (dev):
Get-DomainGPOUserLocalGroupMapping -LocalGroup Administrators | select objectName, GPODisplayName, ContainerName, ComputerName | fl
Organization Unit (OU)
- PowerView:
Get-NetOU -FullData
- PowerView (dev):
Get-DomainOU
- ADModule:
Get-ADOrganizationalUnit -Filter * -Properties *
To read which GPO is aplied to each OU, use the gplink
value extracted from Get-NetOU
.
- PowerView:
Get-NetGPO -GPOname '{FD2B3AF5-356B-ADE4-98C1F4EF8081}'
- ADModule:
Get-GPO -Guid FD2B3AF5-356B-ADE4-98C1F4EF8081
To know which computers are inside a OU:
- PowerView:
Get-NetOU -OUName Students | %{Get-NetComputer -ADSPath $_}
- PowerView (dev):
Get-DomainOU "Servers" | %{Get-DomainComputer -SearchBase $_.distinguishedname -properties name}
Access Control List (ACL)
Enables control on the ability of a process to access objects and other resources in active diectory based on:
- Access Tokens: Security context of a process which contains the identity and privileges of a user.
- Security Descriptors: SID of the owner , Discretionary ACL (DACL) and System ACL (SACL).
It’s a list of Access Control Entities (ACE) which corresponds to an individual permission or audits access. Determines who has permission and what can be done on an object.
Exists two types:
- DACL: Defines the permissions trustees a user or group have on an object.
- SACL: Logs sucess and failure audit messages when an object is accessed.
ACLs are vital to security architecture of Active Directory.
We can list the ACLs associated to a specified object, with a specified prefix, specified LDAP search or to specific path.
- PowerView:
Get-ObjectAcl -SamAccountName <username> -ResolveGUIDs Get-ObjectAcl -ADSprefix 'CN=Administrator,CN=Users' -Verbose Get-ObjectAcl -ADSpath "LDAP://CN=Domain Admins,CN=Users,DC=corp,DC=local" -ResolveGUIDS -Verbose Get-PathAcl -Path "\\dc01.corp.local\sysvol"
- ADModule:
(Get-Acl 'AD:\CN=Administrator,CN=Users,DC=corp,DC=local').Access
PowerView has a module named ACLScanner
that finds interesting ACL such as ACL that are modified or ones which determines where and which object we can modify.
- PowerView:
Invoke-ACLScanner -ResolveGUIDs Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentityReferenceName -match "RDPUsers"}
Domain Trust Mapping
We can get a list of all domain trusts for a domain.
- PowerView:
Get-NetDomainTrust Get-NetDomainTrust -Domain es.lab.corp.local
- PowerView (dev):
Get-DomainTrust
- ADModule:
Get-ADTrust Get-ADTrust -Identity es.lab.corp.local
- Other:
nltest /domain_trusts
Forest Mapping
A Forest is like a tree of domains (domain and subdomains) and the name of the forest is the name as the root domain of the tree.
We can get details about a forest:
- PowerView:
Get-NetForest Get-NetForest -Forest extcorp.local
- ADModule:
Get-ADForest Get-ADForest -Identity extcorp.local
We can get all domains in a forest:
- PowerView:
Get-NetForestDomain Get-NetForestDomain -Forest extcorp.local
- ADModule:
(Get-ADForest).Domains
We can get all global catalogs of a forest:
- PowerView:
Get-NetForestCatalog Get-NetForestCatalog -Forest extcorp.local
- ADModule:
Get-ADForest | select -ExpandProperty GlobalCatalogs
We can get the map trusts of a forest:
- PowerView:
Get-NetForestTrust Get-NetForestTrust -Forest extcorp.local
- ADModule:
Get-ADTrust -Filter 'msDS-TrustForestTrustInfo -ne "$null"'
User Hunting
Local Admin Check
Find all machines on the current domain where the current user has local admin access.
- PowerView:
Find-LocalAdminAccess -Verbose
Note: This function queries the domain controller for a list of computers
Get-NetComputer
and then use multi-threadedInvoke-CheckLocalAdminAccess
on each machine. MAKE A LOT OF NOISE
In case Find-PSRemotingLocalAdminAccess.ps1
is blocked you can use:
Import-Module .\Find-WMILocalAdminAccess.ps1
Find-WMILocalAdminAccess -ComputerName machine01.corp.local
Find-WMILocalAdminAccess -ComputerFile .\computers.txt -Verbose
NOTE: WMI needs ADMIN PRIV to work, so if we get an error is that the user has not enough privileges.
Get Local Admins (Local Admin Priv. needed)
We can find local admins on all machines of the domain but we need administrator privileges on non-dc machines.
- PowerView:
Invoke-EnumerateLocalAdmin -Verbose
Note: This function queries the DC fo a list of computers
Get-NetComputer
an then use multi-threadedGet-NetLocalGroup
on each machine.MAKE A LOT OF NOISE
Sessions opened on a machine
Returns session information for a computer where CName
is the source IP.
- PowerView Dev:
Get-NetSession -ComputerName dc01.corp.local | select CName, UserName
Machines where a User/Group has session
We can find computers where a domain admin or another specified user or group has an active session:
- PowerView:
Invoke-UserHunter Invoke-UserHunter -GroupName "RDPUsers" Invoke-UserHunter -UserName "john.brown"
Note: This function queries the DC for members of a given group using
Get-NetGroupMember
, gets a list of computers withGet-NetComputer
and list sessions and logged users withGet-NetSession
andGet-NetLoggedon
from each machine.
We can also confirm the admin access with:
- PowerView:
Invoke-UserHunter -CheckAcces
We can also find with
Invoke-UserHunter
where a domain admin is logged-in. - PowerView:
Invoke-UserHunter -Stealth
Note: This option queries the DC for members of the given group using
Get-NetGroupMember
, gets a list of only of high traffic servers such as DC, File Servers and Distributed File Servers for less traffic generation and list sessions and logged on users withGet-NetSession
andGet-NetLoggedon
.MAKE NOISE
RedTeam Note: To prevent of beeing detected by the Microsoft ATA (Advanced Thread Analytics) that analyzes the traffic of the DC, use a list of computers and remove the DC from it.
Get-NetComputer
Invoke-UserHunter -ComputerFile hosts.txt
BlueTeam Note:
Netcease.ps1
is a script which change permission on the NetSessionEnum by removing permission to Authenticated Users group. This Script should be executed on the DC. https://github.com/p0w3rsh3ll/NetCease.To revert the effect:
.\Netcease.ps1 -Revert
After any modfification we need to restart the server:
Restart-Service -Name Server -Force
The binary net.exe uses SAMR protocol, exists another script which hardens a server. https://vulners.com/n0where/N0WHERE:139229
SQLServers
We can provide a list of all SQL servers which have a SPN register on the domain controller.
- PowerUPSql
Get-SQLInstanceDomain
Note: This not mean that is a SQL Server running or listening, that means htat there are a MSSQL on a SPN.
BloodHound
Provides GUI for AD entities and relationships for the data collected by its ingestors (SharpHound.ps1).
https://github.com/BloodHoundAD/BloodHound
First we need to run ingestors on a machine in order to collect data.
. .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod All -Verbose
SharpHound has a number of different collection methods (all documented on the repository):
- Default: Performs group membership collection, domain trust collection, local group collection, session collection, ACL collection, object property collection, and SPN target collection
- Group: Performs group membership collection
- LocalAdmin: Performs local admin collection
- RDP: Performs Remote Desktop Users collection
- DCOM: Performs Distributed COM Users collection
- PSRemote: Performs Remote Management Users collection
- GPOLocalGroup: Performs local admin collection using Group Policy Objects
- Session: Performs session collection
- ComputerOnly: Performs local admin, RDP, DCOM and session collection
- LoggedOn: Performs privileged session collection (requires admin rights on target systems)
- Trusts: Performs domain trust enumeration
- ACL: Performs collection of ACLs
- Container: Performs collection of Containers
- DcOnly: Performs collection using LDAP only. Includes Group, Trusts, ACL, ObjectProps, Container, and GPOLocalGroup.
- ObjectProps: Performs Object Properties collection for properties such as LastLogon or PwdLastSet
- All: Performs all Collection Methods except GPOLocalGroup.
Sometimes BloodHound miss to check the sessions so we can execute it manually.
Invoke-BloodHound -CollectionMethod LoggedOn -Verbose
Note: Remember that we can append the invoke command at the end of the file an executed it out of memory with
iex (iwr ...)
RedTeam Note: We can avoid detections like ATA with:
Invoke-BloodHound -CollectionMethod All -ExcludeDC
After execution download the .zip
file and drop to BloodHound
in order to import it.
OPSEC Alert: Running collections method such as
LocalAdmin
,RDP
,DCOM
,PSRemote
andLoggedOn
will allow SharpHound to enumerate every single computer in the domain.Collecting this information is useful to BloodHound and without it you may see fewer paths.
To use on LDAP queries we can use DcOnly
collection method.
Invoke-BloodHound -CollectionMethod DcOnly
Raw queries
Executing raw queries is useful for finding nodes that have particular properties or to help specific attack paths.
- Query all users that have
Service Principal Name (SPN)
set.
MATCH (u:User {hasspn:true}) RETURN u
- Query all users that have
Do not require Kerberos preauthenticaion
set.
MATCH (u:User {dontreqpreauth:true}) RETURN u
- Query all computers that are
AllowedToDelegate
.
MATCH (c:Computer), (t:Computer), p=((c)-[:AllowedToDelegate]->(t)) RETURN p
- Query all computers with
Unconstrained Delegation
.
MATCH (c:Computer {unconstraineddelegation:true}) RETURN c
- Query all computers with
Constrained Delegation
.
MATCH (c:Computer), (t:Computer), p=((c)-[:AllowedToDelegate]->(t)) RETURN p
- Query all users with
Constrained Delegation
.
MATCH (u:User), (t:Computer), p=((u)-[:AllowedToDelegate]->(t)) RETURN p
- Query all Principals with GenericWrite over GPOs.
MATCH (gr:Group), (gp:GPO), p=((gr)-[:GenericWrite]->(gp)) RETURN p
- Query ACL for a specify group:
MATCH (g1:Group {name:"RDP USERS@CORP.LOCAL"}), (g2:Group), p=((g1)-[:GenericAll]->(g2)) RETURN p
- Query potential MS SQL Admins:
MATCH p=(u:User)-[:SQLAdmin]->(c:Computer) RETURN p