偶尔走失,从未离开

本文将详细介绍LDAP存在的一些安全问题,LDAP普通注入和盲注,还有未授权访问问题。


文章目录:

0x01 简介

LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)是用来实现 目录服务 的一种运行于TCP/IP之上的协议。

目录服务是一种特殊的数据库系统,其专门针对读取,浏览和搜索操作进行了特定的优化、

目录一般用来包含描述性的,基于属性的信息,并支持精细复杂的过滤能力,可以存储包括个人信息,Web链接,jpeg图像等各种信息。

LDAP目录中的信息是按照树形结构组织的:

dn:一条记录的位置
dc:一条记录所属的区域
ou:一条记录所属的组织
cn/uid:一条记录的名字/ID

可以将LDAP与关系型数据库类比,数据库主要是由DB,TABLE和ROW来定位一条记录。

而LDAP首先要说明是哪一棵树(dc),然后是从树根到目标所经过的所有分叉(ou),最后就是目标的名字(cn/uid)

比如:

dn:cn=honglv,ou=bei,ou=xi,ou=dong,dc=waibo,dc=com

以上记录的树根为 dc=waibo和dc=com,分叉为ou=bei,ou=xi和ou=dong,目标为cn=honglv

具体的一条记录如下:

dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org
objectClass:organizationalPerson
cn:stan
cn:小刀
sn:小刀
description:a good boy

(保存为LDIF文件,可以导入到LDAP数据库中)

0x02 LDAP语法

LDAP注入是围绕着LDAP的语法来展开的,所以我们要先学习一下其语法。

search语法:attribute operator value
search filter options:( "&" or "|" (filter1) (filter2) (filter3) ...) ("!" (filter))
  • =(等于)

查找"Name"属性为"John"的所有对象:

(Name=John)

这条语句会返回"name"为"john"的所有对象,以便强调LDAP语句的开始和结束

  • &(逻辑与)

如果具有多个条件,并且希望所有条件都能满足,则使用该语法。

(&(Name=John)(live=Dallas))

以上语句查询居住在Dallas,并且名为John的所有人员

  • !(逻辑非)

此操作符用来排除具有特定属性的对象:

(!Name=John)

查找所有"name"不为"John"的人员

  • 通配符 *

可以用通配符表示值可以等于任何内容

(title=*)

查找具有职务头衔的所有人员

(Name=Jo*)

查找所有"Name"以"Jo"开头的人员

最后,举一个较复杂的例子:

(&(Name=John)(|(live=Dallas)(live=Austin)))

查找所有居住在Dallas或Austin,并且名为John的人员

0x03 LDAP 注入

LDAP注入和SQL注入比较类似,不过没有SQL注入中那么多华丽花哨的东西,要简单一些。

使用最广泛的LDAP服务端有两个:ADAM和OpenLDAP

正常的LDAP语句为:

(attribute=value)

我们可以构造value值,来改变原意

(attribute=value)(injected\_filter)

其中,OpenLDAP会忽略第二个过滤器,只执行第一个过滤器。而在ADAM中,则不允许出现存在两个过滤器的语句。

AND 注入

这种情况下,应用会将用户提交的参数拼接到一个含有&的语句中,来执行LDAP查询

(&(parameter1=value1)(parameter2=value2))

案例1:绕过登录验证

应用接收两个参数user和password,然后构造如下LDAP过滤器发送给LDAP服务器

(&(user=uname)(password=pwd))

由于LDAP服务器只处理第一个过滤器,所以我们可以插入如下语句:

admin)(&))(

1.jpg

通过插入这样的语句,我们就能让密码验证部分(password)的过滤器失效,从而绕过登录验证

(&(user=admin)(&))((password=xxx))

2.jpg

案例2:访问未授权数据

假如使用如下语句可以列举出所有可见的低安全等级文档,document是可控参数

(&(directory=document)(security_level=low)) 

我们可以插入如下语句:

document)(security_level=*))(&(directory=document

最终生成的过滤器为:

(&(directory=document)(security_level=*))(&(direcroty=document)(security_level=low))

第一个过滤器被执行,而第二个过滤器被忽略,从而列出所有安全等级的文档

4.jpg

OR注入

这种情况下,应用会将用户提交的参数拼接到一个含有|的语句中,来执行LDAP查询

(|(parameter1=value1)(parameter2=value2))

在这类注入中,由于是或关系,所以我们可以在查询出敏感数据的同时,又不破坏原有的过滤器结构,从而适用范围更广。

案例1:

存在一个资源管理器,用户可以查询系统中可用资源:

(|(type=Rsc1)(type=Rsc2))

1.jpg

我们注入如下语句,来查询出所有打印机和用户

printer)(uid=*)

过滤器最终被拼接为:

(|(type=printer)(uid=*))(type=scanner)

2.jpg

0x04 LDAP盲注

与SQL注入一样,LDAP中也存在盲注的情况,其通过页面响应的不同来提取属性值。

AND 盲注

如下语句提供了这样的功能:查询出Epson系列所有的打印机,其中objectClass的值是可控的。

(&(objectClass=printer)(type=Epson*))

我们注入如下语句,来屏蔽掉第二个过滤器:

*)(objectClass=*))(&(objectClass=void

这时候语句实际上变成了:

(&(objectClass=*)(objectClass=*))

第一个参数保持永真,不断修改第二个值,就可以推测出objectClass有哪些值(返回数据时为真)

(&(objectClass=*)(objectClass=users))(&(objectClass=void)(type=Epson*))
(&(objectClass=*)(objectClass=resources))(&(objectClass=void)(type=Epson*))

当然也可以逐位去探测:

(&(objectClass=*)(objectClass=u*))(&(objectClass=void)(type=Epson*))
(&(objectClass=*)(objectClass=us*))(&(objectClass=void)(type=Epson*))
(&(objectClass=*)(objectClass=use*))(&(objectClass=void)(type=Epson*))
(&(objectClass=*)(objectClass=user*))(&(objectClass=void)(type=Epson*))
(&(objectClass=*)(objectClass=users))(&(objectClass=void)(type=Epson*))

OR盲注

or盲注和and盲注的方法差不多,只是逻辑刚好要反过来。

我们要保持第一个参数永假,然后不断修改第二个参数的值。

(|(objectClass=void)(objectClass=users))(&(objectClass=void)(type=Epson*))

过程和方法类似于AND盲注,这里就不多说了

提升盲注效率

前面我们用逐位猜测的方法进行盲注,这种方法其实还可以再改进一下。

(&(objectClass=*)(objectClass=*a*))(&(objectClass=void)(type=Epson*))
(&(objectClass=*)(objectClass=*b*))(&(objectClass=void)(type=Epson*))
......

在正式开始之前,先确定要猜测的字符范围,将范围大大缩小之后,再进行逐位的猜测。

0x05 未授权访问/匿名访问

LDAP在默认情况下是允许用户匿名访问的,但只能进行read和search操作,而不能进行修改和删除操作。

但如果我们存储了大量的敏感信息,那么未授权的read和search也会造成巨大的安全隐患。

LDAP服务默认在389端口,利用的话直接用LDAP客户端工具连接即可。

0x06 参考


作者  :  watcher


添加新评论