Lab 4.1: Enumerating Active Directory with Different Tools
Objectives
- Learning to enumerate Active Directory with a variety of tools
- Interpret output of enumeration commands and form conclusions on observed results
TTPs Emulated in this Lab
- T1087 - Account Discovery
- T1482 - Domain Trust Discovery
- T1615 - Group Policy Discovery
- T1201 - Password Policy Discovery
- T1018 - Remote System Discovery
Preparation
Preparation Steps
For this lab, we will use the student.draconem.io machine that is located in the user subnet of draconem.io, this machine can be accessed through guacamole. Go ahead and log into the machine with the following credentials:
- url: http://10.130.2.22:8080/guacamole
- username: student
- password: Sec565!!
If you need to copy paste commands, you can do so by opening the guacamole menu. On a Windows device, the Guacamole menu is displayed by pressing Ctrl + Alt + Shift. On a Mac, the Guacamole menu is displayed by pressing Ctrl ^ + Command ⌘ + Shift.
A new guacamole menu will appear in which you'll be able to paste your text. afterwards you'll be able to paste the text of the guacamole menu in your guacamole session, just like any normal paste.
Attention
In a real red team operation, it will be unlikely you are just going to be able to "drop in" through RDP, especially without proxying your RDP connection over some sort of command-and-control channel. The only reason you are allowed to do this is so you can get acquainted with all the tooling that is available, do not expect that this will be the case in real life operations!
On your own
Enumerate the following items in the domain:
1. Users
2. Computers
3. Domain trusts
4. Password policy
5. Fine grained password policy
6. Local Administrator Password Solution
7. Group managed Service Accounts
8. Identify Ip addresses and/or computernames without using nslookup
Walkthrough
In order to make sure you choose the right tactic and the right targets to achieve your objectives, enumeration is required. Throughout the course we have already discussed how to do host based enumeration, in this lab however, we are going to enumerate everything related to Active Directory.
During the lecture, we have discussed various tools and have given you various nudges to what could potentially be interesting for you to enumerate. However, do not let this be a constraint, in this lab you will follow a pre defined path to enumeration, but feel free to explore the environment any way you see fit.
It is in your best interest to perform enumeration with a multitude of tooling and using any command you deem interesting. Do not be afraid to make errors in this class, this is what the lab is for! It is much better to try new things in a controlled environment than in a real red team operation. On that note, let us jump into the lab!
User Enumeration
Probably the number one most important enumeration step you can do is start looking for valid usernames. This will let you get a feel for the Active Directory, understand their naming convention and potentially already identify some key targets that will aid you in your conquest to reach your objectives.
As mentioned in the lecture, keep a close eye on the description field of users, as they can contain valuable intelligence. Additionally, keep an eye open for svc_xxx accounts or xxx_svc accounts, those typically are service accounts that could be useful later when we would want to kerberoast some of these. In the C:\Tools folder you will find all of your favorite tools already available for you, no need to download anything!
Computer Enumeration
Much like user accounts, computer accounts provide a red team operator vital information about the architecture of the environment you are operating under. Take a close look at the naming conventions, most organizations have a policy when naming computer objects. Figuring out the naming convention will help you identify potentially interesting servers, as well as increase your opsec in the event you need to create a new computer object in the AD.
Domain Trust Enumeration
Chances are that your target environment has multiple domains that are interconnected with each other. This interconnectivity is provided by setting up domain trust(s). As a red team operator it is important to know which trusts are present in the environment, as there is a chance you will have to traverse one or several trust(s) to achieve the objective.
Password Policy Enumeration
The password policy is not really that important in a full fleged red team operation, as password spraying in a red team operation is generally not the best idea because it is extremely noisy. However, it can still be useful information for kerberoasting or as-rep roasting or if you are really stuck... yes, password spraying.
Fine-Grained Password Policy Enumeration
Fine-grained password policies are policies that are in place to serve as an additional layer of security. These password policies are applied to the user(s) and/or group(s) object(s) in Active Directory. One object can have multiple Fine-grained policies, in which case the one with the lowest precedence counter "wins". These policies are not often encountered (yet) based on our real world experience, but when they are, they provide insight in what probably are sensitive and privileged accounts. Let's take a look at how we can enumerate this.
Attention
This requires read rights on the Password Setting Container object, which is only granted to domain/enterprise administrators by default.
LAPS Enumeration
Local Administrator Password Solution is a Microsoft solution to help prevent local administrator password reuse, which is a common problem in large organizations. By pushing LAPS using a GPO, it is possible to automatically manage local administrator passwords per asset, including automatic password rotation as well. This makes it harder for an adversary to compromise multiple servers, as all local admin passwords are now random and quite secure.
As we mentioned in the lecture however, this does require a change in the basic Active Directory schema. It introduces a new attribute to the computer object under the form of the ms-Mcs-AdmPwd property. This property stores the local admin password in plain-text and is secured by a DACL. In other words, if you can compromise a user that has read privileges on the aforementioned property, you can extract the local administrator password in plain-text, effectively compromising the asset. It should come as no surprise that identifying where LAPS is deployed is beneficial for a red teamer, as we can effectively rule out password reuse on those assets and start hunting for users that are privileged enough to read LAPS passwords. Although unprivileged users cannot query the ms-Mcs-AdmPwd property, they can query the ms-Mcs-AdmPwdExpirationTime property, which will show us which computers have LAPS enabled. There is also another enumeration approach, as LAPS gets deployed using GPO, we can enumerate which computers have LAPS enabled through GPO enumeration.
gMSA Enumeration
Group managed service accounts are very similar to LAPS, but instead of local admin passwords, they are passwords for service accounts. This ensures that service accounts have strong and regularly rotated passwords, which makes it impossible for them to get kerberoasted. As a red teamer, it pays off to learn about these types of accounts as they, much like LAPS, have accounts configured that are able to retrieve the password.
DNS enumeration
When a server is responsible for DNS and there is no external appliance often reffered to as an IPAM (IP Address Management) solution, it is possible to perform DNS enumeration both reverse and forward lookups, from LDAP.
RSAT
Using RSAT for User Enumeration
1. Probably the easiest and most straight forward way of enumerating Active Directory is to use the Remote Server Administration Tool. Unfortunately, the AD RSAT modules are usually not installed by default on a workstation or server other than the Domain Controller. When this is the case, no need to panic, we can install it ourselves using PowerShell with the following command:
Add-WindowsCapability –online –Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
If you are interested what other RSAT modules can be installed, we can figure that out with PowerShell too!
Get-WindowsCapability -Name RSAT* -Online | Select-Object -Property DisplayName, State
2. For our lab environment, we went ahead and already preinstalled the necessary RSAT tooling for you. To launch RSAT, go to the windows button on the left hand side to open the search menu and type in mmc.exe. Alternatively you could also use the Windows key + R shortcut to open the run prompt, in this prompt you can type mmc to achieve the same results:
3. Once the MMC window is open, go to file -> Add/Remove Snap-in...
4. We can now add the Active Directory Users and Computers snap-in to our view.
5. Now that we added the snap-in to our view, we can start using it to enumerate Active Directory, for example taking a peek at the IT Organizational Unit.
Go ahead and browse through some of the units, maybe you can find some interesting descriptions...

Attention
During a real life engagement, chances are slim that you will be able to use the GUI component of the RSAT toolkit, nevertheless it is still a useful piece of software to keep in the back of your mind.
Using RSAT for Computer Enumeration
Computer enumeration in RSAT is not much different than user enumeration in RSAT is, as a reminder:
6. To launch RSAT, go to the windows button on the left hand side to open the search menu and type in mmc.exe.
Alternatively you could also use the Windows key + R shortcut to open the run prompt, in this prompt you can type mmc to achieve the same results:
7. Once the MMC window is open, go to file -> Add/Remove Snap-in...
8. We can now add the Active Directory Users and Computers snap-in to our view.
Now that we added the snap-in to our view, we can start using it to enumerate Active Directory.
Using RSAT for Password Policy Enumeration
9. This is a nice time to explore a little bit, try to identify the password policy using the mmc snap-in manager. As a red team operator, you will on occassions be forced to use tooling you are not very familiar with and will have to think outside the box. If you need hints, feel free to use them.
Hint 1
The answer cannot be found in a snap-in that we have already used so far, take a look at other available snap-ins...
Hint 2
The snap-in you are looking for will allow you to view LDAP queries and is something we have so far done using PowerShell ...
Answer
In order to figure out the password policy from mmc, we will need to utilize the ADSI Edit snap-in. Once we have this snap-in opened, we can view properties of AD objects. The object we would like to inspect is the default naming context. In the properties window, we will find the information we are looking for: lockoutwindow, password length, treshold, ...
Using RSAT for Fine-Grained Password Policy Enumeration
10. To enumerate fine-grained password policies in RSAT, we will need the ADSI Edit snap in once again:
Using RSAT for LAPS Enumeration
11. We can use the GPO Management snap in to show us a visual representation of all GPOs that are in use hoping to find any reference to LAPS deployment. Keep in mind that a large organization likely has a lot of GPOs applied to their environment and it will not always be very clear which GPOs will be worth investigating manually. For this reason, RSAT might not be your best option this time.
12. We can also use the ADSI Edit snap-in to inspect the ms-Mcs-AdmPwdExpirationTime property, however, much like the aformentioned method, a large environment will have hundreds or even thousands of computer objects. Querying these by hand is very time consuming and not really worth the time investment considering there are several automation methods available.
Using RSAT for gMSA Enumeration
13. Any group managed service account will be placed in the Managed Service Accounts container, which makes them easy to query:
Using RSAT for DNS enumeration
14. With RSAT, we can use the DNS snap in to view the DNS records of the domain:
Attention
Only domain administrators are able to enumerate DNS using this method. The screenshot below serves as an illustration of what this looks like. You will NOT be able to reproduce this as the student user!
AD Module
Using the AD Module for User Enumeration
The next enumeration method we are going to use will take advantage of the Microsoft signed PowerShell module. An obvious advantage of this method is that it has legitimate use cases and is backed by Microsoft. A downside of this method is that it uses PowerShell and therefore generates quite a bit of logs, be aware of this when you decide to utilize this method for enumeration on engagements.
For lab facilitation purposes, we went ahead and already pre-installed the AD module for you (it comes bundled with RSAT). In case you are in a real operation and want to utilize this technique you could either use a C2 framework with the capablitiy to consume PowerShell scripts or use the GitHub repository of Nikhil Mittal to reflectively load the required dependencies in memory without leaving obvious artifacts on disk.
15. Let's open up a PowerShell prompt and use the following commandlet to enumerate all AD users:
Get-AdUser -Filter *
16. If you want, you could also introduce object filtering in your PowerShell commands. For example list all object properties using the -Properties * flag. In case you want a refresher on PowerShell filters, a good resource is the following URL: https://www.itprotoday.com/powershell/powershell-basics-filtering-objects
For example, list only users from the IT OU:
Get-ADUser -SearchBase "OU=IT,DC=Draconem,DC=corp" -Filter *
17. Another nice option, return only the users that have a description
Get-ADUser -Filter "Description -like '*'" -Properties Description | select name,Description
Feel free to experiment with various filters and property selectors.
Using the AD Module for Computer Enumeration
18. Much like we did when enumerating users, we can utilize the Microsoft signed PowerShell AD Module to enumerate computers. Let's open up a PowerShell prompt and use the following commandlet to enumerate all Computers in the draconem.io domain:
Get-AdComputer -Filter *
Using the AD Module for Domain Trust Enumeration
19. We can use the AD Module to verify any existings trusts accross domains. Let's open up a PowerShell prompt and use the following commandlet to enumerate all trusts in the draconem.io domain:
Get-ADTrust -Filter * | select name, Direction
Using the AD Module for Password Policy Enumeration
20. We can use the Microsoft signed Active Directory module to enumerate the password policy as follows:
Get-ADDefaultDomainPasswordPolicy
Using the AD Module for Fine-Grained Password Policy Enumeration
21. Enumerating fine-grained password policies with the Active Directory module is very straightforward (launch PowerShell with Administrative privilleges):
Get-ADFineGrainedPasswordPolicy -Filter *
Using the AD Module for LAPS Enumeration
22. We can leverage the AD Module as well to enumerate all computers with a value in the ms-Mcs-AdmPwdExpirationTime property:
Get-ADComputer -Filter * -Properties * | Where-Object { $_.'ms-Mcs-admpwdexpirationtime' -ne $null } | select name
Using the AD Module for gMSA Enumeration
23. The AD Module is one of the best ways to enumerate these types of accounts as the commandlet also reveals who can retrieve the password:
Get-ADServiceAccount -Filter * -Properties * | select name, PrincipalsAllowedToRetrieveManagedPassword
Using the AD Module for DNS enumeration
24. Using the AD Module, we can use the IPv4Address property of the computer object that is returned when invoking the Get-ADComputer cmdlet.
#forward lookup
Get-ADComputer -filter * -Properties * | select name,ipv4address
#reverse lookup
Get-ADComputer -Properties IPv4Address -Filter * | where IPv4Address -eq 'SOME IP ADDRESS' | select name
Note
If you want a fun read on why we have to do a double pipe for the reverse lookup:
https://www.reddit.com/r/PowerShell/comments/4bbzbo/getadcomputer_returns_null_when_filtering_by/
Thanks Microsoft! :)
Powerview & Sharpview
Using PowerView & SharpView for User Enumeration
It should come as no surprise that PowerView and SharpView syntax are very similar, as SharpView is a plain C# port of the popular PowerView project.
Attention
Since SharpView is a C# port, we cannot utilize the PowerShell built-in filtering like we can with PowerView, not that big of a deal, but we need to keep it in the back of our heads.
25. Enumerating users with PowerView is very similar as using the ADModule:
#Import the PowerView module, this is typically done in memory using (Iex -iwr(<url>)), but since this is a lab, we just import from disk
cd C:\Tools
. .\Powerview-Modded.ps1
#use the Get-DomainUser PowerView method to enumerate domain users
Get-DomainUser
Using PowerView & SharpView for Computer Enumeration
26. SharpView and PowerView use the same syntax, the only caveat is that SharpView does not have the PowerShell built-in filtering. The syntax to enumerate domain computers is as follows:
Get-DomainComputer | select Dnshostname
Using PowerView & SharpView for Domain Trust Enumeration
27. SharpView and PowerView use the same syntax, the only caveat is that SharpView does not have the PowerShell built-in filtering.
The syntax to enumerate domain computers is as follows:
Get-DomainTrust
Using PowerView & SharpView for Password Policy Enumeration
28. We can also use PowerView or SharpView to achieve this task, in fact this will also give us the kerberos policy which could increase our opsec when we start forging tickets:
Get-DomainPolicy
Using PowerView & SharpView for Fine-Grained Password Policy Enumeration
29. PowerView (and SharpView) do not have built-in functionality of enumerating fine-grained password policies.
This will be a nice red team exercise. Using all the knowledge you have gained so far about enumerating fine-grained password policies, could you create a script to do the enumeration for you? You can base your scripting on the following source: https://github.com/leoloobeek/LAPSToolkit/blob/master/LAPSToolkit.ps1#L1924
Solution
We can expand LAPSToolkit with the following function:
function Convert-LDAPProperty {
<#
.SYNOPSIS
Helper that converts specific LDAP property result fields.
Used by several of the Get-Net* function.
.PARAMETER Properties
Properties object to extract out LDAP fields for display.
#>
param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[ValidateNotNullOrEmpty()]
$Properties
)
$ObjectProperties = @{}
$Properties.PropertyNames | ForEach-Object {
if (($_ -eq "objectsid") -or ($_ -eq "sidhistory")) {
# convert the SID to a string
$ObjectProperties[$_] = (New-Object System.Security.Principal.SecurityIdentifier($Properties[$_][0],0)).Value
}
elseif($_ -eq "objectguid") {
# convert the GUID to a string
$ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid
}
elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") -or ($_ -eq "lastlogoff") -or ($_ -eq "badPasswordTime") ) {
# convert timestamps
if ($Properties[$_][0] -is [System.MarshalByRefObject]) {
# if we have a System.__ComObject
$Temp = $Properties[$_][0]
[Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
[Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
$ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low)))
}
else {
$ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0])))
}
}
elseif($Properties[$_][0] -is [System.MarshalByRefObject]) {
# try to convert misc com objects
$Prop = $Properties[$_]
try {
$Temp = $Prop[$_][0]
Write-Verbose $_
[Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
[Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
$ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low)
}
catch {
$ObjectProperties[$_] = $Prop[$_]
}
}
elseif($Properties[$_].count -eq 1) {
$ObjectProperties[$_] = $Properties[$_][0]
}
else {
$ObjectProperties[$_] = $Properties[$_]
}
}
New-Object -TypeName PSObject -Property $ObjectProperties
}
filter Get-DomainSearcher {
<#
.SYNOPSIS
Helper used by various functions that takes an ADSpath and
domain specifier and builds the correct ADSI searcher object.
.PARAMETER Domain
The domain to use for the query, defaults to the current domain.
.PARAMETER DomainController
Domain controller to reflect LDAP queries through.
.PARAMETER ADSpath
The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local"
Useful for OU queries.
.PARAMETER ADSprefix
Prefix to set for the searcher (like "CN=Sites,CN=Configuration")
.PARAMETER PageSize
The PageSize to set for the LDAP searcher object.
.PARAMETER Credential
A [Management.Automation.PSCredential] object of alternate credentials
for connection to the target domain.
.EXAMPLE
PS C:\> Get-DomainSearcher -Domain testlab.local
.EXAMPLE
PS C:\> Get-DomainSearcher -Domain testlab.local -DomainController SECONDARY.dev.testlab.local
#>
param(
[Parameter(ValueFromPipeline=$True)]
[String]
$Domain,
[String]
$DomainController,
[String]
$ADSpath,
[String]
$ADSprefix,
[ValidateRange(1,10000)]
[Int]
$PageSize = 200,
[Management.Automation.PSCredential]
$Credential
)
if(!$Credential) {
if(!$Domain){
$Domain = (Get-NetDomain).name
}
elseif(!$DomainController) {
try {
# if there's no -DomainController specified, try to pull the primary DC
# to reflect queries through
$DomainController = ((Get-NetDomain).PdcRoleOwner).Name
}
catch {
throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
}
}
}
elseif (!$DomainController) {
try {
$DomainController = ((Get-NetDomain -Credential $Credential).PdcRoleOwner).Name
}
catch {
throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
}
if(!$DomainController) {
throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
}
}
$SearchString = "LDAP://"
if($DomainController) {
$SearchString += $DomainController
if($Domain){
$SearchString += "/"
}
}
if($ADSprefix) {
$SearchString += $ADSprefix + ","
}
if($ADSpath) {
if($ADSpath -like "GC://*") {
# if we're searching the global catalog
$DN = $AdsPath
$SearchString = ""
}
else {
if($ADSpath -like "LDAP://*") {
if($ADSpath -match "LDAP://.+/.+") {
$SearchString = ""
}
else {
$ADSpath = $ADSpath.Substring(7)
}
}
$DN = $ADSpath
}
}
else {
if($Domain -and ($Domain.Trim() -ne "")) {
$DN = "DC=$($Domain.Replace('.', ',DC='))"
}
}
$SearchString += $DN
Write-Verbose "Get-DomainSearcher search string: $SearchString"
if($Credential) {
Write-Verbose "Using alternate credentials for LDAP connection"
$DomainObject = New-Object DirectoryServices.DirectoryEntry($SearchString, $Credential.UserName, $Credential.GetNetworkCredential().Password)
$Searcher = New-Object System.DirectoryServices.DirectorySearcher($DomainObject)
}
else {
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
}
$Searcher.PageSize = $PageSize
$Searcher
}
filter Get-NetDomain {
<#
.SYNOPSIS
Returns a given domain object.
.PARAMETER Domain
The domain name to query for, defaults to the current domain.
.PARAMETER Credential
A [Management.Automation.PSCredential] object of alternate credentials
for connection to the target domain.
.EXAMPLE
PS C:\> Get-NetDomain -Domain testlab.local
.EXAMPLE
PS C:\> "testlab.local" | Get-NetDomain
.LINK
http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG
#>
param(
[Parameter(ValueFromPipeline=$True)]
[String]
$Domain,
[Management.Automation.PSCredential]
$Credential
)
if($Credential) {
Write-Verbose "Using alternate credentials for Get-NetDomain"
if(!$Domain) {
# if no domain is supplied, extract the logon domain from the PSCredential passed
$Domain = $Credential.GetNetworkCredential().Domain
Write-Verbose "Extracted domain '$Domain' from -Credential"
}
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain, $Credential.UserName, $Credential.GetNetworkCredential().Password)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch {
Write-Warning "The specified domain does '$Domain' not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid."
$Null
}
}
elseif($Domain) {
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch {
Write-Warning "The specified domain '$Domain' does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else {
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
function Get-FineGrainedPasswordPolicies {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$True)]
[String]
$PolicyName = '*',
[String]
$Domain,
[String]
$DomainController,
[String]
$ADSpath,
[Switch]
$FullData,
[ValidateRange(1,10000)]
[Int]
$PageSize = 200,
[Management.Automation.PSCredential]
$Credential
)
begin {
$FineGrainedSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $ADSpath -PageSize $PageSize
}
process {
if ($FineGrainedSearcher) {
$FineGrainedSearcher.filter="(&(ObjectClass=msDS-PasswordSettings)(name=$PolicyName))"
}
try {
$FineGrainedSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
if ($FullData) {
# convert/process the LDAP fields for each result
Convert-LDAPProperty -Properties $_.Properties
}
else {
# otherwise just returning the ADS paths of the OUs
$_.properties.adspath
}
}
}
catch {
Write-Warning $_
}
}
}
Using PowerView & SharpView for LAPS Enumeration
30. PowerView (and SharpView) do not have LAPS enumeration by default, but behaves very similar to the AD Module when applying filtering:
Get-DomainComputer -Properties * | Where-Object { $_.'ms-Mcs-admpwdexpirationtime' -ne $null } | select name
Using PowerView & SharpView for gMSA Enumeration
31. Much like fine-grained password policies, PowerView does not have built-in enumeration for group managed service accounts.
Can you extend LAPSToolKit like we did for fine-graind password policies, but this time for group managed service accounts?
Solution
We can expand LAPSToolkit with the following function:
function Get-NetGmsa {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$True)]
[String]
$gmsaName = '*',
[String]
$Domain,
[String]
$DomainController,
[String]
$ADSpath,
[Switch]
$FullData,
[ValidateRange(1,10000)]
[Int]
$PageSize = 200,
[Management.Automation.PSCredential]
$Credential
)
begin {
$GMSASearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $ADSpath -PageSize $PageSize
}
process {
if ($GMSASearcher) {
$GMSASearcher.filter="(&(ObjectClass=msDS-GroupManagedServiceAccount)(name=$gmsaName))"
}
try {
$GMSASearcher.FindAll() | Where-Object {$_} | ForEach-Object {
if ($FullData) {
# convert/process the LDAP fields for each result
Convert-LDAPProperty -Properties $_.Properties
}
else {
# otherwise just returning the ADS paths of the OUs
$_.properties.adspath
}
}
}
catch {
Write-Warning $_
}
}
}
BONUS - ADSI
Using ADSI for User Enumeration
As you might have already seen during the lecture, this method is the most prefered method of seasoned red teamers.
It will depend on your tooling and tradecraft, but if you are using a command-and-control framework that has built-in functionality to handle LDAP filters, this type of searching will give you full control over your results and will be very stealthy.
Unfortunately, when executing these commands in a C2 that does not have this functionality, the same IoCs apply as any other PowerShell based command. Neverthless learning how to use LDAP syntax is a very nice to have skill as a red team operator.
32. For example, get the last entry in the domain admin group:
([adsisearcher]'(memberof=cn=Domain Admins,cn=Users,dc=draconem,dc=corp)').FindAll().GetDirectoryEntry() | Select-Object -Last 1 -Property sAMAccountName
33. Or simply get all the users in the environment:
([adsisearcher]'(objectclass=user)').FindAll().GetDirectoryEntry() | Select-Object -Property sAMAccountName
Using ADSI for Computer Enumeration
34. In case you are feeling up for some LDAP querying by hand, we can also use ADSI. Let's open up a PowerShell prompt (or use the same one from before) and enumerate the computers as follows:
([adsisearcher]'(ObjectCategory=Computer)').FindAll().GetDirectoryEntry() | Select-Object -Property samaccountname
Using ADSI for Domain Trust Enumeration
35. In case you are feeling up for some LDAP querying by hand, we can also use ADSI.
Let's open up a PowerShell prompt (or use the same one from before) and enumerate the computers as follows:
([adsisearcher]'(objectClass=trustedDomain)').FindAll().GetDirectoryEntry() | select name,trustdirection
With ADSI the trustdirection is a numeric value, which can be interpreted as follows:
- 1: Inbound
- 2: Outbound
- 3: Bi-directional
Using ADSI for Password Policy Enumeration
Using ADSI for default password policy configuration is a bit more complex, as the domain policy is set through a GPO. ADSI in itself is not able to simply read the GPO data, so retrieving the policy is a two-step process:
36. First, we will have to query the groupPolicyContainer object class in LDAP to get the filepath to the GPOs:
([adsisearcher]'(objectClass=groupPolicyContainer)').FindAll().GetDirectoryEntry()
\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf file for all GPO objects until we find the right one.
This is rather tedious, so ADSI is not the most recommended way to tackle this problem, although not impossible.
Attention
The GUID of the default domain policy will always be the same ({31B2F340-016D-11D2-945F-00C04FB984F9})
The same is also true for the default domain controller policy ({{6AC1786C-016F-11D2-945F-00C04fB984F9}})
type "\\draconem.corp\sysvol\draconem.corp\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf"
37. We could also take a much more straight-forward approach using adsi to make a LDAP connection to the base object and then list the base object properties
$base=[adsi]'LDAP://DC=draconem,DC=corp'
$base | Select-Object -Property lockoutThreshold,minPwdLength
Using ADSI for Fine-Grained Password Policy Enumeration
38. ADSI can of course also be used to achieve the same result:
([adsisearcher]'(ObjectClass=msDS-PasswordSettings)').FindAll().getDirectoryEntry() | Select-Object -Property name,msDS-PSOAppliesTo
Using ADSI for LAPS Enumeration
39. Through the power of LDAP queries we can also enumerate computer objects with LAPS enabled. No need for dependencies! :)
([adsisearcher]"(&(objectCategory=computer)(ms-MCS-admpwdexpirationtime=*))").findAll().GetdirectoryEntry() | select name
Using ADSI for gMSA Enumeration
40.
([adsisearcher]'(ObjectClass=msDS-GroupManagedServiceAccount)').FindAll().getDirectoryEntry()
BONUS - ADFind
Using ADFind for User Enumeration
A crowd favorite with threat actors is a little tool called ADFind it is free to download and written in C++. Under the hood, ADFind is using a bunch of Windows API calls to enumerate Active Directory. Let's utilize ADFind to enumerate users, you will see that the majority of tools follow familiar (LDAP) syntax. ADFind is a complex program and has very detailed documentation, a nice cheat sheet can also be found here: https://social.technet.microsoft.com/wiki/contents/articles/7535.adfind-command-examples.aspx
41. To find all users:
.\AdFind.exe -f objectclass=user sAMAccountName Description
42. To list all the users in the staff OU:
.\AdFind -f "sAMAccountName=Staff" member -list
Using ADFind for Computer Enumeration
43. Adfind is following LDAP syntax, we can enumerate computer objects as follows:
.\AdFind.exe -f objectclass=computer samaccountname
Using ADFind for Domain Trust Enumeration
44. Adfind is following LDAP syntax, we can enumerate computer objects as follows:
.\AdFind.exe -f objectclass=trusteddomain name trustdirection
Much like with ADSI,the trustdirection is a numeric value, which can be interpreted as follows:
- 1: Inbound
- 2: Outbound
- 3: Bi-directional
Using ADFind for Password Policy Enumeration
45.
.\AdFind.exe -default -s base lockoutduration lockoutthreshold lockoutobservationwindow maxpwdage minpwdage minpwdlength
Using ADFind for Fine-Grained Password Policy Enumeration
46. We can use ADFind in a similar fashion as we use ADSI to enumerate the fine-grained password policies:
.\AdFind.exe -f ObjectClass=msDS-PasswordSettings
Using ADFind for LAPS Enumeration
47. ADFind has the capabilities of parsing LDAP queries much like ADSI does.
As can be noticed, it is very worthwile to learn LDAP syntax for enumeration purposes as every single enumeration tool relies on LDAP queries one way or another:
.\AdFind.exe -f "(&(objectclass=computer)(ms-Mcs-admpwdexpirationtime=*))" samaccountname
Using ADFind for gMSA Enumeration
48. Using ADFind to enumerate gmsa:
Note
the -sddl -resolvesids flag in adfind is used to force adfind to parse the security descriptor and translate the security identifiers to their respective human-readable names.
.\AdFind.exe -sddl -resolvesids -f '(ObjectClass=msDS-GroupManagedServiceAccount)' samaccountname msDS-GroupMSAMembership
BONUS - ADExplorer
Using ADExplorer for User Enumeration
ADExplorer is a tool that is part of the sysinternals suite. This toolkit is developed by Microsoft to facilitate the life of administrators (and redteamers). Using ADExplorer it is possible to create a snapshot of the environment which can then be parsed offline. This is a very nice reconnaisance tactic as it limits the amount of queries being sent into the live environment. An added benefit of sysinternals tooling is that it gets hosted online and is reachable over SMB. This is rather interesting as this allows you to execute the tool without actually dropping it to disk, of course this will create an outbound SMB connection which is an IOC. ADExplorer has a GUI which allows you to view the environment or load a snapshot.
49. For the sake of illustration, we are first going to create a snapshot using the cli and then use our snapshot in ADExplorer.
.\ADExplorer.exe -snapshot "dc01.draconem.corp" "snapshot.dat"
50. Once you got the snapshot taken, we can use ADExplorer's GUI to parse the snapshot. Launch ADExplorer from the C:\Tools directory and load the snapshot you created which is located in C:\tools\snapshot.dat
51. Which we can use to enumerate the Active Directory:
Using ADExplorer for Computer Enumeration
52. Since ADExplorer has GUI capabilities, enumerating the computers is rather trivial:
Using ADExplorer for Domain Trust Enumeration
53. Domain trusts can be found in the system container in ADExplorer:
54. You could also use ADExplorer's search function that supports LDAP like querying:
Using ADExplorer for Password Policy Enumeration
55. Much like the RSAT approach, ADExplorer works by displaying the properties of the default naming context:
Now that we know the "basic" password policy, it makes sense that we take a look to try and identify if there is any fine-grained password policy enabled in the environment.
Using ADExplorer for Fine-Grained Password Policy Enumeration
56. Be sure to launch ADExplorer as an administrator, or the password-settings container will appear empty:
Note
As shown in the lecture earlier, fine-grained password policies are not enumeratable by normal users by default. However, we can still enumerate domain groups. If a group has a fine-grained password policy applied to it the msDS-PSOApplied property will point to the policy name, unfortunately, other than the name of the policy we will not be able to reveal further details. If you have some time to kill, feel free to try and figure out which AD objects have a fine-grained policy attached to themselves from an unprivileged perspective.
Using ADExplorer for LAPS Enumeration
57. Much like RSAT, ADExplorer is a GUI based application. As already stated, in large organizations it is unfeasible to go over all computer objects by hand to go and hunt for LAPS enabled computers.
Using ADExplorer for gMSA Enumeration
58. Using ADExplorer to enumerate gmsa is trivial and very similar to using RSAT:
Note
You can use the ConvertFrom-SddlString to translate security descriptors into a more readable format:

Let's now take a look at how we can leverage LDAP to be a stealthier replacement than nslookup
BONUS - Using LAPSToolkit for LAPS Enumeration
59. LAPSToolkit by LeoLoobeek was specifically built to automate the process for us. This is by far the easiest method of enumerating LAPS.
Attention
Because we created a custom script to enumerate fine grained password policies, we have to close and reopen our PowerShell session. The fine grained password policies script sources a lot of code from the LAPSToolkit, which makes the Toolkit misbehave because of functions that have been defined multiple times. Opening a new PowerShell window unloads previously loaded scripts, fixing this problem.
#import LAPSToolkit (from within the c:\Tools directory)
. .\LapsToolkit.ps1
#enumerate computers with LAPS enabled
Get-LAPSComputers
#enumerate who is allowed to access LAPS password (no output means default configuration (domain admins only))
Find-AdmPwdExtendedRights
BONUS - Using SharpAdidnsdump for DNS enumeration
60.
.\SharpAdidnsdump.exe <DCIP>
Note
Unfortunately, it is not feasible to perform this kind of enumeration using ADFind, ADExplorer or PowerView/SharpView. This is because the IPV4address property is not stored in an AD object and needs to get parsed in order to be interpreted.
BONUS - Enumeration over C2
We could probably spend the entire day in the lab performing enumeration tasks, if you've got some time left feel free to use your command-and-control implant in combination with the tools we have just used to get a feel of how they behave when using a C2. This will help you out tremendously during the day 6 CTF!
P.S: Did you spot any honeypot objects in the AD? If not, you might want to take a step back and enumerate some more ;-).
Conclusion
In this lab, you have learned how to enumerate an Active Directory environment with a multitude of tools. This lab should act as a nice reference point whenever you need to enumerate AD in various situations ranging from loud to stealth.





















































