Loading

LDAP注入介绍

LDAP注入介绍

一、 前言

前些日子在看 OWASP TOP 10 时看到了对LDAP注入攻击的介绍,对此产生了兴趣,在网上经过一番搜索之后找到了构成本文主要来源的资料,整理出来分享给大家。

二、 介绍

1. LDAP协议

LDAP(Lightweight Directory Access Protocol):即轻量级目录访问协议。是一种运行于TCP/IP之上的在线目录访问协议,主要用于目录中资源的搜索和查询。

2. LDAP存储

LDAP的存储以信息目录的形式存在,在该目录中可只定义一次用户和组,而在多台机器和多个应用程序间共享它们。LDAP与数据库最大区别在于,数据库以“表格-字段-值”的形是来存储数据,而LDAP以树状形方式访问存储在LDAP目录中的信息。

LDAP目录结构

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

条目&对象类&属性

LDAP目录服务是用于共享某些通用属性的存储和组织信息的软件应用程序,信息基于目录树入口被结构化,而服务器提供方便的浏览和搜索等服务。LDAP是面向对象的,因此LDAP目录服务中的每一个入口都是一个对象实例,并且必须对应该对象属性的规则。

  • 条目(entry):是目录中存储的基本信息单元。一个entry有若干个属性和若干个值,有些entry还能包含子entry
  • 对象类(obejectclass):对象类封装了可选/必选属性,同时对象类也是支持继承的。一个entry必须包含一个objectClass,且需要赋予至少一个值。而且objectClass有着严格的等级之分,最顶层是top和alias。例如,organizationalPerson这个objectClass就隶属于person,而person又隶属于top
  • 属性(atrribute):顾名思义,用来存储字段值。被封装在objectclass里的,每个属性(attribute)也会分配唯一的OID号码

3. LDAP查询语句

LDAP同样基于客户端/服务器模型,最常见的操作时使用过滤器搜索目录入口。客户端向服务器发送查询,服务器则响应匹配这些过滤器的目录入口。

一个圆括号中的判断称为一个过滤器:

( "&" or "|" (filter1) (filter2) (filter3) ...) ("!" (filter))
  • =(等于)
    查找“名“属性为“John”的所有对象,可以使用:
(givenName=John) 
  • &(逻辑与)
    如果具有多个条件并且希望全部条件都得到满足,则可使用此语法。例如,如果希望查找居住在 Dallas 并且“名”为“John”的所有人员,可以使用:
(&(givenName=John)(l=Dallas))
  • !(逻辑非)
    此操作符用来排除具有特定属性的对象。假定您需要查找“名”为“John”的对象以外的所有对象。则应使用如下语句:
(!givenName=John)
  • *(通配符)

可使用通配符表示值可以等于任何值。例如:返回以“Jo”开头的所有对象。

(givenName=Jo*)

高级用法eg:

您需要一个筛选条件,用来查找居住在 Dallas 或 Austin,并且名为“John”的所有对象。使用的语法应当是:

(&(givenName=John)(|(l=Dallas)(l=Austin)))

4. LDAP 注入

无逻辑操作符的注入

情景:(attribute=$input)

我们构造输入:$input=value)(injected_filter

代入查询的完整语句就为:

(attribute=value)(injected_filter)

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

例如我们要想查询一个字段是否存在某值时,可以用$input=x*进行推移,利用页面响应不同判断x*是否查询成功

带有逻辑操作符的注入

(|(attribute=$input)(second_filter))
(&(attribute=$input)(second_filter))

此时带有逻辑操作符的括号相当于一个过滤器。此时形如value)(injected_filter)的注入会变成如下过滤器结构

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

虽然过滤器语法上并不正确,OpenLDAP还是会从左到右进行处理,忽略第一个过滤器闭合后的任何字符。一些LDAP客户端Web组成会忽略第二个过滤器,将ADAM和OpenLDAP发送给第一个完成的过滤器,因而存在注入。

举个最简单的登陆注入的例子,如果验证登陆的查询语句是这样:

(&(USER=$username)(PASSWORD=$pwd))

输入$username = admin)(&)(使查询语句变为

(&(USER=admin)(&))((PASSWORD=$pwd))

即可让后面的password过滤器失效,执行第一个过滤器而返回true,达到万能密码的效果。

盲注深入

攻击者可以使用字母、数字搜索提取属性的值,这个想法的关键在于将一个复杂的值转化为TRUE/FALSE列表。这个机制,通常称为booleanization,大意是二值化吧,
假设攻击者想知道department属性的值,处理如下:

(&(idprinter=HPLaserJet2100)(department=a*))(object=printer))
(&(idprinter=HPLaserJet2100)(department=f*))(object=printer))
(&(idprinter=HPLaserJet2100)(department=fa*))(object=printer))

如此根据返回的不同结果猜解是否正确,和MYSQL盲注类似。
同样,攻击者可以使用字符集削减技术减少获得信息所需的请求数,为完成这一点,他使用通配符测试给定的字符在值中是否为anywhere

(&(idprinter=HPLaserJet2100)(department=*b*))(object=printer))
(&(idprinter=HPLaserJet2100)(department=*n*))(object=printer))

三、防御LDAP注入

总而言之,我们看到圆括号、星号、逻辑操作符、关系运操作符在应用层都必须过滤。
无论什么时候,只要可能,构造LDAP搜索过滤器的值在发送给LDAP服务器查询之前都要用应用层有效地值列表来核对。正则表达式替换掉就可以了。

参考资料:

LDAP注入与防御剖析

理解LDAP与LDAP注入

从一次漏洞挖掘入门Ldap注入

posted @ 2020-04-04 23:57  chalan630  阅读(1112)  评论(0编辑  收藏  举报