导语:企业通常会部署Active Directory环境来管理域对象,如用户,组织,部门,计算机和打印机,并将此与自定义Web应用程序的增加结合起来,企业组织自然也希望将这两种技术集成在一起。
企业通常会部署Active Directory环境来管理域对象,如用户,组织,部门,计算机和打印机,并将此与自定义Web应用程序的增加结合起来,企业组织自然也希望将这两种技术集成在一起。这种集成是为了在域环境中创建最佳的集中式的身份验证方式,同时也提供了查询和管理Active Directory环境的方法。
需要记住的是,集成这两种技术也可能会为恶意攻击者提供另一个攻击面。因此,在与Active Directory集成时,实现良好的Web应用程序安全性至关重要。
在开始使用之前,我们首先了解一下用于将Web应用程序与Active Directory – LDAP(轻量级Active Directory协议)集成的协议。LDAP不仅可以从目录数据库查询对象,还可以用于管理和身份验证。
另外要记住的是LDAP 本身并不是目录数据库。它是一种提供访问目录数据库方法的服务和协议。此外,LDAP也并不是微软Active Directory环境独有的。实际上也有其他几种类型的数据库使用了LDAP,如OpenLDAP。
SQL注入是人们想到Web应用程序开发的时候想到的最典型的攻击方法,但是LDAP集成的网站也可能通过注入攻击被利用。SQL注入和LDAP注入之间存在着明显的差异,因为两者之间的语法差异很大。
为了说明LDAP注入,我搭建了一个集成了LDAP的有漏洞的Web应用程序,并将在下面演示一个简单的注入过程。在演示LDAP注入之前,我们先来介绍一下这两个知识点:
1. 了解目录数据库结构。
2. 了解LDAP语法。
目录数据库结构
根据企业组织的不同,目录数据库可能非常复杂而且非常庞大。因此,我将使用LDIF(LDAP交换格式)文件来说明一个简单的目录结构。LDIF文件只是表示目录数据和LDAP命令的纯文本文件。它们也用于读取,写入和更新目录中的数据。你可以在下面看到一个LDIF模板文件示例。
第8-10行:我们定义了顶级域名“ org ”。
第12-15行:我们定义了子域“ yourcompany ”,即“ yourcompany.org ”。
第17-37行:我们定义了三个组织单元(ou):财务和销售。
第29+行:我们在域“yourcompany.org”中添加了一个用途,并为属性赋值。例如,“ cn ”表示规范名称(或名字),“ sn ”表示姓氏,“ 邮件 ”表示该员工的电子邮件地址。
注意:
根据你使用的环境类型,LDAP属性会有所不同。例如,“userPassword”存在于OpenLDAP中,但不在Active Directory环境中。
了解基本的LDAP语法
LDAP具有非常特定的查询结构,并具有特定的语法。以下是在LDAP查询中使用的常见操作符:
· “=”(等于)
· &(逻辑和)
· | (逻辑或)
· !(逻辑不)
· *(通配符)
例如,如果我们想要在上面的LDAP结构中查询名为“ steve ”的人,我们的查询将如下所示:
(cn=steve)
也许我们想要搜索名称以“ s ” 开头的任何成员,那么我们可以使用通配符:
(cn=s*)
我们还可以使用“ | ”运算符搜索名称以“s”或“t”开头的任何人:
(|(cn=s*)(cn=t*))
我们也可以使用“&”运算符来要求这两个字段都是正确的。例如,如果我们想要搜索名称以“s”开头,姓氏以“d ” 结尾的任何人。
(&(cn=s*)(sn=*d))
最后,我们可以将所有这些操作符合并在一起来执行查询。例如,假设我们想要查找任何名字以“s ” 开头的人,但他们的姓必须以“d”或“r” 开头:
(&(cn=s*)(|(sn=d*) (sn=r*))
LDAP注入演示
现在我们对相关的知识点有了更好的了解,让我们继续进行演示。从下图中可以看到一个叫做 “Your Company LLC”的公司的“员工搜索表单”的网页示例:
我们先简单地输入一些数据并提交。
我们的表单通过获取查询(在上面的url栏中看到)提交值“ s ”和属性“ cn ”(名字)并返回给我们一个表,其中包含了名字以“s”开头的员工。
我们可以查看本网站的网页源码,查看相应的表单字段并获取URL中的参数(见下图)。
我们可以看到,LDAP属性只允许我们选择某些字段。我们可以在我们的URL中进行更改,也可以在开发人员控制台中直接编辑字段的值。这通常比在开发者控制台中更容易修改。显然,修改URL参数并不适用于POST请求,因此,我通常更愿意在开发人员控制台中编辑这些值。另一种方法是使用像Burpsuite或ZAP这样的代理在发送到服务器之前修改这些值。
下面你可以看到这个字段从“cn”更改为了“password”。
然后我们只需点击提交按钮,OK,下面我们可以看到,我们操纵了正在发送的数据,目的是检索用户的密码哈希值。但是,这仍然不是LDAP注入,只是一个很糟糕的编码习惯,导致了在客户端代码中可以控制这些属性。
现在让我们看看是否可以将LDAP注入到查询中并操纵我们看到的结果。在这个演示中,我将简单地显示LDAP语句预注入(见下图)。请注意,在渗透测试中,你将不可能看到这些语句的源代码。在这些情况下,可能必须使用模糊测试和信息侦察来成功利用LDAP注入。
正如我们所看到的,开发者没有做任何类型的输入验证或过滤用户在连接之前传递的值。与SQL注入一样,查询的字符串连接也是危险的。使用LDAP库的大多数Web框架还提供了一种经过验证的方法,用于在查询之前转义和/或过滤用户提供的输入。如果在与目录数据库集成时使用LDAP,应始终利用这些安全的方法或功能。
在上面的查询中,有几件事情正在发生:
1. 我们的声明以逻辑或“|”开始 其中包括两个子语句。如果匹配到一个对象,那么该对象将返回所需的属性包含了"cn","sn"和"ou"。
2. 在第一个子语句中,我们执行了(&(<supplied attribute>=<search term>)(department=finance))。这意味着我们可以搜索具有我们想要的任何属性和值的对象,但是该对象也必须属于财务部门。
3. 在第二个子语句中,我们执行了(&(<supplied attribute>=<search term>)(department=sales))。这意味着我们可以搜索具有我们想要的任何属性和值的对象,但该对象也必须属于销售部门。
4. 通过将这两者结合在一起,开发人员正试图将搜索查询仅限于属于财务或销售部门的用户对象。
尽管窃取销售或财务人员的凭证可能具有不可估量的价值,但是能够获取到域管理员的凭证那当然是更好的了。所以,我们来制作一个利用这个制作精妙的查询的注入。例如,在将URL中所需的LDAP属性从“ cn ”更改为“ password ”后,我们可以将LDAP语法作为我们的搜索条件注入:
))(department=it)(|(cn=
这将改变我们的查询:
改为:
这个语句现在可以查询我们的目录中的任何对象,这些对象需要包含:
1. 要有密码;
要么
2. 要属于“IT”部门;
要么
3. 要有任何规范的名称或在财务部门;
要么
4. 要有任何规范的名称或在销售部门。
当我们要利用LDAP注入时,用“OR”要比“AND”更好。
让我们试试这个新的查询:
真棒!利用这个技巧,我们现在得到了域凭据。正如我们所看到的,修改属性并注入正确的LDAP语法能够使我们可以从目录中查询任何我们想要的内容。
防御方法
1. 始终使用框架提供的功能来正确的验证,过滤或转义用户提供的输入数据。
2. 不允许用户指定客户端的属性值。使用可由用户指定的存储值或服务器端功能。
3. 更好地格式化你的查询(以及其他预防方法)以防止被修改。例如,如果上面的语句已被更改为
那么攻击者要查询到财务或销售部门的数据将是相当困难的。再次,适当的查询结构并不足以保护其本身。
4. 如果有问题的框架不提供验证,过滤或转义这些值的方法,请尽量通过正则表达式,存储过程或其他一些输入验证方法过滤用户提供的输入。但是,自定义方法只能作为最后的手段,应该由其他开发人员或安全专业人员验证其准确性。
其他说明
1. 在渗透测试中,你将不可能获得有关目录数据库的源代码和信息。因此,适当的侦察和模糊测试是比较关键的。
2. 你可能有权访问或无法修改属性。在这种情况下,你可能仅限于注入并仅从预定义的属性中检索信息。
3. LDAP也可以用来更新或删除一个目录数据库,所以在进行渗透测试时请一定要小心。
4. LDAP注入也可以用来绕过认证。具体内容请查看下面的OWASP文章的详细链接。
有关LDAP的一些比较有用的链接:
· LDAP注入身份验证绕过:https://www.owasp.org/index.php/Testing_for_LDAP_Injection_(OTG-INPVAL-006)
· OpenLDAP属性:http://www.zytrax.com/books/ldap/ape/
· Ldap查询基础知识:https://technet.microsoft.com/en-us/library/aa996205(v=exchg.65).aspx
· Active Directory属性:https://msdn.microsoft.com/en-us/library/ms675090(v=vs.85).aspx