LDAP Injection (Lightweight Directory Access Protocol Injection)

http://projects.webappsec.org/w/page/13246947/LDAP%20Injection

LDAP Injection

LDAP Injection is an attack technique used to exploit web sites that construct LDAP statements from user-supplied input.

Lightweight Directory Access Protocol (LDAP) is an open-standard protocol for both querying and manipulating X.500 directory services. The LDAP protocol runs over Internet transport protocols, such as TCP. Web applications may use user-supplied input to create custom LDAP statements for dynamic web page requests.

When a web application fails to properly sanitize user-supplied input, it is possible for an attacker to alter the construction of an LDAP statement. When an attacker is able to modify an LDAP statement, the process will run with the same permissions as the component that executed the command. (e.g. Database server, Web application server, Web server, etc.). This can cause serious security problems where the permissions grant the rights to query, modify or remove anything inside the LDAP tree. The same advanced exploitation techniques available in SQL Injection can also be similarly applied in LDAP Injection.


LDAP注入是一种攻击网站的的技术,这类被攻击的网站会利用用户提供的输入构造LDAP语句。

轻量级目录访问协议(LDAP)是一个开放标准协议,该协议用于查询和操作X.500的目录服务。LDAP协议同TCP类似,运行于网络传输层。网页应用程序会利用用户输入创建自定义的LDAP语句以实现动态网页请求。网页应用程序如果不能对用户提供的输入进行适当的审查,会为攻击者创造改变LDAP语句的机会。攻击者修改的LDAP语句可以以一定的权限运行,这种权限同运行该语句的组件(如数据库服务器、网页应用程序服务器、网页服务器等)的权限相同。当这种权限具有查询、修改或删除LDAP树内的任何文件时,会造成严重的安全问题。可用于SQL注入的高级利用技术同样可以用于相似的LDAP注入中。


Example

Vulnerable code:

 line   1 using System;
 line   2 using System.Configuration;
 line   3 using System.Data;
 line   4 using System.Web;
 line   5 using System.Web.Security;
 line   6 using System.Web.UI;
 line   7 using System.Web.UI.HtmlControls;
 line   8 using System.Web.UI.WebControls;
 line   9 using System.Web.UI.WebControls.WebParts;
 line  10 
 line  11 using System.DirectoryServices;
 line  12 
 line  13 public partial class _Default : System.Web.UI.Page 
 line  14 {
 line  15     protected void Page_Load(object sender, EventArgs e)
 line  16     {
 line  17         string userName;
 line  18         DirectoryEntry entry;
 line  19 
 line  20         userName = Request.QueryString["user"];
 line  21 
 line  22         if (string.IsNullOrEmpty(userName))
 line  23         {
 line  24             Response.Write("<b>Invalid request. Please specify valid user name</b></br>");
 line  25             Response.End();
 line  26 
 line  27             return;
 line  28         }
 line  29 
 line  30         DirectorySearcher searcher = new DirectorySearcher();
 line  31 
 line  32         searcher.Filter = "(&(samAccountName=" + userName + "))";
 line  33 
 line  34         SearchResultCollection results = searcher.FindAll();
 line  35 
 line  36         foreach (SearchResult result in results)
 line  37         {
 line  38             entry = result.GetDirectoryEntry();
 line  39 
 line  40             Response.Write("<p>");
 line  41             Response.Write("<b><u>User information for : " + entry.Name + "</u></b><br>");
 line  42 
 line  43             foreach (string proName in entry.Properties.PropertyNames)
 line  44             {
 line  45                 Response.Write("<br>Property : " + proName);
 line  46 
 line  47                 foreach( object val in entry.Properties[proName] )
 line  48                 {
 line  49                     Response.Write("<br>Value: " + val.ToString());
 line  50                 }
 line  51             }
 line  52 
 line  53             Response.Write("</p>");
 line  54         }
 line  55     }
 line  56 }
 

Looking at the code, we see on line 20 that the userName variable is initialized with the parameter user and then quickly validated to see if the value is empty or null. If the value is not empty, the userName is used to initialize the filter property on line 32. In this scenario, the attacker has complete control over what will be queried on the LDAP server, and he will get the result of the query when the code hits line 34 to 53 where all the results and their attributes are displayed back to the user.

分析以上代码,我们发现在第20行userName变量用user参数进行初始化,并判断该值是否为空。如果这个值不为空,在第32行,userName会被用于初始化过滤属性。在这种情况下,攻击者完全可以在LDAP服务器上查询任何东西,并且在第34-53行所有的查询结果和属性都回馈给了用户。

 

Attack Example

攻击示例

http://example/default.aspx?user=*

In the example above, we send the * character in the user parameter which will result in the filter variable in the code to be initialized with(samAccountName=*). The resulting LDAP statement will make the server return any object that contains the samAccountName attribute. In addition, the attacker can specify other attributes to search for and the page will return an object matching the query.

在这个例子中,我们在user参数中发送*字符,该字符会初始化samAccountName(samAccountName=*)。LDAP会使服务器返回所有含有samAccountName属性的对象。另外,攻击者可以指定其他属性去查询,该页面会返回满足查询的对象。

Mitigation

缓解方法

The escape sequence for properly using user supplied input into LDAP differs depending on if the user input is used to create the DN (Distinguished Name) or used as part of the search filter. The listings below shows the character that needs to be escape and the appropriate escape method for each case.

对于用户提供的输入至LDAP中的转义序列理应根据用户输入的用途分别对待,用户输入可以用于创建DN(可分辨的名字)或者作为查询过滤器的一部分。下面列举的字符应该被过滤或者对不同的情况采取不同的过滤策略。

Used in DN - Requires \ escape

  • &
  • !
  • |
  • =
  • <
  • >
  • ,
  • +
  • -
  • "
  • '
  • ;

Used in Filter- Requires {\ASCII} escape

  • (           {\28}
  • )           {\29}
  • \           {\5c}
  • *           {\2a}
  • /           {\2f}
  • NUL      {\0}

The code below implements the escape logic for both DN and Filter case. Use CanonicalizeStringForLdapFilter() to escape when the input is used to create the filter and CanonicalizeStringForLdapDN()for DN. In addition, both IsUserGivenStringPluggableIntoLdapSearchFilter and IsUserGivenStringPluggableIntoLdapDN can be used to detect the presence of restricted characters.

下面的代码实现了DN和过滤情况的逻辑过滤。使用函数  CanonicalizeStringForLdapFilter()去过滤用户输入作为创建过滤器的情况,而用CanonicalizeStringForLdapDN()函数去过滤创建用户的情况。另外,IsUserGivenStringPluggableIntoLdapSearchFilterIsUserGivenStringPluggableIntoLdapDN两个函数可以检测限制符号的存在。


line   1 using System;
line   2 using System.Collections.Generic;
line   3 using System.Text;
line   4 
line   5 namespace LdapValidation
line   6 {
line   7     public class LdapCanonicaliztion
line   8     {
line   9         /// <summary>
line  10         /// Characters that must be escaped in an LDAP filter path
line  11         /// WARNING: Always keep '\\' at the very beginning to avoid recursive replacements
line  12         /// </summary>
line  13         private static char[] ldapFilterEscapeSequence = new char[] { '\\', '*', '(', ')', '\0', '/' };
line  14 
line  15         /// <summary>
line  16         /// Mapping strings of the LDAP filter escape sequence characters
line  17         /// </summary>
line  18         private static string[] ldapFilterEscapeSequenceCharacter = new string[] { "\\5c", "\\2a", "\\28", "\\29", "\\00", "\\2f" };
line  19 
line  20         /// <summary>
line  21         /// Characters that must be escaped in an LDAP DN path
line  22         /// </summary>
line  23         private static char[] ldapDnEscapeSequence = new char[] { '\\', ',', '+', '"', '<', '>',';' };
line  24 
line  25         /// <summary>
line  26         /// Canonicalize a ldap filter string by inserting LDAP escape sequences.
line  27         /// </summary>
line  28         /// <param name="userInput">User input string to canonicalize</param>
line  29         /// <returns>Canonicalized user input so it can be used in LDAP filter</returns>
line  30         public static string CanonicalizeStringForLdapFilter(string userInput)
line  31         {
line  32             if (String.IsNullOrEmpty(userInput))
line  33             {
line  34                 return userInput;
line  35             }
line  36 
line  37             string name = (string)userInput.Clone();
line  38 
line  39             for (int charIndex = 0; charIndex < ldapFilterEscapeSequence.Length; ++charIndex)
line  40             {
line  41                 int index = name.IndexOf(ldapFilterEscapeSequence[charIndex]);
line  42                 if (index != -1)
line  43                 {
line  44                     name = name.Replace(new String(ldapFilterEscapeSequence[charIndex], 1), ldapFilterEscapeSequenceCharacter[charIndex]);
line  45                 }
line  46             }
line  47 
line  48             return name;
line  49         }
line  50 
line  51         /// <summary>
line  52         /// Canonicalize a ldap dn string by inserting LDAP escape sequences.
line  53         /// </summary>
line  54         /// <param name="userInput">User input string to canonicalize</param>
line  55         /// <returns>Canonicalized user input so it can be used in LDAP filter</returns>
line  56         public static string CanonicalizeStringForLdapDN(string userInput)
line  57         {
line  58             if (String.IsNullOrEmpty(userInput))
line  59             {
line  60                 return userInput;
line  61             }
line  62 
line  63             string name = (string)userInput.Clone();
line  64 
line  65             for (int charIndex = 0; charIndex < ldapDnEscapeSequence.Length; ++charIndex)
line  66             {
line  67                 int index = name.IndexOf(ldapDnEscapeSequence[charIndex]);
line  68                 if (index != -1)
line  69                 {
line  70                     name = name.Replace(new string(ldapDnEscapeSequence[charIndex], 1), @"\" + ldapDnEscapeSequence[charIndex] );
line  71                 }
line  72             }
line  73 
line  74             return name;
line  75         }
line  76 
line  77         /// <summary>
line  78         /// Ensure that a user provided string can be plugged into an LDAP search filter 
line  79         /// such that there is no risk of an LDAP injection attack.
line  80         /// </summary>
line  81         /// <param name="userInput">String value to check.</param>
line  82         /// <returns>True if value is valid or null, false otherwise.</returns>
line  83         public static bool IsUserGivenStringPluggableIntoLdapSearchFilter(string userInput)
line  84         {
line  85             if (string.IsNullOrEmpty(userInput))
line  86             {
line  87                 return true;
line  88             }
line  89 
line  90             if (userInput.IndexOfAny(ldapDnEscapeSequence) != -1)
line  91             {
line  92                 return false;
line  93             }
line  94 
line  95             return true;
line  96         }
line  97 
line  98         /// <summary>
line  99         /// Ensure that a user provided string can be plugged into an LDAP DN 
line 100         /// such that there is no risk of an LDAP injection attack.
line 101         /// </summary>
line 102         /// <param name="userInput">String value to check.</param>
line 103         /// <returns>True if value is valid or null, false otherwise.</returns>
line 104         public static bool IsUserGivenStringPluggableIntoLdapDN(string userInput)
line 105         {
line 106             if (string.IsNullOrEmpty(userInput))
line 107             {
line 108                 return true;
line 109             }
line 110 
line 111             if (userInput.IndexOfAny(ldapFilterEscapeSequence) != -1)
line 112             {
line 113                 return false;
line 114             }
line 115 
line 116             return true;
line 117         }
line 118     }
line 119 }

References

"LDAP Injection: Are Your Web Applications Vulnerable?", By Sacha Faust - SPI Dynamics

[1] http://ebook.security-portal.cz/book/hacking_method/LDAP/LDAPinjection.pdf

 

"LDAP Injection & Blind LDAP Injection"

[2] http://www.blackhat.com/presentations/bh-europe-08/Alonso-Parada/Whitepaper/bh-eu-08-alonso-parada-WP.pdf

 

"A String Representation of LDAP Search Filters"

[3] http://www.ietf.org/rfc/rfc1960.txt

 

"Understanding LDAP"

[4] http://www.redbooks.ibm.com/redbooks/SG244986.html

 

"LDAP Resources"

[5] http://ldapman.org/

 

Failure to Sanitize Data into LDAP Queries ('LDAP Injection')

[6] http://cwe.mitre.org/data/definitions/90.html



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Active Directory 是微软公司开发的一种目录服务,它可以用于管理网络中的用户、计算机和其他资源。LDAPLightweight Directory Access Protocol)是一种用于访问和管理目录服务的协议。在 Active Directory 中,可以使用 LDAP 来访问和管理目录服务。 要配置 Active Directory 中的 LDAP,需要进行以下步骤: 1. 打开 Active Directory Users and Computers 管理工具。 2. 在左侧面板中,右键单击域名,选择“属性”。 3. 在“属性”窗口中,选择“安全”选项卡。 4. 单击“高级”按钮,打开“高级安全设置”窗口。 5. 在“高级安全设置”窗口中,选择“权限”选项卡。 6. 单击“添加”按钮,添加要访问 LDAP 的用户或组。 7. 在“选择用户、计算机或组”窗口中,输入要添加的用户或组的名称,单击“检查名称”按钮,确认名称正确后,单击“确定”按钮。 8. 在“高级安全设置”窗口中,选择“对象”选项卡。 9. 单击“属性”按钮,打开“属性编辑器”窗口。 10. 在“属性编辑器”窗口中,选择“msDS-Other-Settings”属性,单击“编辑”按钮。 11. 在“编辑属性”窗口中,输入以下值: 名称:msDS-Other-Settings 值:1 12. 单击“确定”按钮,关闭所有窗口。 13. 在 LDAP 客户端中,配置连接字符串,指定要访问的 Active Directory 服务器和端口号。 14. 使用 LDAP 客户端连接 Active Directory 服务器,进行目录服务的访问和管理。 以上就是 Active Directory 配置 LDAP 的详细步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值