+Protocol for accessing and managing directory information, widely used in enterprise environments.+
LDAP is an open-source and cross-platform protocol used for authentication against various directory services (such as AD).
AD stores user account information and security information such as passwords and facilitates sharing this information with other devices on the network. LDAP is the language that applications use to communicate with other servers that also provide directory services. In other words, LDAP is a way that systems in the network environment can “speak” to AD.
Protocol for accessing and managing directory information
Widely used in enterprise environments
Operates over TCP/IP
Directory Services:
Hierarchical organization of resources
Includes users, groups, devices, and other objects
A directory is a hierarchical data store that contains information about network resources such as users, groups, computers, printers, and other devices.
Operations:
Search: Query directory objects
Add: Insert new records
Delete: Remove existing records
Modify: Update attributes of records
Authentication:
Anonymous
Simple (clear-text)
SASL (more secure methods)
LDAP Data Model:
DIT (Directory Information Tree)
DN (Distinguished Name)
Attributes: Descriptive elements like username, email, etc.
Common Implementations:
Microsoft’s Active Directory
OpenLDAP
Novell’s eDirectory
Security Concerns:
Clear-text password vulnerabilities
LDAP injection attacks
Use LDAPS for secure connections
Penetration Testing Relevance:
Enumeration of user accounts and groups
Information gathering for privilege escalation
Note: Always perform activities like penetration testing with proper authorization.
LDAP Requests & Responses (how a session works):
Model Overview:
LDAP uses a client-server architecture.
Clients communicate with servers using LDAP messages, encoded in ASN.1 and transmitted over TCP/IP.
Supports various requests like bind, unbind, search, compare, add, delete, modify, etc.
LDAP requests & responses:
LDAP requests are messages that clients send to servers to perform operations on data stored in a directory service. An LDAP request is comprised of several components:
LDAP Requests:
Session Connection:
Clients connect via an LDAP port (commonly 389 or 636).
Request Type:
Specifies the operation (e.g., bind, search).
Request Parameters:
The client provides additional information for the request, such as the distinguished name (DN) of the entry to be accessed or modified, the scope and filter of the search query, the attributes and values to be added or changed, etc
Request ID:
Unique identifier for matching requests with responses.
Once the server receives the request, it processes it and sends back a response message that includes several components:
LDAP Responses:
Response Type:
Indicates the operation that was performed in response to the requests.
Result Code:
Indicates success or failure and the reason.
Matched DN:
Returns the DN of the closest matching entry, if applicable.
Referral:
Provides a URL to another server with potentially more relevant information (if applicable).
Response Data:
Additional data related to the response, such as attributes and values of an entry.
After receiving and processing the response, the client disconnects from the LDAP port.
+Example+:
Consider a simple example where a client wants to search for a user’s information in the directory:
Searches the directory for entries matching the criteria.
Constructs a response message with the result.
Server sends back a response:
Response type: searchResult.
Result code: success (if the entry is found) or an error code.
Referral: (not applicable in this case)
Response data: Attributes and values of “John Doe” if the entry is found.
Client processes the response:
Parses the attributes and values of “John Doe”.
Disconnects from the server.
Diagram to understand visually:
[Client] |
|---[Connect to LDAP Server on Port 389/636] |
|---[Send LDAP Request] | |
| |--[Request Type: e.g., Search] | |--[Request Parameters: DN, Scope, Filter] | |--[Request ID: Unique Identifier] |
[LDAP Server] |
|---[Process Request] | |
| |--[Perform Operation: e.g., Search Directory] |
|---[Send LDAP Response] |
|--[Response Type: e.g., SearchResult] |--[Result Code: Success or Error] |--[Matched DN: Closest Matching Entry] |--[Referral: URL to Another Server (if applicable)] |--[Response Data: Attributes and Values (if found)] |
[Client] |
|---[Process Response] |
|---[Disconnect]
LDAP AD Authentication:
LDAP is set up to authenticate credentials against AD using a “BIND” operation to set the authentication state for an LDAP session.
LDAP authentication messages are sent in cleartext by default so anyone can sniff out LDAP messages on the internal network. It is recommended to use TLS encryption or similar to safeguard this information in transit.
_
There are two types of LDAP authentication.
Simple Authentication:
Simple authentication means that a username and password create a BIND request to authenticate to the LDAP server. Simple authentication methods are as follows:
Anonymous authentication
Unauthenticated authentication
Username/password authentication.
SASL Authentication:
Security Layer (SASL) framework uses other authentication services. It can also provide further security due to the separation of authentication methods from application protocols.
SASL Authentication example:(please note there are more methods of SASL Authentication):
Kerberos
, to bind to the LDAP server and then uses this authentication service to authenticate to LDAP.
The LDAP server uses the LDAP protocol to send an LDAP message to the authorization service which initiates a series of challenge/response messages resulting in either successful or unsuccessful authentication.
OpenLDAP is an open-source implementation of the Lightweight Directory Access Protocol (LDAP).
Used for directory services to store and manage sensitive information like user credentials, network resources, and permissions.
How It Works:
Uses a hierarchical data structure (Directory Information Tree, DIT).
Supports a variety of operations like add, delete, modify, and search.
Protocols Involved:
LDAP
LDAP over SSL/TLS (LDAPS)
SASL for advanced authentication
Importance in Cybersecurity:
Used as a central repository for user credentials.
Security measures like ACLs (Access Control Lists) can be implemented.
Application in Penetration Testing:
Test for misconfigurations in ACLs.
Check for weak encryption or lack of signing in communications.
Platform-Specific Implementations:
Most often used in Unix and Linux environments.
Can be integrated with other platforms like Windows for cross-platform directory services.
Configuration:
Main configuration file is usually slapd.conf or under etc/openldap/slapd.d in newer versions.
ACLs, logging, and other settings are configurable.
Limitations:
Complexity can lead to misconfiguration.
Security features must be manually enabled and configured.
LDAP signing:
Definition:
LDAP Signing is a security feature that helps prevent man-in-the-middle attacks.
It ensures that LDAP (Lightweight Directory Access Protocol) packets are genuine and unaltered during transmission.
How It Works
The LDAP server signs all traffic sent to clients.
Clients validate the signature to confirm data integrity.
Protocols Involved:
SASL
(Simple Authentication and Security Layer) mechanisms can be used.
LDAP over SSL/TLS also can enforce packet signing.
Importance in Cybersecurity:
Prevents unauthorized modification of data during transmission.
Increases trustworthiness of LDAP communications.
Application in Penetration Testing:
Test to ensure LDAP signing is enabled.
Check for vulnerabilities that may bypass or exploit unsigned LDAP traffic.
Platform-Specific Implementations:
Microsoft AD (Active Directory) often implements this.
OpenLDAP and other directory services can also enforce LDAP signing.
Configuration:
Often set via Group Policy on Windows systems.
For Linux, configurations are generally in the LDAP configuration files.
Limitations:
Increases computational overhead.
May not encrypt data, just signs it for integrity. Use with encryption for enhanced security.
LDAP Bind Request:
A bind request consists of 3 elements:
The LDAP protocol the clients wants to use:
This is represented by an integer value.
The DN of the client/user to authentication:
For an Anonymous Bind
it would be empty. It would also typically be empty for SASL Authentication as SASL uses encoded credentials
The credentials the client/user uses to authentication:
For simple authentication this is the password for the DN specified in part 2. For Anonymous bind the string would be empty, for SASL authentication this is an encoded value.
LDAP Anonymous Bind:
LDAP anonymous binds allow us to retrieve information from the domain, such as:
A list of all users
A list of all groups
A list of all computers.
User account attributes.
The domain password policy.
Enumerate users who are susceptible to AS-REPRoasting.
Passwords stored in the description fields
Linux hosts running open-source versions of LDAP and Linux vCenter appliances are often configured to allow anonymous binds.
Filter rules are enclosed in parentheses and can be grouped by surrounding the group in parentheses and using one of the following comparison operators:
AND (&)
Syntax: (&(condition1)(condition2))
Description: Combines multiple conditions with a logical AND. All conditions must be true for a match.
OR (|)
Syntax: (|(condition1)(condition2))
Description: Combines multiple conditions with a logical OR. At least one condition must be true for a match.
NOT (!)
Syntax: (!(condition))
Description: Negates a condition. The condition must be false for a match.
Some examplesAND *and* ~ORoperations are as follows:
Searches for users who’s names start with jo or groups who’s name start with “sql”
Examples of these being paired withldapsearch:
We can pair search terms with filters to narrow down information even more.
If I am enumerating a domain and a I know there is a user I want to go after called “Nathan” I can craft the following queries to enumerate them further.
When writing an LDAP search filter, we need to specify a rule requirement for the LDAP attribute in question (i.e. “(displayName=william)”). The following rules can be used to specify our search criteria:
Operator
Meaning
Description
=
Equality Operator
Checks for exact match between attribute and value.
~=
Approximately equal to
Finds entries where the attribute is approximately equal to the given value.
>=
Greater than or equal to
Finds entries where the attribute value is greater than or equal to the given value.
<=
Less than or equal to
Finds entries where the attribute value is less than or equal to the given value.
=*
Presence Test
Checks if an attribute is present, regardless of its value.
This matching rule will find all groups that the user Nathan Barley ("CN=Nathan Barley,OU=Network Ops,OU=IT,OU=Employees,DC=SUGARAPE,DC=LOCAL") is a member of.
Description: This rule is limited to filters that apply to the DN. This is a special “extended” match operator that walks the chain of ancestry in objects all the way to the root until it finds a match.
+Notes+:
- The wildcard * is correct after the name as we want to view all information about that account.
- Sometimes we will get output like this (this usually means the account is not found in the directory):
-
- Where as this account is active and in use by the looks of it:
-
Windows:
#Ldap QueryGet-ADObject -LDAPFilter '(&(ObjectClass=user)(cn=<name*>))'# Examples Using LDAPFilterGet-ADObject -LDAPFilter '(&(objectCategory=user)(cn=carol*))'
+Note+: This will return all users called Carol, we could further narrow down our search by adding a last name:
- '(&(objectCategory=user)(cn=carol smith))'
List Users Who have Constrained Delegation Privileges:
#Ldap Query(userAccountControl:1.2.840.113556.1.4.803:=524288)
# Example Using LDAPFilterGet-DomainUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
Users with Administrative Privileges:
Linux:
#Ldap Query(&(objectClass=user)(adminCount=1))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 '(&(objectClass=user)(adminCount=1))'
Windows:
# Example Using LDAPFilterGet-ADObject -LDAPFilter '(&(objectCategory=user)(adminCount=1))'
List All administratively disabled accounts.:
Linux:
#LDAP Query(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))'
+Note+: Don’t pipe into | select samaccountname| it didn’t work for me, I think it may be due to the account being disabled, then maybe the sam account is disabled?
List User Emails:
Linux:
#LDAP Query(&(objectClass=user)(mail=*@domain.com))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 (&(objectClass=user)(mail=*@sugarape.local))
Windows:
#LDAP Query(&(objectClass=user)(mail=*@domain.com))
# Example Using LDAPFilterGet-ADObject -LDAPFilter (&(objectClass=user)(mail=*@sugarape.local))
List Group Information:
List All Groups:
Linux:
#LDAP Query(objectClass=group)# Example Using LDAPSearchldapsearch -H ldap://monteverde.MEGABANK.LOCAL -x -b "DC=MEGABANK,DC=LOCAL" -s sub "(&(objectclass=group))" | grep sAMAccountName: | cut -f2 -d" "
Windows:
#LDAP Query(&(objectCategory=group))
# Example Using LDAPFilterGet-ADObject -LDAPFilter '(&(objectCategory=group))' | select name | Measure-Object
+Note+: The example counts the number of groups too by piping into measure object.
List Group Membership of a specific user:
Linux:
#LDAP Query(&(objectClass=group)(member=CN=John Doe,CN=Users,DC=domain,DC=com))# Example Using LDAPSearchldapsearch -x -b "dc=domain,dc=com" -H ldap://10.129.95.210 '(&(objectClass=group)(member=CN=John Doe,CN=Users,DC=domain,DC=com))'
Windows:
#LDAP Query(&(objectClass=group)(member=CN=John Doe,CN=Users,DC=domain,DC=com)
# Example Using LDAPFilterGet-ADObject -LDAPFilter '(&(objectClass=group)(member=CN=John Doe,CN=Users,DC=domain,DC=com)'
+Note+: Can’t seem to get to work just yet
List Members of a Specific Group:
Linux:
#LDAP Query(&(objectCategory=Person)(sAMAccountName=*)(memberOf=CN=<GroupName>,OU=Groups,DC=[DCNAME],DC=[DCNAME]))# Example Using LDAPSearchldapsearch -H ldap://monteverde.MEGABANK.LOCAL -x -b "DC=MEGABANK,DC=LOCAL" -s sub "(&(objectCategory=Person)(sAMAccountName=*)(memberOf=CN=Helpdesk,OU=Groups,DC=MEGABANK,DC=LOCAL))"
Windows:
#LDAP Query(&(objectCategory=Person)(sAMAccountName=*)(memberOf=CN=<GroupName>,OU=Groups,DC=[DCNAME],DC=[DCNAME]))
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(&(objectCategory=Person)(sAMAccountName=*)(memberOf=CN=Helpdesk,OU=Groups,DC=MEGABANK,DC=LOCAL))"
+Notes+:
Signifies no-one is in this group:
Users are part of this group.
List Computers:
Linux:
#LDAP Query(objectClass=computer)# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 '(objectClass=computer)'
Windows:
#LDAP Query(objectClass=computer)
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(objectClass=computer)"
List OU information:
List All OU’s:
Linux:
#LDAP Query(objectClass=OrganizationalUnit)# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 '(objectClass=OrganizationalUnit)'
Windows:
#LDAP Query(objectClass=OrganizationalUnit)
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(objectClass=OrganizationalUnit)"
List Specific OU Information:
Linux:
#LDAP Query(ou=[OUName])# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 '(ou=Accounting)'
Windows:
#LDAP Query(ou=[OUName])
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(ou=Accounting)"
List Account Information:
List Active Accounts:
Linux:
#LDAP Query(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"ldapsearch -h 172.16.5.5 -x -b "DC=SUGARAPE,DC=LOCAL" -s sub "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" | grep "sugarape.local"
+Note+: Can pipe into grep as well once an email is discovered to pipe out valid usernames:
Windows:
#LDAP Query(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
Account Expires in Specific Time Frame:
Linux:
#LDAP Query(&(objectClass=user)(accountExpires>=131342487000000000)(accountExpires<=131395327000000000))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 "(&(objectClass=user)(accountExpires>=131342487000000000)(accountExpires<=131395327000000000))"
Windows:
#LDAP Query(&(objectClass=user)(accountExpires>=131342487000000000)(accountExpires<=131395327000000000))
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(&(objectClass=user)(accountExpires>=131342487000000000)(accountExpires<=131395327000000000))"
List Disabled Accounts:
Linux:
#LDAP Query(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))"
Windows:
#LDAP Query(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))"
Linux System Support:
Linux:
#LDAP Query(&(objectClass=device)(osName=Linux*))# Example Using LDAPSearchldapsearch -x -b "dc=sugarape,dc=local" -H ldap://10.129.95.210 "(&(objectClass=device)(osName=Linux*))"
Windows:
#LDAP Query(&(objectClass=device)(osName=Linux*))
# Example Using LDAPFilterGet-ADObject -LDAPFilter "(&(objectClass=device)(osName=Linux*))"
SearchBase and SearchScope Parameters:
The SearchBase parameter:
This parameter specifies an Active Directory path to search under and allows us to begin searching for a user account in a specific OU:
It accepts an OU’s AD Distinguished Name (DN)
“OU=Employees,DC=CONTOSO,DC=LOCAL”.
The SearchScope parameter:
“SearchScope” allows us to define how deep into the OU hierarchy we would like to search.
There are three levels of depth we can search when using this parameter:
SearchScope Depth:
Depth: 0
Name: Base
Description: The object is specified as the SearchBase. For example, if we ask for all users in an OU defining a base scope, we get no results. If we specify a user or use Get-ADObject we get just that user or object returned.
Depth: 1
Name: OneLevel
Description: Searches for objects in the container defined by the SearchBase but not in any sub-containers.
Depth: 2
Name: SubTree
Description: Searches for objects contained by the SearchBase and all child containers, including their children, recursively all the way down the AD hierarchy.
+Example Picture and searches+:
In the above example with the SearchBase set to the AD Operational Unit (OU) OU=Employees,DC=SUGARAPE,DC=LOCAL we can set the scope to the following. We are going to be querying for user, by passing these parameters to Get-AdUser:
Base/0
Would attempt to query the OU object (Employees) itself.
Result: We would get 0 hits as there are no users directly in the base.
OneLevel/1
Would search within the Employees OU only.
Result: We would get the user Amelia Matthews returned as she is sitting nested within it and the first/oneLevel
SubTree/2
Queries the Employees OU and all of the sub-OUs underneath it, such as Accounting, Contractors, etc. OUs under those OUs (child containers).
Results: We would get all users nested within the sub-ou’s, in this instance 970 users
Passing SearchScope Depth as an argument:
We can use name or number & they are both interpreted the same:
LDAPire is my own custom-built Python-based tool for Active Directory reconnaissance and enumeration. It’s designed to streamline the process of gathering essential AD information during penetration tests or security assessments.
Key features:
Adaptive connection attempts (SSL and non-SSL)
Flexible authentication (anonymous and authenticated)
Comprehensive user and group enumeration
Multiple output files for quick reference and detailed analysis
<SNIP>
PORT STATE SERVICE VERSION
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: MEGABANK.LOCAL, Site: Default-First-Site-Name)| ldap-rootdse:
| LDAP Results
| <ROOT>
| domainFunctionality: 7| forestFunctionality: 7| domainControllerFunctionality: 7| rootDomainNamingContext: DC=MEGABANK,DC=LOCAL
| ldapServiceName: MEGABANK.LOCAL:[email protected]<SNIP>
Enumerating LDAP using ldapsearch:
Enumerate LDAP naming context server name and domain name:
+DO THIS FIRST!+ before anything else.
We cannot do ldap queries without knowing the FQDN of the ldap server and the domain name e.g "dc=sugarape,dc=local".
Establish Naming Context:
ldapsearch -H ldap://[IP] -x -s base namingcontexts
ldapsearch -H ldap://10.129.228.111 -x -s base namingcontexts
There are two different versions of windapsearch, in my testing it’s actually better to use the GO version as it seems to work, there are some issues with the current python version with imports being outdated etc.
The syntax is different for the GO version in we have to specify the module with -m then the module name e.g. users
We can enumerate via ldap with just a password too, alas the Support box:
from ldap3 import*s = Server('[IP]',get_info = ALL)
c = Connection(s, '', '')
c.bind()
## If it returns true we can run the next command it will return all LDAP informations.info
Simple Python Script:
from ldap3 import*srver = input("Enter IP of DC ")
s = Server(srver,get_info = ALL)
c = Connection(s, '', '')
checkserver = c.bind()
if checkserver ==True:
print(s.info)
else:
"Server does not allow LDAP Anonymous bind"
More advanced python script that allows passing username and passwords, also implements SSL:
from ldap3 import*import re
import argparse
import logging
import getpass
defis_valid_ip(ip):
pattern = re.compile(r"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$")
return pattern.match(ip) isnotNone# Setup logginglogging.basicConfig(filename='ldap_test.log', level=logging.INFO)
# Command-line argument parsingparser = argparse.ArgumentParser(description="LDAP Anonymous Bind Test")
parser.add_argument('dc_ip', help="IP address of the Domain Controller")
parser.add_argument('-u', '--user', help="Username for authentication", default='')
parser.add_argument('-p', '--password', help="Password for authentication", default='')
args = parser.parse_args()
# Validate IP addresssrver = args.dc_ip
ifnot is_valid_ip(srver):
print("Invalid IP address format.")
logging.error(f"Invalid IP address format: {srver}")
exit(1)
# Handle secure password inputuser = args.user
password = args.password
ifnot password and user:
password = getpass.getpass("Enter password: ")
# Function to attempt LDAP connectiondefattempt_connection(use_ssl):
try:
s = Server(srver, use_ssl=use_ssl, get_info=ALL)
c = Connection(s, user, password)
checkserver = c.bind()
return s, c, checkserver
exceptExceptionas e:
logging.error(f"Error connecting to the server with SSL={use_ssl}: {e}")
returnNone, None, False# Attempt to connect with SSL firstprint(f"Attempting to connect to {srver} with SSL...")
logging.info(f"Attempting to connect to {srver} with SSL")
s, c, checkserver = attempt_connection(use_ssl=True)
# If SSL connection fails, retry without SSLifnot checkserver:
print("Failed to connect with SSL. Retrying without SSL...")
logging.warning("Failed to connect with SSL. Retrying without SSL...")
s, c, checkserver = attempt_connection(use_ssl=False)
# Final status checkif checkserver:
print("Connected successfully. Retrieving server information...")
logging.info("Connected successfully")
print(s.info)
else:
print("Failed to connect: Server does not allow LDAP Anonymous bind or invalid credentials.")
logging.error("Failed to connect: Server does not allow LDAP Anonymous bind or invalid credentials.")
Powershell Script to query LDAP:
# Create a DirectoryEntry object for the LDAP path$ldapPath = "LDAP://dc=sugarape,dc=local"$directoryEntry = New-Object System.DirectoryServices.DirectoryEntry($ldapPath)
# Create a DirectorySearcher object$searcher = New-Object System.DirectoryServices.DirectorySearcher($directoryEntry)
# Define the LDAP filter$searcher.Filter = "(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*))))"# Search in the entire subtree$searcher.SearchScope = "Subtree"# Find all matching entries$results = $searcher.FindAll()
# Iterate through the results and display the propertiesforeach ($result in $results) {
$entry = $result.GetDirectoryEntry()
$entry.Properties | foreach {
Write-Output "$($_.PropertyName) = $($_.Value)" }
}
+Attacking LDAP+
Netexec/Crackmapexec:
Has alot of amazing modules we can use with LDAP:
Command: crackmapexec ldap -L
LDAP Credential Stealing:
In the box, Authority it is possible to steal LDAP credentials by hosting a malicious ldap server and then forcing a client that uses LDAP to authenticate back to us our endpoint.
If you can control force authentication to an endpoint of your choosing this is viable way to steal crededentials
Have the victim connect back to us:
With PWM if we can access the config page we can enter our URL:
Ensure ldap not ldaps or it will be encrypted and you will just see cipher text.
Setup Listening Server:
nc -nvlp 636
+Note+:
No special type of server needs to be used just a server and port to listen on.
To test for LDAP injection, we can use input values that contain special characters or operators that can change the query’s meaning:
Injection Characters:
*
An asterisk * can match any number of characters.
( )
Parentheses ( ) can group expressions.
|
A vertical bar | can perform logical OR.
&
An ampersand & can perform logical AND.
(cn=*)
Input values that try to bypass authentication or authorisation checks by injecting conditions that always evaluate to true can be used. For example, (cn=*) or (objectClass=*) can be used as input values for a username or password fields.
This is an actual piece of PHP code that would run.
In this query, $username and $password contain the user’s login credentials.
An attacker could inject the * character into either field to modify the LDAP query and bypass authentication as it’s not being sanitized.
If injected into the $username field the LDAP query will match any user account with any password!!
If injected into the $password field the LDAP query match any user account with any password that contains the injected string. This would allow the attacker to gain access to the application with any username
+Lab Example+:
I injected the * char into the username and password fields and could login as the code was not being sanitized.
Prevention Techniques
Input Validation: Sanitize and validate all user inputs before using them in LDAP queries.
Use Bind Operations: Instead of constructing search filters with user input, use LDAP bind operations for authentication.
Escape Special Characters: Use LDAP-specific escaping functions to neutralize special characters in user input.
Implement Least Privilege: Ensure LDAP accounts have minimal necessary permissions.
Use Prepared Statements: If available in your programming language, use LDAP prepared statements to separate queries from data.
Fix
To mitigate the risks associated with LDAP injection attacks, it is crucial to thoroughly validate and sanitize user input before incorporating it into LDAP queries. This process should involve removing LDAP-specific special characters like * and employing parameterised queries to ensure user input is treated solely as data, not executable code.
Apply the principle of least privilege for LDAP accounts
Regularly audit and update LDAP configurations
Use input validation and parameterized queries to prevent LDAP injection
Implement proper password policies
Monitor LDAP logs for suspicious activities
Keep LDAP software and related components up to date
Use firewalls to restrict LDAP access to authorized hosts only
Implement account lockout policies to prevent brute-force attacks
Fix:
To mitigate the risks associated with LDAP injection attacks, it is crucial to thoroughly validate and sanitize user input before incorporating it into LDAP queries. This process should involve removing LDAP-specific special characters like * and employing parameterised queries to ensure user input is treated solely as data, not executable code.