LDAP Browser¶
Active Directory reconnaissance through beacon LDAP relay. The LDAP Browser allows operators to execute arbitrary LDAP queries against domain controllers using a beacon's authenticated session -- no direct network access from the operator workstation is required.
All queries are dispatched as discovery tasks to the selected beacon, which performs the LDAP bind and search using its current security context. Results are returned through the normal task polling pipeline and rendered in the UI.
Windows Beacons Only
LDAP queries require a Windows beacon with network access to a domain controller. The beacon selector in the UI filters to Windows beacons automatically. Non-Windows beacons cannot execute LDAP queries.
Architecture¶
sequenceDiagram
participant Operator as Operator UI
participant API as Stentor API
participant Queue as Task Queue
participant Beacon as Beacon (Windows)
participant DC as Domain Controller
Operator->>API: POST /cockpit/ldap/query
API->>Queue: Enqueue discovery task (ldap_query)
API-->>Operator: {task_id, status: "queued"}
Beacon->>Queue: Poll for tasks
Queue-->>Beacon: ldap_query task
Beacon->>DC: LDAP search (authenticated bind)
DC-->>Beacon: LDAP result entries
Beacon->>API: Submit task result
Operator->>API: Poll GET /cockpit/beacons/:id/tasks
API-->>Operator: Completed task with LDAPQueryResult UI Overview¶
The LDAP Browser page (/ldap) provides a three-tab interface:
| Tab | Purpose |
|---|---|
| Browse | Tree view for navigating the AD directory structure. Expanding a node queries one level of children using scope: onelevel. Click a node to populate the Base DN field in the Query tab. |
| Query | Custom LDAP filter editor with configurable Base DN, scope, and attribute list. Results display in a sortable table with DN and attribute columns. |
| Templates | Pre-built red team query templates organized by ATT&CK category. Selecting a template populates the Query tab with the template's filter and attributes. |
Beacon Selector¶
A dropdown at the top of the page lists all active Windows beacons. Each entry shows the hostname, username, and IP address. Selecting a beacon sets it as the target for all subsequent queries.
Result Table¶
Query results are displayed as a table with columns for each requested attribute. The result includes metadata:
| Field | Type | Description |
|---|---|---|
entries | array | Array of LDAP entries, each with dn and attributes |
count | int | Total number of entries returned |
truncated | bool | Whether the result set was truncated by max_results |
base_dn | string | The Base DN used for the query |
filter | string | The LDAP filter that was executed |
Execute LDAP Query¶
POST /api/v1/cockpit/ldap/query¶
Enqueue an LDAP query task to a beacon. The beacon executes the query against its reachable domain controller and returns the results through the task pipeline.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
beacon_id | string | Yes | UUID of the target beacon |
base_dn | string | Yes | LDAP search base (e.g., DC=corp,DC=local) |
filter | string | Yes | LDAP filter expression |
attributes | string[] | No | Attributes to return (empty = all attributes) |
scope | string | No | Search scope: base, onelevel, or subtree (default: subtree) |
dc | string | No | Target domain controller hostname or IP |
domain | string | No | Target domain name |
max_results | int | No | Maximum number of entries to return |
Example -- enumerate all domain computers:
curl -s -X POST https://stentor.app/api/v1/cockpit/ldap/query \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"beacon_id": "BEACON_UUID",
"base_dn": "DC=corp,DC=local",
"filter": "(objectCategory=computer)",
"attributes": ["sAMAccountName", "dNSHostName", "operatingSystem", "lastLogonTimestamp"],
"scope": "subtree",
"max_results": 500
}'
Response:
The result is retrieved by polling the beacon's task list (GET /api/v1/cockpit/beacons/:beacon_id/tasks) until the task status changes to completed. The task output contains the LDAPQueryResult JSON.
LDAP Filter Syntax¶
Stentor passes filters directly to the domain controller's LDAP implementation. Standard RFC 4515 filter syntax is supported.
| Operator | Syntax | Example |
|---|---|---|
| Equality | (attribute=value) | (sAMAccountName=admin) |
| Presence | (attribute=*) | (servicePrincipalName=*) |
| Substring | (attribute=*value*) | (description=*admin*) |
| AND | (&(filter1)(filter2)) | (&(objectClass=user)(adminCount=1)) |
| OR | (|(filter1)(filter2)) | (|(objectClass=user)(objectClass=computer)) |
| NOT | (!(filter)) | (!(userAccountControl:1.2.840.113556.1.4.803:=2)) |
| Bitwise AND | (attr:1.2.840.113556.1.4.803:=value) | UAC flag matching |
| Chain (LDAP_MATCHING_RULE_IN_CHAIN) | (attr:1.2.840.113556.1.4.1941:=value) | Recursive group membership |
Bitwise matching
The OID 1.2.840.113556.1.4.803 performs a bitwise AND against the attribute value. This is essential for userAccountControl flag checks. For example, (userAccountControl:1.2.840.113556.1.4.803:=2) matches accounts where the ACCOUNTDISABLE flag (bit 2) is set.
Search Scope¶
| Scope | Behavior |
|---|---|
base | Only the object specified by Base DN is returned |
onelevel | Direct children of Base DN (one level deep) |
subtree | Base DN and all descendants recursively (default) |
The Browse tab uses onelevel scope to expand tree nodes one level at a time, querying with (objectClass=*) and requesting the objectClass, name, and description attributes.
Pre-built Query Templates¶
GET /api/v1/cockpit/ldap/templates¶
Returns the static set of pre-built LDAP query templates. Templates are cached in the UI for 10 minutes.
Template response fields:
| Field | Type | Description |
|---|---|---|
id | string | Template identifier |
name | string | Human-readable name |
description | string | What the query finds |
category | string | ATT&CK category (credential-access, lateral-movement, discovery, etc.) |
filter | string | LDAP filter expression |
attributes | string[] | Attributes to return |
base_dn_suffix | string | Optional Base DN override (uses {baseDN} placeholder) |
Available Templates¶
| Template | Description | Filter |
|---|---|---|
| Kerberoastable Users | User accounts with SPNs set (Kerberoasting targets) | (&(objectCategory=person)(objectClass=user)(servicePrincipalName=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) |
| AS-REP Roastable Users | Accounts without Kerberos pre-authentication | (&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304)) |
| LAPS Passwords | Computers with LAPS passwords (requires read access) | (ms-Mcs-AdmPwd=*) |
| Template | Description | Filter |
|---|---|---|
| Unconstrained Delegation | Computers/users trusted for unconstrained delegation | (&(userAccountControl:1.2.840.113556.1.4.803:=524288)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) |
| Constrained Delegation | Objects with constrained delegation configured | (msDS-AllowedToDelegateTo=*) |
| Template | Description | Filter |
|---|---|---|
| All Domain Admins | Members of Domain Admins (recursive) | (&(objectCategory=person)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=Domain Admins,CN=Users,{baseDN})) |
| All Computers | All computer objects in the domain | (objectCategory=computer) |
| GPO List | All Group Policy Objects | (objectClass=groupPolicyContainer) |
| Trust Objects | Domain trust relationships | (objectClass=trustedDomain) |
| Template | Description | Filter |
|---|---|---|
| AdminSDHolder Protected | Objects with adminCount=1 (AdminSDHolder protected) | (&(adminCount=1)(objectCategory=person)(objectClass=user)) |
| DCShadow Candidates | Domain controllers (potential DCShadow targets) | (&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192)) |
OPSEC Considerations¶
Detection Surface
LDAP queries generate Windows Security Event 1644 (LDAP search completed) on domain controllers when expensive searches diagnostic logging is enabled. High-volume or unusual LDAP queries (e.g., enumerating all SPNs) may trigger SIEM correlation rules.
- MITRE ATT&CK: T1018 (Remote System Discovery), T1069 (Permission Groups Discovery)
- Event sources: Windows Security Event 4662 (directory object access), Event 1644 (LDAP query stats)
| Concern | Mitigation |
|---|---|
| Query volume | Use max_results to limit result sets. Avoid full subtree enumeration in monitored environments. |
| Query patterns | Kerberoastable/AS-REP queries are well-known signatures. Consider splitting into multiple smaller queries over time. |
| Authenticated bind | Queries execute under the beacon's security context. The domain controller logs the binding user. |
| Network traffic | LDAP traffic flows from the beacon host to the DC -- not from your operator workstation. Ensure the beacon's network access pattern is consistent with its cover identity. |
| Timing | Space queries across beacon check-in cycles. Rapid-fire LDAP queries from a single host are anomalous. |
Reducing LDAP noise
Request only the attributes you need instead of returning all attributes. Targeted attribute lists reduce response size and look more like legitimate application LDAP queries. Use onelevel scope when possible instead of subtree.