LDAP

Lightweight Directory Access Protocol | AD | User information | User accounts

Lightweight Directory Access Protocol (LDAP) is an integral part of Active Directory (AD). Latest version is RCF 4511. LDAP is open source and used for authentication against directory services such as Active Directory.

LDAP is the language that applications use to communicate with services like Active Directory and with other server that provide directory services as well. LDAP lets systems in the network talk with the AD.

AD LDAP Authentication

There are 2 types of LDAP authentication:

  1. Simple authentication including anonymous authentication, unauthenticated authentication, and username/password authentication. It will create a BIND request to LDAP server.

  2. SASL authentication. SASL using authentication services like Kerberos to bind to the LDAP server. The LDAP protocol sends LDAP message which starts challenge and response messages.

LDAP authentication messages are sent in cleartext.

LDAP queries

Communicating with directory services using LDAP is done with queries.

Query
Result

(objectCategory=computer)

find all workstations in a network

((&(objectCategory=person)(objectClass=user))

searches for all users

(objectClass=group)

searches for all groups

More queries: computers, users, groups.

Example queries

Find disabled users

 Get-ADObject -LDAPFilter '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))' -Properties * | select samaccountname,useraccountcontrol

Find out how many users, computers and groups

PS C:\Users\mczen> (Get-ADUser -Filter *).Count
877
PS C:\Users\mczen> (Get-ADComputer -Filter *).Count
7
PS C:\Users\mczen> (Get-ADGroup -Filter *).Count
90

# Or specify a group
(Get-ADGroupMember -Identity "IT").Count

Powershell Filters

Filters in PowerShell allows us to get better output and retreive data we are looking for. It can be used to narrow down specific data in large result.

This would filter out all Microsoft software making the list of search results a lot smaller.

PS C:\zen> get-ciminstance win32_product -Filter "NOT Vendor like '%Microsoft%'" | fl

IdentifyingNumber : {748D3A12-9B82-4B08-A0FF-CFDE83612E87}
Name              : VMware Tools
Vendor            : VMware, Inc.
Version           : 10.3.2.9925305
Caption           : VMware Tools
Operators
Meaning
-eq	        Equal to
-le	        Less than or equal to
-ge	        Greater than or equal to
-ne	        Not equal to
-lt	        Less than
-gt	        Greater than
-approx	        Approximately equal to
-bor	        Bitwise OR
-band	        Bitwise AND
-recursivematch	Recursive match
-like	        Like
-notlike	Not like
-and	        Boolean AND
-or	        Boolean OR
-not	        Boolean NOT

Find users with DoesNotRequirePreAuth who's accounts can be ASREPRoasted.

# Administrative groups
Get-ADUser -Filter {adminCount -eq '1' -and DoesNotRequirePreAuth -eq 'True'}

# All users
Get-ADUser -Filter {DoesNotRequirePreAuth -eq 'True'}

# Get group members
Get-ADGroupMember -Identity "Protected Users"

Get info about a host

# Get basic information
Get-ADComputer WS01

# Get detailed information, including operating system, last logon time, etc.
Get-ADComputer WS01 -Properties *

# Get specific properties
Get-ADComputer WS01 -Properties OperatingSystem, LastLogonDate, Description

LDAP Search Filters

The -LDAPFilter enables us to use LDAP search filters which syntax is defined here: https://datatracker.ietf.org/doc/html/rfc4515

LDAP filters must have 1 or more criteria, when using more we use AND or OR to concatenate.

Operator
Function

&

and

|

or

!

not

Search criteria

When using an LDAP search filter we need to specifiy rules, like (displayName=mczen).

Critera
Rule
Example

Equal to

(attribute=123)

(&(objectclass=user)(displayName=Smith)

Not equal to

(!(attribute=123))

!objectClass=group)

Present

(attribute=*)

(department=*)

More attributes https://docs.bmc.com/docs/fpsc121/ldap-attributes-and-associated-fields-495323340.html

Object Identifiers (OIDs)

Object Identifiers (OIDs) are unique identifiers used to name objects. We can use machting rule OIDs with LDAP filters, found here. This query will return all administratively disabled user accounts, or ACCOUNTDISABLE (2) with matching rule: 1.2.840.113556.1.4.803

Get-ADUser -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=2)' | select name
  • 1.2.840.113556.1.4.803 is the Object Identifier (OID) for a bitwise AND operation.

  • :=2 checks if account is disbabled

Find all groups

Get-ADGroup -LDAPFilter '(member:1.2.840.113556.1.4.1941:=CN=Harry Jones,OU=Network Ops,OU=IT,OU=Employees,DC=INLANEFREIGHT,DC=LOCAL)' | select Name
  • 1.2.840.113556.1.4.1941 This OID find all groups that the user is a member off

  • :=: Specifies the equality match.

LDAP Queriy - Description Field

Get-ADUser -Properties * -LDAPFilter '(&(objectCategory=user)(description=*))' | select samaccountname,description
  • objectCategory=user: Ensures that only user objects are retrieved.

  • description=*: Ensures that only users with a non-empty description field are retrieved.

LDAP Query - Find Trusted Users

This filter "(userAccountControl:1.2.840.113556.1.4.803:=524288)" can be used to find all users or computers marked as trusted for delegation, or unconstrained delegation. Trusted users can act on behalf of other users in AD.

# Get users
Get-ADUser -Properties * -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' | select Name,memberof, servicePrincipalName,TrustedForDelegation | fl

# Get computers
Get-ADComputer -Properties * -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' | select DistinguishedName,servicePrincipalName,TrustedForDelegation | fl
  • 1.2.840.113556.1.4.803 is the Object Identifier (OID) for a bitwise AND operation

  • :=524288 checks if the bit corresponding to the TRUSTED_FOR_DELEGATION

LDAP Query - Users With Blank Password

Get-AdUser -LDAPFilter '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))(adminCount=1)' -Properties * | select name,memberof | fl
  • (userAccountControl:1.2.840.113556.1.4.803:=32): Checks if the bit corresponding to the PASSWD_NOTREQD flag is set in the userAccountControl attribute. This indicates that a password is not required for the account.

Recursive Match

With RecursiveMatch we dcan find all of the groups an AD user is part of, both direct and inderect group memberships?

# Won't show nested groups
Get-ADUser -Identity harry.jones -Properties * | select memberof | ft -Wrap

# Will show all groups, including nested
 Get-ADGroup -Filter 'member -RecursiveMatch "CN=Harry Jones,OU=Network Ops,OU=IT,OU=Employees,DC=INLANEFREIGHT,DC=LOCAL"' | select name

SearchBase and SearchScope Parameters

SearchScope allows us to define how deep into the OU hierarchy we would like to search. This parameter has three levels:

Base

0

The object is specified as the SearchBase. Base scope only looks at the OU itself, not at users within.

OneLevel

1

Searches for objects in the container defined by the SearchBase but not in any sub-containers. Or 1 level deep.

SubTree

2

Entire subtree, including all levels of sub-containers and their children. Recursively all the way down the AD hierarchy.

Searchscope Base

# Count all AD users
PS C:\zen> (Get-ADUser -SearchBase "OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -Filter *).count
970

# Empty output
PS C:\zen> Get-ADUser -SearchBase "OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -SearchScope Base -Filter *
PS C:\zen>

# Search Base OU object
PS C:\zen> Get-ADObject -SearchBase "OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -SearchScope Base -Filter *

DistinguishedName                      Name      ObjectClass        ObjectGUID
-----------------                      ----      -----------        ----------
OU=Employees,DC=INLANEFREIGHT,DC=LOCAL Employees organizationalUnit 34f42767-8a2e-493f-afc6-556bdc0b1087

Searchscope OneLevel

# We get one user returned to us
PS C:\htb> Get-ADUser -SearchBase "OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -SearchScope OneLevel -Filter *

Searchscope Subtree

# Will count all objects
PS C:\zen> (Get-ADUser -SearchBase "OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -SearchScope Subtree -Filter *).count

# Or count all employees in IT
(Get-ADUser -SearchBase "OU=IT,OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -SearchScope Subtree -Filter *).count

PowerView

PowerView is a PowerShell tool for enumerationg AD's and gathering network information. It provides a set of functions to explore Active Directory, identify users, computers, and groups, and analyze their relationships. Use by Import-Module .\PowerView.ps1.

# Show useraccountcontrol attributes.
Get-DomainUser * -AdminCount | select samaccountname,useraccountcontrol

# Find user in OU writers
Get-ADUser -SearchBase "OU=Writers,OU=Employees,DC=INLANEFREIGHT,DC=LOCAL" -Filter * | Select-Object SamAccountName

DS Tools

List the SAM account names of users whose passwords are set to never expire

dsquery user "OU=Employees,DC=inlanefreight,DC=local" -name * -scope subtree -limit 0 | dsget user -samid -
pwdneverexpires | findstr /V no

Windows Management Instrumentation (WMI)

Get-WmiObject -Class win32_group -Filter "Domain='INLANEFREIGHT'" | Select Caption,Name

LDAP Anonymous Bind

LDAP anonymous binds allow unauthenticated attackers to retrieve information from the domain, this can be used to list users, groups, computers, account attributes and password policies.

A anonymous bind is a request where the username and password fields are left empty.

We can use python to interact LDAP:

Python 3.8.5 (default, Aug  2 2020, 15:09:07) 
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ldap3 import *
>>> s = Server('10.129.1.207',get_info = ALL)
>>> c =  Connection(s, '', '')
>>> c.bind()
True
>>> s.info

Ldapsearch

We can use tools suchas windapsearch and ldapsearch to enumerate a domain.

# ldapsearch
ldapsearch -H ldap://10.129.1.111 -x -b "dc=zencorp,dc=local"

# Info
python3 ldapsearch-ad.py -l 10.129.1.207 -t info

Windapsearch

# Check for bind
python3 windapsearch.py --dc-ip 10.129.1.111 -u "" --functionality

# Get domain users
python3 windapsearch.py --dc-ip 10.129.1.207 -u "" -U

# Get domain computers
python3 windapsearch.py --dc-ip 10.129.1.207 -u "" -C

# Search for OU by user
python3 windapsearch.py --dc-ip 10.129.42.188 -u "" -s "john doe"

# Show groups
python3 windapsearch.py --dc-ip 10.129.42.188 -u "" -G

# Unconstrained delegation
python3 windapsearch.py --dc-ip 10.129.42.188 -u "" -U --unconstrained-users

Credentialed Enumeration

When having domain credentials we get retrieve all kinds for information from LDAP.

python3 windapsearch.py --dc-ip 10.129.1.207 -u zencorpo\\john.doe --da

Of checking for users with unconstrained delegations.

python3 windapsearch.py --dc-ip 10.129.1.207 -d zencorp.local -u zencorp\\john.doe --unconstrained-users

Or using ldapsearch

# Check password policy
python3 ldapsearch-ad.py -l 10.129.1.207 -d zencorp -u john.doe -p pass123 -t pass-pols

# Check for Kerberoastable users
python3 ldapsearch-ad.py -l 10.129.1.207 -d zencorp -u john.doe -p pass123 -t kerberoast | grep servicePrincipalName

# Check ofr ASREPRoastable users
python3 ldapsearch-ad.py -l 10.129.1.207 -d zencorp -u john.doe -p pass123 -t asreproast

If we want to find users with smartcard_required attribute set we can use the LDAP filter (userAccountControl:1.2.840.113556.1.4.803:=262144).

python3 ldapsearch-ad.py -l 10.129.42.188 -d zencorp -u john doe -p pass123 -t search -s "(userAccountControl:1.2.840.113556.1.4.803:=262144)"
  • userAccountControl: LDAP attribute being queried

  • :1.2.840.113556.1.4.803: LDAP Matching Rule OID for bitwise matching

  • :=: bitwise AND operation

  • 262144: corresponds to the SMARTCARD_REQUIRED flag

Properties here

Last updated

Was this helpful?