LDAP是Lightweight Directory Access Protocol , 即轻量级目录访问协议, 用这个协议可以访问提供目录服务的产品,例如OpenLDAP。
比如公司的员工列表名单, 对于一个员工你能查到他的电话,工位,部门等各种信息, 这就是一个目录。目录存储数据的方式,不像我们熟知的关系数据库, 在数据都表中一行一行以树的方式存储。 比如一个人的信息是这样的:
常见LDAP统一认证服务,我们可以基于LDAP实现单点登录:
安全问题
LDAP 注入是利用用户引入的参数生成恶意 LDAP 查询,通过构造 LDAP 过滤器来绕过访问控制、用户权限提升。在维持正常过滤器的情况下构造出 AND、OR 操作注入来获得敏感信息。
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的人员。
最佳实践文档https://ldapwiki.com/wiki/Best%20Practices%20for%20LDAP%20Security
LDAP注入
可以搞个靶场进行练习。
LDAP注入举栗
AND LDAP注入
当后端的代码如下
(&(parameter1=value1)(parameter2=value2))
这里value1和value2都会被查询,其中value1和value2是用户可控的,如果过滤不完善,就会存在LDAP注入的可能。
比如一个用户登录的场景,用户输入username和password,应用会构造一个过滤器并发给LDAP服务器进行查询。
(&(username=uname)(password=pwd))
当用户输入一个有效的用户名,例如admin,那么就有可能在username字段后面进行注入,从而在不知道密码的情况下进行登陆。
payload: admin)(&)) result: (&(username=admin)(&))(password=123))
LDAP服务器只会处理第一个过滤器,而第一个过滤器永真,因此绕过了登录框
OR LDAP注入
当后端代码如下:
(|(parameter1=value1)(parameter2=value2))
一个典型的OR LDAP注入的场景就是:
假设一个资源管理器允许用户了解系统中可用的资源(打印机、扫描器、存储系统等)。用于展示可用资源的查询为:
(|(type=Rsc1)(type=Rsc2))
Rsc1和Rsc2表示系统中不同种类的资源,例如,Rsc1=printer,Rsc2=scanner用于列出系统中所以可用的打印机和扫描器。
payload: Rsc1=printer)(uid=*) result: (|(type=printer)(uid=*))(type=scanner))
LDAP服务器会响应所有的打印机和用户对象
LDAP盲注
LDAP AND盲注
假设一个Web应用想从一个LDAP目录列出所有可用的Epson打印机,错误信息不会返回,应用发送如下的过滤器:
(&(objectclass=printer)(type=Epson*))
使用这个查询,如果有可用的Epson打印机,其图标就会显示给客户端,否则没有图标出现。如果攻击者进行LDAP盲注入攻击*)(objectClass=*))(&(objectClass=void
,Web应用会构造如下查询:
(&(objectclass=*)(objectClass=*))(&(objectClass=void)(type=Epson*))
仅对第一个过滤器进行处理:
(&(objectclass=*)(objectClass=*))
结果是,打印机的图标会一定显示出来,因为该查询永远会有结果,过滤器objectClass=*总是返回一个对象。当图标被显示时响应为真,否则为假。
例如构造如下的注入:
(&(objectClass=*)(objectClass=users))(&(objectClass=foo)(type=Epson*)) (&(objectClass=*)(objectClass=resources))(&(objectClass=foo)(type=Epson*))
这种代码注入的设置允许攻击者推测可能存在于LDAP目录服务中不同对象类的值。当响应Web页面至少包含一个打印机图标时,对象类的值就是存在的,另一方面而言,如果对象类的值不存在或没有对它的访问,就不会有图标出现。
LDAP OR盲注
这种情况下,用于推测想要的信息的逻辑是相反的,因为使用的是OR逻辑操作符。接下来使用的是同一个例子,OR环境的注入为:
(|(objectClass=void)(objectClass=void))(&(objectClass=void)(type=Epson*))
这个LDAP查询没有从LDAP目录服务获得任何对象,打印机的图标也不会显示给客户端(FALSE)。如果在响应的Web页面中有任何图标,则响应为TRUE。故攻击者可以注入下列LDAP过滤器来收集信息:
(|(objectClass=void)(objectClass=users))(&(objectClass=void)(type=Epson*)) (|(objectClass=void)(objectClass=resources))(&(objectClass=void)(type=Epson*))
owasp官方文档https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html
LDAP安全防护
LDAP过滤器的结构和使用得最广泛的LDAP:ADAM和OpenLDAP
1、服务端对输入内容的合法性进行验证,检查提交的数据是否包含特殊字符,对特殊字符进行编码转换。
2、对于系统出现的错误信息,使用统一的错误页面,屏蔽系统本身的出错信息。
3、参数化XPath查询,将需要构建的XPath查询表达式,以变量的形式表示,变量不是可以执行的脚本。
4、通过MD5、SSL等加密算法,对于数据敏感信息和在数据传输过程中加密,即使某些非法用户通过非法手法获取数据包,看到的也是加密后的信息。
总结下就是:限制提交非法字符,对输入内容严格检查过滤,参数化XPath查询的变量。