文章总结: 文章深入解析LDAP注入原理,涵盖树形结构、查询语法及AND/OR/盲注攻击手法。通过PentesterLab靶场演示利用通配符与过滤器闭合绕过认证的具体过程。强调防御需严格进行输入验证,对特殊字符进行转义处理,以有效防止注入风险。 综合评分: 85 文章分类: WEB安全,漏洞分析,渗透测试,漏洞POC,安全开发
LDAP注入原理及防御
原创
dcnb dcnb
Web安全基础与实践
2026年1月29日 21:30 广东
LDAP,全称为轻量目录访问协议(Lightweight Directory Access Protocol),是一种基于X.500标准的轻量级目录服务协议,用于用于集中存储、查询、管理分布式环境中的结构化目录数据(如用户账号、设备信息、权限配置等),广泛应用于企业级身份认证、资源访问控制等场景。
1、LDAP简介
LDAP是一种通讯协议,支持TCP/IP,其默认端口为389,加密端口为636。与MySQL等关系型数据库将数据按记录一条条记录在表中不同,LDAP数据库的结构是树型的,数据是存储在叶子节点上的。这种存储结构十分有利于数据的查询,但无法支持频繁的写操作,因此LDAP适用于需要静态存储大量数据且快速查找的场景。
LDAP目录中的数据结构类似于文件系统的目录树。树的顶端是根(Root),向下扩展出多个分支,每个分支可以包含更多的分支或叶子节点,也就是最终的条目。目录中的信息包括:
(1)dn:一条记录的位置;
(2)dc:一条记录所属的区域;
(3)ou:一条记录所属的组织;
(4)cn/uid:一条记录的名字/ID。
目录信息树(DIT)是LDAP中的数据组织方式。在查询时,首先说明数据位于哪一棵树(dc),然后从树根到目标所经过的所有分叉(ou),最后得到数据的名字(cn/uid),具体结构如图1所示。
图1 DIT结构示意
在LDAP中,条目(entry)是目录中存储的基本信息单元,图1中每一个方框就代表一个条目。每个条目有若干个属性和若干个值,有些条目还可以包含子条目。下面是一个用户条目的示例:
dn: cn=websec,ou=people,dc=example,dc=comcn: websecsn: websecmail: [email protected]: inetOrgPerson
其中mail等数据就是条目中的属性,存储条目的具体信息。objectClass就是条目中的对象类,用于定义条目的属性集合,每个条目必须关联至少一个对象类(如inetOrgPerson,通用用户类)。
2、LDAP注入漏洞原理
2.1 LDAP查询语法
在介绍LDAP注入之前,我们首先对LDAP的查询语法进行简单的介绍。
LDAP查询使用一种类似于布尔逻辑表达式的过滤器语法,基本的LDAP查询语法如下:
(1)基本结构(属性=值)
cn=websec
这条查询语句用于查找所有属性cn的值等于websec的条目。
(2)逻辑AND运算
(&(objectClass=inetOrgPerson)(cn=websec))
这条查询语句用于查找所有objectClass属性为inetOrgPerson且cn为websec的条目。
(3)逻辑OR运算
(|(cn=websec1)(cn=websec2))
这条查询语句用于查找cn为websec1或websec2的条目。
(4)逻辑NOT运算
(!(cn=websec))
这条查询语句用于查找所有cn不为websec的条目。
2.2 LDAP注入漏洞
(1)AND注入
对于这种攻击方式,应用会构造由“&”操作符和和用户引入的参数组成的正常查询在LDAP目录中搜索,如上文逻辑AND运算所示。此时攻击者可以注入代码,维持正常的过滤器结构但能使用查询实现恶意攻击。
对于一个需要输入用户名和密码的登陆界面,UserName和Passwd分别对应用户名和密码,如果攻击者输入一个有效的用户名(假设为websec),再构造一个合法的过滤器结构,Passwd检查就会被绕过。Payload如下所示:
(&(UserName=websec(&))(Passwd=pwd))
LDAP服务器只处理第一个过滤器,即(&(UserName=websec(&)),该查询永真。因此攻击者无需密码即可访问系统。
(2)OR注入
对于这种攻击方式,应用会构造由“|”操作符和和用户引入的参数组成的正常查询在LDAP目录中搜索,如上文逻辑OR运算所示。此时攻击者可以注入代码,维持正常的过滤器结构但能使用查询实现恶意攻击。
对于一个资源管理器,其允许用户访问系统中的打印机、扫描机等资源。在该场景下就可以使用OR注入。
我们假设Rsc1=Printer表示系统中可用的打印机,Rsc2=Scanner为系统中可用的扫描机。如果攻击者构造如下Payload,LDAP服务器会响应所有的打印机和用户对象:
(|(type=Printer)(uid=*))(type=Scanner)
(3)LDAP盲注
假设攻击者可以从服务器响应中推测出一些内容,尽管应用没有报出错信息,LDAP过滤器中注入的代码却生成了有效的响应或错误。攻击者可以利用这一行为向服务器询问正确的或错误的问题,这种攻击称之为盲注攻击。
我们假设对象类为class,其对应一类数据,其中包含cn等于websec的一组数据,错误信息不会返回。如果用户想要从LDAP目录中获取所有的websec数据,可以构造如下过滤器:
(&(objectClass=class)(cn=websec*))
该查询会回显所有对象类为class,cn等于websec的数据。这是一个合法的查询语句。
如果攻击者进行LDAP盲注,可以构造如下Payload:
(&(objectClass=*)(objectClass=*))(&(objectClass=void)(cn=websec*))
此时仅第一个LDAP过滤器会被处理,这样cn等于websec的数据一定会回显。
这种代码注入方式允许攻击者推测可能存在于LDAP目录服务中不同对象类的值。当响应页面至少包含一个数据时,对象类的值就是存在的,如果对象类的值不存在或没有对它的访问,就不会有回显。
除了利用AND进行盲注外,还可以使用OR进行盲注。此时用于推测想要的信息的逻辑与AND相反。对于上述例子,我们可以构造如下Payload:
(|(objectClass=void)(objectClass=class))(&(objectClass=void)(cn=websec*))
该LDAP查询可以从目录中获取对象为class,cn等于websec的数据,从而收集信息。
3、LDAP注入实例
本文在Windows10攻击机中进行LDAP注入演示。
3.1靶场搭建
本文利用PentesterLab提供的靶场进行实例演示(iso镜像文件下载链接https://pentesterlab.com/exercises/web_for_pentester/attachments)。
在安装并设置完虚拟机配置后,打开虚拟机,如图2所示。
图2 靶场虚拟机界面
接着,输入sudo su切换至管理员权限,并输入ifconfig查看靶场ip地址,如图3所示。
图3 靶场ip地址查看
根据在虚拟机中查询到的ip地址,直接在win10攻击机中访问该地址,进入靶场,如图4所示。
图4 靶场界面
3.2 LDAP attacks – Example1
进入Example1后,发现界面显示未认证,如图5所示。
图5 Example1未认证界面
我们首先查看后端php代码:
<?php require "../header.php" ; $ld = ldap_connect("localhost") or die("Could not connect to LDAP server"); ldap_set_option($ld, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($ld, LDAP_OPT_REFERRALS, 0); if ($ld) { if (isset($_GET["username"])) { $user = "uid=".$_GET["username"]."ou=people,dc=pentesterlab,dc=com"; } $lb = @ldap_bind($ld, $user,$_GET["password"]); if ($lb) { echo "AUTHENTICATED"; } else { echo "NOT AUTHENTICATED"; } } require "../footer.php" ; ?>
其中关键函数为ldap_bind(),它使用指定的RDN($bind_rdn)和密码($bind_password)绑定到LDAP目录,如果未指定则使用匿名认证。因此我们可以利用不提交用户名和密码的方式实现匿名登录访问。可以构造如下Payload:
http://192.168.1.129/ldap/example1.php
提交后发现认证成功,如图6所示。
图6 Example1认证成功
3.3 LDAP attacks – Example2
初始界面为以hacker身份认证,被认为不合法,如图7所示。
图7 Example2不合法认证界面
我们查看后端php代码:
<?php require "../header.php" ; $ld = ldap_connect("localhost") or die("Could not connect to LDAP server"); ldap_set_option($ld, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($ld, LDAP_OPT_REFERRALS, 0); if ($ld) { $lb = @ldap_bind($ld, "cn=admin,dc=pentesterlab,dc=com", "pentesterlab"); if ($lb) { $pass = "{MD5}".base64_encode(pack("H*",md5($_GET['password']))); $filter = "(&(cn=".$_GET['name'].")(userPassword=".$pass."))"; if (!($search=@ldap_search($ld, "ou=people,dc=pentesterlab,dc=com", $filter))) { echo("Unable to search ldap server<br>"); echo("msg:'".ldap_error($ld)."'</br>"); } else { $number_returned = ldap_count_entries($ld,$search); $info = ldap_get_entries($ld, $search); if ($info["count"] < 1) { //NOK echo "UNAUTHENTICATED"; } else { echo "AUTHENTICATED as"; echo(" ".htmlentities($info[0]['uid'][0])); } } } } require "../footer.php" ; ?>
分析代码,其中关键为filter,也就是LDAP过滤器,其形式为$filter = “(&(cn=”.$_GET[‘name’].”)(userPassword=”.$pass.”))”。此时我们可以使用上文介绍的AND注入攻击方式实现无需密码登录。由于我们目前还不知道用户名是什么,而AND注入的前提是有有效的用户名,我们可以使用通配符*进行模糊匹配。根据上述思路,构造如下Payload:
http://192.168.1.129/ldap/example2.php?name=a*)(cn=*))%00password=pwd
其中a*代表以a开头的单词,这是尝试获取用户名的信息。此时LDAP服务器只处理第一个过滤器,也就是&(name=a*)(cn=*),可以使用任意密码登录,回显界面如图8所示。
图8 Example2正确回显
可以发现已经以admin身份认证。
此外,我们还可以尝试获取其他用户名信息,构造如下payload获取以b开头的用户名:
http://192.168.1.129/ldap/example2.php?name=b*)(cn=*))%00password=pwd
可以发现回显显示认证失败,可知没有满足条件的用户名,如图9所示。
图9 Example2尝试获取其他用户名
想要获取其他条件的用户名信息构造方式相似,使用通配符技巧查找用户。
4、LDAP注入防御
LDAP注入的防御方式与SQL注入类似,主要是要对用户的输入进行合法性验证,做好过滤工作,就可以实现有效防御。
我们给出了LDAP涉及的特殊字符及需要转义处理的字符,如图10所示。
图10 LDAP涉及的特殊字符及需要转义处理的字符
本文由刘嘉奕同学投稿。
- END –
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Web安全基础与实践 dcnb dcnb《LDAP注入原理及防御》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论