0x00 LDAP注入

学习web_for_pentester时,碰到了ldap注入,想着把环境移植到自己的环境中来,于是需要自己来搭建ldap,之前都是在windows下完成的操作,这次用linux完成openldap的安装,虽然是第一次装,但是感觉还行,在安装phpldapadmin时由于更新了下php把我原来的环境弄炸了,修复环境,加上导出导入数据确实折腾了很久,对ldap的了解更深了点,记录下

openldap安装过程就不记录了,网上有不少帖子,跟着来就行了,先了解一些常见的缩写

dn 唯一标示,类似linux文件系统的绝对路径,通过dn我们可以快速查找到目录信息树中的任意一个节点
basedn也就是我们所说的目录信息树的根,rdn 则是相对标示名,即相对路径
dc 一般用于将完整域名划分几部分,如,pentestlab.org就会被表示为dc=pentesterlab,dc=com
uid 用户id
cn 姓名
sn 姓
o 组织[公司]名称,像这些只是从逻辑上分开
ou 单位[部门]名称

ldap过滤器 ldap未过滤输入会导致什么_ldap过滤器


search语法:

attribute operator value search filter options:( "&" or "|" (filter1) (filter2) (filter3) ...) ("!" (filter))

LDAP过滤器定义于RFC4515中,这些过滤器的结构可概括如下:

Fileter = (filtercomp)
Filtercomp = and / or / not / item
And = & filterlist
Or = | filterlist
Not = ! filter
Filterlist = 1*filter
Item = simple / present / substring
Simple = “=” / “~=” / ”>=” / “<=”
Present = attr =*
Substring = attr “=” [initial]*[final]
Initial = assertion value
Final = assertion value

所有过滤器必须置于括号中,只有简化的逻辑操作符(AND、OR、NOT)和关系操作符(=、>=、<=、~=)可用于构造它们。特殊符“*”可用来替换过滤器中的一个或多个字符。

除使用逻辑操作符外,RFC4256还允许使用下面的单独符号作为两个特殊常量:

(&)     ->Absolute TRUE 
(|)     ->Absolute FALSE
Web应用中的LDAP注入

LDAP注入攻击和SQL注入攻击相似,因此接下来的想法是利用用户引入的参数生成LDAP查询。

LDAP过滤器的结构和使用得最广泛的LDAPADAMOpenLDAP,下面的结论将会致代码注入:

(attribute=value):如果过滤器用于构造查询但缺少逻辑操作符,如value)(injected_filter的注入会导致两个过滤器(attribute=value)(injected_filter)。在OpenLDAP实施中,第二个过滤器会被忽略,只有第一个会被执行。而在ADAM中,有两个过滤器的查询是不被允许的,因而这个注入毫无用处。

(|(attribute=value)(second_filter)) or (&(attribute=value)(second_filter)):如果第一个用于构造查询的过滤器有逻辑操作符,形如value)(injected_filter)的注入会变成如下过滤器:(&(attribute=value)(injected_filter)) (second_filter)。虽然过滤器语法上并不正确,OpenLDAP还是会从左到右进行处理,忽略第一个过滤器闭合后的任何字符。一些LDAP客户端或者Web会忽略第二个过滤器,将第一个完整的过滤器发送给ADAMOpenLDAP,因而存在注入。

一些应用框架在将请求发送给服务器之前会检查过滤器是否正确,在这种情况下,过滤器语义上必须是正确的,其注入如:value)(injected_filter))(&(1=0。这会导致出现两个不同的过滤器,第二个会被忽略:(&(attribute=value)(injected_filter))(&(1=0)(second_filter))

既然第二个过滤器会被LDAP服务器忽略,有些部分便不允许有两个过滤器的查询。这种情况下,只能构建一个特殊的注入以获得单个过滤器的LDAP查询。value)(injected_filter这样的注入产生的结果是:(&(attribute=value)(injected_filter)(second_filter))

测试一个应用是否存在代码注入漏洞典型的方法是向服务器发送会生成一个无效输入的请求。因此,如果服务器返回一个错误消息,攻击者就能知道服务器执行了他的查询,他可以利用代码注入技术。回想一下之前讨论的,我们可以将注入环境分为两种:AND注入环境和OR注入环境以及盲注AND盲注OR环境。

总结一下符号如下表

符号

含义

&

与(列表中所有项必须为true)

|

或(列表中至少一个必须为true)

!

非(求反的项不能为true)

=

相等(根据属性的匹配规则)

~=

近似等于(根据属性的匹配规则)

>=

大于(根据属性的匹配规则)

<=

小于(根据属性的匹配规则)

=*

存在(条目中必须有这个属性,但值不做限制)

*

通配符(表示这个位置可以有一个或多个字符),当指定属性值时用到

\

转义符(当遇到“*”,“(”,“)”时进行转义)

模模糊糊的看完了,虽然有点小复杂,不过还是感觉懂了一点入门的东西,wooyun牛逼,感谢前辈大佬们,了解后直接肝靶场。

ldap过滤器 ldap未过滤输入会导致什么_ldap过滤器_02


0x01 Example1

ldap过滤器 ldap未过滤输入会导致什么_Marketing_03


点进去后,提示未授权,payload是直接把所有的usernamepassword都去掉就行了。

ldap过滤器 ldap未过滤输入会导致什么_搜索_04


分析下源码

$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";
    }
  }

ldap_connect()用于连接ldapldap_set_option($ld, LDAP_OPT_PROTOCOL_VERSION, 3)设置ldap的版本为3ldap_set_option($ld, LDAP_OPT_REFERRALS, 0)设置LDAP库是否自动追随LDAP服务器返回的引用,0为否
ldap_bind()使用指定的 RDN($bind_rdn)和密码($bind_password)绑定到LDAP目录,如果未指定则使用匿名认证。

这里就是利用的不提交验证方式进行匿名登陆访问成功的。


0x02 Example2

直接用admin登陆成功,admin)(%26))%00&password=x

ldap过滤器 ldap未过滤输入会导致什么_操作符_05


解释下原因,看下源码。

ldap过滤器 ldap未过滤输入会导致什么_ldap过滤器_06


下面这个划蓝线的是我们利用的过滤器,当传入参数后就变成了

(&(cn=admin)(&))%00(userPassword=x),注意%26&URL编码,这里要使用%00将第二个过滤器即(userPassword=x)截断掉,不然会出现语法错误。

ldap过滤器 ldap未过滤输入会导致什么_ldap过滤器_07


当然了,如果在不知道用户名为admin的情况下,可以使用上文所说的*来进行模糊匹配。

比如a*)(%26))%00&password=x

ldap过滤器 ldap未过滤输入会导致什么_Marketing_08


当为b*的时候的时候,由于没有账户就出错了。

ldap过滤器 ldap未过滤输入会导致什么_操作符_09


同理还可以结合其余的过滤器查寻到更多的信息,有机会再进行深入的学习(太菜了!!!)。

转一点其它人的例子

下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索: manager=*

下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索:cn=Ray Kultgen

下列过滤器返回所有不包含通用名 Ray Kultgen 的条目:(!(cn=Ray Kultgen))

下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性:description=*X.500*

下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目: (&(ou=Marketing)(!(description=*X.500*)))

下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目: (&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))

下列过滤器返回所有不代表人员的条目: (!(objectClass=person))

下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目:(&(!(objectClass=person))(cn~=printer3b))

最后,其实可以直接ldap客户端直接连,连上去,啥都有了。

ldap过滤器 ldap未过滤输入会导致什么_Marketing_10