Ldap Injection in Aspnet with Hmac Signatures
Ldap Injection in Aspnet with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Ldap Injection occurs when an attacker can manipulate LDAP query construction through untrusted input. In ASP.NET applications that bind to LDAP directories for authentication or group membership checks, unsanitized parameters such as user-supplied usernames or search filters can change query semantics. For example, a developer building a login flow might concatenate a username directly into an LDAP filter like (&(objectClass=user)(sAMAccountName={username})). If username contains special LDAP characters such as *, (, ), or \, the filter structure can be unintentionally altered, enabling bypasses or extraction of additional directory information.
When HMAC signatures are introduced as a mechanism to ensure integrity and authenticity of requests (e.g., an API client signs a payload with a shared secret and the server verifies the signature before processing), the LDAP interaction may still occur downstream. The vulnerability arises when the server uses data from the request—potentially included in or derived from the signed payload—to build LDAP queries without proper escaping. Because the HMAC only guarantees that the payload has not been tampered with, it does not sanitize or validate the semantic content of user-controlled fields. An attacker could craft a validly signed payload containing malicious LDAP metacharacters, and the server will still trust and use that data for directory operations.
Consider an endpoint that accepts a signed JSON body with a filter field used to search Active Directory. The client computes an HMAC over the JSON payload and sends it in a header. The server verifies the HMAC, then directly interpolates filter into an LDAP query. If the attacker supplies filter=(objectClass=user)(|(sAMAccountName=admin)(description=*)), the server may produce an LDAP query that returns more entries than intended, enabling information disclosure. In some configurations, crafted sequences can lead to authentication bypass (e.g., modifying the filter to always evaluate to true) or unauthorized group membership inference. This combination thus exposes the application to classic LDAP Injection despite the presence of HMAC-based request integrity checks.
Hmac Signatures-Specific Remediation in Aspnet — concrete code fixes
Remediation focuses on treating all data used in LDAP queries as untrusted, regardless of HMAC verification. Input validation and canonicalization must be applied to LDAP filter components individually, and you should avoid string concatenation in favor of parameterized LDAP APIs where available. Below are concrete code examples for an ASP.NET Core controller that receives a signed payload and safely builds an LDAP filter.
First, define a helper to escape special LDAP characters according to RFC 4515. This function ensures that characters like *, (, ), \\, NUL, and line breaks are properly encoded.
using System.Text;
public static class LdapEncoder
{
public static string Escape(string input)
{
if (string.IsNullOrEmpty(input))
{
return input;
}
var sb = new StringBuilder();
foreach (char c in input)
{
// From RFC 4515: special characters must be escaped
// * -> \2a
// ( -> \28
// ) -> \29
// \\ -> \5c
// NUL -> \00
switch (c)
{
case '*':
sb.Append("\\2a");
break;
case '(':
sb.Append("\\28");
break;
case ')':
sb.Append("\\29");
break;
case '\\\\':
sb.Append("\\5c");
break;
case '\0':
sb.Append("\\00");
break;
case '\n':
sb.Append("\\0a");
break;
case '\r':
sb.Append("\\0d");
break;
default:
// Only escape control chars and asterisk; others pass through
if (c <= 0x1F || c == 0x7F)
{
sb.AppendFormat("\\{0:X4}", (int)c);
}
else
{
sb.Append(c);
}
break;
}
}
return sb.ToString();
}
}
In your controller, validate and escape each component before constructing the filter. Do not trust the signed payload’s fields directly for query building.
[ApiController]
[Route("api/[controller]")]
public class LdapController : ControllerBase
{
[HttpPost("search")]
public IActionResult Search([FromBody] LdapSearchRequest request, [FromHeader] string xSignature)
{
// Assume HMAC verification happens here; if invalid, return 401.
if (!VerifyHmac(request, xSignature))
{
return Unauthorized();
}
// Validate allowed characters/patterns for attributes and values
if (!IsValidAttribute(request.AttributeName))
{
return BadRequest("Invalid attribute name");
}
string safeValue = LdapEncoder.Escape(request.AttributeValue);
// Use parameterized-style composition; avoid string interpolation for the filter
string filter = $"(objectClass=user)({request.AttributeName}={safeValue})";
// Perform LDAP search with 'filter' using a directory client
// Example: var results = directoryClient.Search(filter, ...);
return Ok(new { Filter = filter });
}
private bool VerifyHmac(LdapSearchRequest request, string signature)
{
// Implementation omitted: compute HMAC over canonical request and compare
return true;
}
private bool IsValidAttribute(string name)
{
// Allow only known safe attribute names to prevent injection via attribute key
var allowed = new HashSet(StringComparer.OrdinalIgnoreCase)
{
"sAMAccountName", "cn", "mail", "uid"
};
return !string.IsNullOrWhiteSpace(name) && allowed.Contains(name);
}
}
public class LdapSearchRequest
{
public string AttributeName { get; set; }
public string AttributeValue { get; set; }
}
Additional measures include rejecting queries that contain unescaped metacharacters, using dedicated LDAP libraries that support parameterized filters, and logging suspicious patterns for further analysis. HMAC verification remains useful for integrity, but it must be complemented with rigorous input handling to prevent LDAP Injection.