Reading the directory with LDAP: Search base, scope, filter, and accessible attributes
An LDAP search result is not determined by a single 'permission' value; it is shaped by baseObject, scope, filter, requested attributes, and client/server limits. Paged Results divides results into pages; it does not bypass authorization or server limits. Being able to read a directory does not imply write/control rights on its objects: reads and changes rely on different access rights scoped to the operation and attribute.
1. Core mechanism
This lesson covers the LDAP Search operation via RFC 4511 §4.5.1: baseObject, scope, derefAliases, sizeLimit, timeLimit, typesOnly, filter and attributes components of SearchRequest. Special cases of the attribute selection list (empty list, '*', '1.1') are defined in §4.5.1.8. The context tags of the filter coding (equalityMatch [3], present [7]) are in the same section. AD's server-side results limits (e.g., MaxPageSize and the paged results control mechanism) are mentioned conceptually, but specific version numbers are not made up; The ACE level logic of the access decision is linked to a separate course.
Interfaces and specifications
- baseObject: DN where the search will begin; the root of the call is determined from here (RFC 4511 §4.5.1.1).
- scope: baseObject(0) that entry only, singleLevel(1) direct subobjects, wholeSubtree(2) the entire subtree (RFC 4511 §4.5.1.2).
- filter: matching condition of objects; Alternatives to CHOICE such as equalityMatch, present, substrings, and/or/not (RFC 4511 §4.5.1.7).
- attributes selects fields from each matching entry. An empty list or '*' requests all user attributes; operational attributes must be named separately. '1.1' alone requests no attributes; the entry's DN can still be returned.
- typesOnly: TRUE returns only attribute names, without values (RFC 4511 §4.5.1.6).
- sizeLimit/timeLimit: upper limits requested by the client; The server can also impose its own upper limit (RFC 4511 §4.5.1.4–5).
- paged results: control used to retrieve large result sets piece by piece; The server limits the number of objects returned in a single request.
Five decisions that define a search
In an LDAP search, baseObject identifies the starting entry and scope defines the candidates. Filter selects matches among them; attributes specifies the requested fields on those entries. Read permissions also constrain the result. Without separating these decisions, we cannot explain an empty response.
This distinction has a practical consequence: the same user in the same directory with different scope or filter will receive very different result sets. 'Is this data accessible?' The question is an incomplete question without specifying the search parameters used.
sizeLimit is the requested entry limit for the whole search; 0 means no additional client limit. The server can still impose its own limits. Paged Results Control is included in the initial SearchRequest. Subsequent pages use the server's cookie and the same search parameters. Page size and total result limits are distinct: paging grants no permission and does not remove administrative limits.
The requested attribute list is a contract
attributes specifies the fields requested on each matching entry. An empty list or '*' requests all user attributes. Operational attributes must be named explicitly; '*' alone does not include them. '1.1' alone requests no attributes. Matching entries are not removed: SearchResultEntry still carries their DN, with an empty attribute list. With typesOnly TRUE, requested and readable attribute names are returned without their values.
An important limitation: even if all user attributes are requested, some attributes and values may not be included in the result due to access controls or other restrictions (RFC 4511 §4.5.1.8). So 'I wanted it but it didn't come' does not always mean 'no'; It could also be 'you are not allowed to read it in this context'.
Select People in the tree: baseObject includes only People; singleLevel includes Kayra, Deniz and Teams; wholeSubtree also includes People and ResearchTeam beneath Teams. For '(mail=*)', an entry without mail yields FALSE. If Deniz.mail is unreadable in this context, AD treats it as absent for filtering too. An attribute unrecognized by the schema can yield Undefined. FALSE and Undefined have different causes; neither is a match.
Example request: receiving a receiving SearchRequest
The artifact for this lesson displays a synthetic SearchRequest at the byte level: baseObject 'DC=outreason,DC=example', scope wholeSubtree(2), derefAliases neverDerefAliases(0), sizeLimit 0 (no client limit), timeLimit 30 seconds, typesOnly FALSE and equalityMatch as filter (sAMAccountName=kayra). The requested attribute list is cn, mail and memberOf.
In the coding, you see that the filter is carried by the equalityMatch [3] context tag (0xA3), and that the AttributeValueAssertion in it consists of attributeDesc and assertionValue OCTET STRING. This instantiates that the filter syntax ('(sAMAccountName=kayra)') actually corresponds to a structured ASN.1 tree.
Reading is not the same right as controlling.
Being able to read an attribute over LDAP does not mean you can change it on that object. Attribute reads use RIGHT_DS_READ_PROPERTY; writes generally use RIGHT_DS_WRITE_PROPERTY, while some operations use operation-specific validated-write or control-access rights. The corresponding ACEs can be scoped to an attribute/property set or object ([MS-ADTS] Access Checks, Validated Writes, and Property Set). For example, reading group membership is not proof that you can update the group's `member` attribute.
This distinction is critical in evaluating defense and attack: broad readability gives 'discovery', but not 'modification' per se. When reporting a result, 'read' and 'writable/checkable' should be specified separately.
Is the search result actually complete?
Receiving two SearchResultEntry messages does not establish successful completion. The final SearchResultDone reports the operation resultCode. Entries from a search ending with sizeLimitExceeded (4) or timeLimitExceeded (3) remain observations, but not a complete requested set. Even success is bounded by base, scope, filter and visibility.
With simple paged results, one page’s successful Done does not finish the entire sequence. A nonempty opaque cookie requires continuation; the completed sequence ends with an empty cookie. Do not infer counts or trust from the cookie contents. Changes between pages can cause duplicate or omitted entries, so a final empty cookie does not guarantee a single-time snapshot. Compare limit, first-page and changed-dataset cases separately.
State and data flow
- The client creates a SearchRequest with baseObject, scope, filter, requested attributes and limits.
- The server locates baseObject and determines the candidate entries from scope.
- For each candidate object, the filter is evaluated with three-valued logic (TRUE/FALSE/Undefined).
- For entries matching TRUE, requested attributes pass access checks before being returned in SearchResultEntry.
- With paging, the first request includes the control; subsequent pages use the same search and the server's cookie. Page size does not remove the search's total sizeLimit or access controls.
- The client records the returned fields as read; this result does not establish write or control rights.
2. Exploitation
Broken trust assumption
The assumption that is broken is this: If I can read the attributes of an object with LDAP, I also have the right to meaningful control or change over that object.
Technical prerequisites
- A bind context that can read the directory; In most environments, Authenticated Users can read many attributes.
- baseObject and wholeSubtree scope suitable for wide result; narrow scope limits exploration.
- An effective read right for the requested attribute; a confidential attribute also requires CONTROL_ACCESS in addition to READ_PROPERTY.
- To assert write/control, separately verify an effective DACL ACE/right that applies to the intended change and target attribute/object.
- For paged results, the server must support the Paged Results Control and policy must allow its use; it does not bypass administrative limits or ACLs.
Exploitation mechanism
A broad read right with a suitable baseObject, wholeSubtree scope, and selected filter can enumerate many objects: users, groups, memberOf, and service-related attributes. The Paged Results Control divides large results into pages resumed with a cookie; RFC 2696 defines it as managing the rate at which a server returns results, not bypassing authorization or server policy limits. Reads remain subject to attribute-level access checks. Reading a group's membership does not grant the right to change its member attribute. Verify the effective right/ACE for the intended change before treating it as possible.
Evidence is needed when moving from discovery to action
Reading LDAP gives the attacker a rich map; From this map 'which account can be changed?' Moving on to the question requires separate evidence. The claim of mutability must be based on write or control-access ACE granted to the principal that reads on DACL of the target object.
In practice, this means listing 'readable' findings separately and 'writable/checkable' findings separately. Mixing the two lists overstates the discovery data and creates false priority.
Scope changes; access rights do not
Keep the same read context and compare singleLevel with wholeSubtree under People in the synthetic tree. ResearchTeam becomes a candidate in the second search because of its parent relationships, not an increase in permission. Expanding the requested attribute list does not expose unreadable Deniz.mail either.
An assessment should record baseObject, scope, filter, requested attributes and limits. “Read the directory” alone does not identify which entries and fields were visible. Write or control rights require separate access evidence.
The risk boundary of this example
Treating a partial search as an inventory of every effective permission path creates unsupported impact claims. Successful reading also does not grant write permission.
3. Defense & Detection
Telemetry scope
- The LDAP search itself (base/scope/filter) is not logged as a separate event in the default security check; The read audit depends on object SACL and Audit Directory Service depends on the Access subcategory (4662).
- 4662 is generated only if the controlled object has the appropriate SACL and indicates the accessed class/attribute with ObjectType/Properties GUID; but does not include the filter or scope of the LDAP query.
- Hence the question 'who made a broad enumeration?' The question cannot be answered with 4662 alone; The read control tells you which object was touched, not what was structure.
- Application visibility is limited: many LDAP readings pass through unchecked attributes, leaving no trace.
Events and relevant fields
- The 4662 Provider is Microsoft-Windows-Security-Auditing, the channel is Security, Version 0 (Microsoft, 4662 document).
- EventData contains SubjectUserSid, SubjectUserName, ObjectServer=DS, ObjectType (class information), ObjectName (the accessed object's distinguished name), OperationType, AccessMask, and Properties. Properties can contain the access type and relevant class/property-set GUIDs.
- Property/property-set GUIDs in Properties can identify access scope; a property set can define rights for multiple attributes in one ACE. Event 4662 still records audited object access, not the LDAP query.
- 4662 does not report the size of the returned result set, sizeLimit, or paging behavior.
Auditing tells 'what was touched', not 'what was read'
The power of 4662 is saving access at the object/attribute levels; The limit is SID, which does not have the shape (base, scope, filter) of the query LDAP. So 'is there a broad enumeration was performed?' The question is only indirectly answered by security incidents: patterns such as accessing many different objects in a short time give clues but are not definitive.
The correct setup is to reduce noise with targeted SACL and supplement it with network/application side LDAP registers if possible. Spreading the read control across forest drowns the signal in noise.
Validation after the change
Record query parameters, entry count, terminal resultCode, paging control and whether the cookie is empty. Do not equate one DC view with every forest object or a fixed snapshot.
Detection logic · XPath
*[System[EventID=4662] and EventData[Data[@Name='AccessMask']='0x10']]Query assumptions
- Selects Security-channel Event 4662 records whose AccessMask text is exactly 0x10. 0x10 is Read Property; 0x10000 is DELETE. %%1537 is not used as a read code.
- This narrow match excludes combined masks and alternative text representations. Broader analysis requires a numeric check of the 0x10 bit. Audit Directory Service Access and an operation-matching SACL are required.
- 4662 does not carry baseObject, scope or filter. This selector is not evidence of broad enumeration; it has not been executed on Windows Event Log or a SIEM.
False positives
- Management tools, directory applications, and replication routinely read and 4662 produce controlled objects.
- If the attribute level SACL is kept large, a large volume will be created under normal workload.
- The odd 4662 does not distinguish whether the query is a broad exploration or a narrow search.
- Reading performed through unchecked attributes produces no events; The absence of an event does not indicate the absence of enumeration.
Hardening
- Apply read control only to high value objects and sensitive attributes with SACL; forest/domain produces overall wide reading SACL with high volume and low signal.
- Prevent unauthorized reading at level ACE by marking truly confidential attributes as confidential (searchFlags confidential bit); verify application compatibility with the pilot.
- Review server-side query limits (e.g. MaxPageSize and management limits) according to environment policy; Make unlimited sorting difficult with a single query.
- Reduce anonymous and overly broad reading rights; Align default permissions with the principle of least privilege.
- Evaluate network/application side LDAP telemetry (if possible) in addition to the security event to capture the enumeration; Don't trust a single source.
Read the examples
READ THE EXAMPLE TOGETHER
SYNTHETIC TEACHING EXAMPLEWhere does this SearchRequest search, and what does it request?
LDAP SearchRequest · scope, filter and attribute selection (synthetic BER example)
DC=outreason,DC=exampleThe starting DN. Scope determines whether the base, immediate children or whole subtree is examined.
wholeSubtree (2)Subtree including the base. This request has sizeLimit=0, timeLimit=30, typesOnly=FALSE. Zero means no client limit; server limits still apply.
(sAMAccountName=kayra)Context [3] equalityMatch contains two OCTET STRING fields: attributeDesc and assertionValue. It selects matching entries, not the returned attributes.
cn, mail, memberOfRequested fields. Only selected, readable values are returned from a matching entry; omission alone does not prove an attribute is absent.
Base and scope define candidates; filter selects matching entries; attributes selects requested fields. These are separate decisions.
Field mapping applies only to the unchanged synthetic fixture. LDAP uses restricted BER; this definite-length example is also accepted by the strict DER parser. No schema, server or access-control engine runs.
Scope of this example
Synthetic SearchRequest based on RFC4511 §4.5.1. One root SEQUENCE (LDAPMessage), exactly94 bytes with no trailing bytes; messageID=1; protocolOp [APPLICATION 3] SearchRequest. baseObject='DC=outreason,DC=example'; scope=2 (wholeSubtree); derefAliases=0 (neverDerefAliases); sizeLimit=0 (no additional client limit; server limits still apply); timeLimit=30; typesOnly=FALSE; filter=[3] equalityMatch (sAMAccountName=kayra); attributes={cn,mail,memberOf}. LDAP uses restricted BER. These definite-length TLVs are also accepted by the project's strict DER parser, which does not validate full BER, LDAP schema, filter evaluation or access decisions. All values are synthetic.
Open the raw record · ASN1-HEX
30 5c 02 01 01 63 57 04 17 44 43 3d 6f 75 74 72
65 61 73 6f 6e 2c 44 43 3d 65 78 61 6d 70 6c 65
0a 01 02 0a 01 00 02 01 00 02 01 1e 01 01 00 a3
17 04 0e 73 41 4d 41 63 63 6f 75 6e 74 4e 61 6d
65 04 05 6b 61 79 72 61 30 14 04 02 63 6e 04 04
6d 61 69 6c 04 08 6d 65 6d 62 65 72 4f 66READ THE EXAMPLE TOGETHER
SYNTHETIC TEACHING EXAMPLEWhat does this observation establish?
Comparison observation worksheet · synthetic
opaque-1A non-empty cookie indicates continuation; first-page success does not complete the directory search.
sizeLimitExceededEntries returned before sizeLimitExceeded may be partial. Their count does not prove completeness.
Different causes can produce the same symptom. Compare this worksheet with the lesson’s decision boundaries.
This JSON is a teaching record, not Windows output or an executable request.
Scope of this example
This teaching worksheet is not native Windows output. Values are comparison assumptions; the controls above show which outcomes remain unknown.
Open the raw record · MODEL-JSON
{
"kind": "teaching-record",
"synthetic": true,
"scenario": "E08",
"page1": {
"entries": [
"toy-A",
"toy-B"
],
"result": "success",
"cookie": "opaque-1"
},
"page2": {
"entries": [
"toy-C"
],
"result": "success",
"cookie": ""
},
"limitedVariant": {
"entries": [
"toy-A"
],
"result": "sizeLimitExceeded"
}
}Two reality checks
- Assumption: A search where I want all user attributes (empty list or '*') gives me every field of that object.
- In fact: '*' does not return operational attributes (they must be requested by name) and access controls may filter some attribute/values from the result entirely. A non-returning field may not be 'none' but 'could not be read in this context' (RFC 4511 §4.5.1.8).
- Assumption: I can read the attributes of an account or group with LDAP, I can also change it.
- In fact: Reading and writing are based on different ACEs. Seeing memberOf or an attribute is not enough to make changes to the relevant object without write or control-access rights; The control assertion must also be verified from DACL.
YOUR TURN
Work through this story.
Go beyond recall: change a condition, read evidence, explain the reason for a decision.
1 / 3 · PREDICT
The base is OU=People with singleLevel scope. Tunahan is directly under People; another account is under nested OU Teams. Which account is a candidate?
A hint
SingleLevel covers immediate children only; filter outcome is separate.
Read the answer reasoning
Tunahan is a candidate; the nested Teams account is outside this scope.
Being a candidate does not automatically establish filter matching or attribute read permission.
2 / 3 · READ EVIDENCE
Does this page prove that the entire search has ended?
- SearchResultDone resultCode
- success (0)
- Paged-results response cookie / Cookie
- Non-empty opaque value
- Received entries / Alınan entry
- 2
A hint
A page’s Done result differs from the final paging cookie.
Read the answer reasoning
No; the non-empty cookie indicates another page.
One successful page proves neither completion of the whole set nor a single-time snapshot.
3 / 3 · EXPLAIN
Tunahan’s memberOf is readable. Why does this not establish permission to change group membership?
A hint
Are the read field, modified target and requested right the same?
Read the answer reasoning
The LDAP result is evidence of reading in a particular context. Changing membership requires separate authorization for the relevant group/member operation; visibility does not substitute for control.
- I separated read from write/control permissions.
- I identified the target object/attribute and effective caller scope.
Your explanation is not automatically graded. Compare the checkpoints with your answer.
Open the case terminal · PowerShell / CMD
Training simulation · Commands and outputs belong to this case.
Read the account name and SID of this session.
Run the prepared script as supplied, or try the everyday commands below.
Ctrl / ⌘ + Enter: run · Shift + Enter: new line
PS C:\Users\tunahan>
Long output: scroll inside the terminal to read more.
Curious? Try everyday commands
Tap a command, then Run. User and network details follow the selected sample computer.
Recent commands in this session
These are learning practices; they do not affect certification exam scores.
Sources
- RFC 4511 · LDAP: The Protocol
§4.5.1 SearchRequest (baseObject/scope/derefAliases/sizeLimit/timeLimit/typesOnly/filter); §4.5.1.7 Filter and equalityMatch [3]/present [7]; §4.5.1.8 AttributeSelection and the '*'/'1.1' special cases; §4.5.2 SearchResultEntry. - RFC 4512 · LDAP: Directory Information Models
§5.1 operational (root DSE) attributes are returned only when requested by name; operational versus user attribute distinction. - Microsoft · 4662(S, F) An operation was performed on an object
Audit Directory Service Access; the SACL requirement; EventData fields (ObjectType/Properties/AccessMask); and the absence of query-shape recording. - RFC 2696 · LDAP Control Extension for Simple Paged Results Manipulation
Abstract and §3: pages/cookies manage the rate and continuation of search-result delivery; not an authorization or server-limit bypass. - [MS-ADTS] · Access Checks
§3.1.1.4.3: object/attribute visibility and RIGHT_DS_READ_PROPERTY; unreadable values are treated as absent in results and filters. - [MS-ADTS] · Validated Writes
§5.1.3.2.2: attribute write uses RIGHT_DS_WRITE_PROPERTY; validated writes have separate operation-specific rights/ACEs. - [MS-ADTS] · Property Set
§3.1.1.2.3.3: property-set GUID may be used in an ACE to grant/deny access across its member attributes; includes Group Membership set. - Microsoft · Membership property set
Group Membership rights-GUID and its property-set member list, including the Member attribute. - Microsoft · Consuming Events (Windows Event Log)
XPath 1.0 limitations: selectors must select Event nodes; supported child/attribute axes and comparison predicates.