Ldap Injection on Azure
How Ldap Injection Manifests in Azure
LDAP injection in Azure environments typically occurs when user-supplied input is concatenated directly into LDAP queries without proper sanitization. Azure's Active Directory and various Azure services that integrate with LDAP directories create specific attack vectors that developers must understand.
The most common Azure-specific manifestation appears in C# applications using System.DirectoryServices or System.DirectoryServices.AccountManagement. Consider this vulnerable pattern found in Azure AD-integrated applications:
using System.DirectoryServices.AccountManagement;
public User GetUserByUserName(string username) {
using (var ctx = new PrincipalContext(ContextType.Domain, "contoso.com")) {
string filter = "(&(objectClass=user)(sAMAccountName=" + username + "))";
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username);
// Direct string concatenation creates injection point
return user;
}
}
An attacker could supply: john)(objectClass=*))(|(objectClass=* which would modify the LDAP filter to potentially return all users or bypass authorization checks entirely.
Azure Functions and Logic Apps that query LDAP directories present another attack surface. When these services process HTTP triggers with user input that flows into LDAP queries, the serverless nature can make detection harder since the execution environment is ephemeral.
Azure API Management policies can also be vulnerable when they perform LDAP lookups for authentication or authorization. A policy might contain:
<ldap>
<server>ldap://ad.contoso.com</server>
<userFilter>(&(objectClass=user)(sAMAccountName={userInput}))</userFilter>
</ldap>Where {userInput} is dynamically inserted without validation, allowing injection through the API Management layer itself.
Azure App Service applications using LDAP for backend authentication to on-premises AD or Azure AD Domain Services face similar risks. The injection can occur at the application layer or within custom authentication middleware.
Azure-Specific Detection
Detecting LDAP injection in Azure requires both static code analysis and runtime scanning. Azure DevOps and GitHub Actions can integrate security scanning into CI/CD pipelines to catch these issues before deployment.
middleBrick's Azure-specific scanning identifies LDAP injection through several mechanisms:
- Static analysis of deployed Azure Functions and App Services to detect vulnerable string concatenation patterns
- Dynamic scanning of API endpoints that accept user input and may pass it to LDAP queries
- Analysis of Azure API Management policies for unsanitized input insertion
- Detection of System.DirectoryServices usage patterns in deployed applications
- LLM/AI security checks for AI-powered Azure services that might process LDAP-related prompts
The scanner tests for LDAP injection by sending payloads that attempt to modify query logic, such as:
username=admin)(objectClass=*))(|(objectClass=*password=*If the application returns unexpected results or error messages containing LDAP syntax, this indicates a vulnerability.
For Azure AD Domain Services, middleBrick can scan the LDAP endpoint (typically port 389 or 636) to verify proper authentication and authorization controls are in place. The scanner checks for:
- Anonymous LDAP access where it shouldn't exist
- Weak bind credentials
- Excessive query results from crafted inputs
- Information disclosure through error messages
Azure Security Center and Defender for Cloud can complement middleBrick by providing runtime protection and alerting on suspicious LDAP query patterns, though they don't replace the need for proactive scanning.
Azure-Specific Remediation
Remediating LDAP injection in Azure environments requires using parameterized LDAP queries and proper input validation. The .NET System.DirectoryServices.AccountManagement library provides safer alternatives to raw string concatenation.
Secure implementation using PrincipalContext:
using System.DirectoryServices.AccountManagement;
public User GetUserByUserName(string username) {
if (string.IsNullOrWhiteSpace(username) || username.Length > 50) {
throw new ArgumentException("Invalid username");
}
using (var ctx = new PrincipalContext(ContextType.Domain, "contoso.com")) {
UserPrincipal user = UserPrincipal.FindByIdentity(
ctx,
IdentityType.SamAccountName,
username
);
return user;
}
}
The AccountManagement API handles proper escaping internally, eliminating the injection vector.
For raw DirectorySearcher usage in Azure applications:
using System.DirectoryServices;
public SearchResult FindUser(string username) {
if (!IsValidUsername(username)) {
throw new ArgumentException("Invalid username format");
}
using (var entry = new DirectoryEntry("LDAP://contoso.com")) {
using (var searcher = new DirectorySearcher(entry)) {
searcher.Filter = "(&(objectClass=user)(sAMAccountName={0}))";
searcher.Filter = string.Format(searcher.Filter,
EscapeLdapFilter(username));
return searcher.FindOne();
}
}
}
private string EscapeLdapFilter(string input) {
var escapeChars = new char[] { '\', '*', '(', ')', '\0' };
if (input.Any(c => escapeChars.Contains(c))) {
throw new ArgumentException("Input contains invalid characters");
}
return input;
}
Azure API Management policies can use the validate-jwt policy before processing user input, ensuring only authenticated requests reach LDAP lookup logic.
For Azure Functions, implement Azure AD authentication at the function level to prevent unauthenticated access to endpoints that might perform LDAP queries:
[FunctionName("GetUser")]
[HttpTrigger(AuthorizationLevel.User, "get", Route = "users/{username}")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.User, "get", Route = "users/{username}")] HttpRequest req,
string username,
ClaimsPrincipal principal) {
if (!principal.Identity.IsAuthenticated) {
return new UnauthorizedResult();
}
// Proceed with secure LDAP query
} Azure Key Vault should store any LDAP bind credentials rather than hardcoding them in application code, reducing the blast radius if an injection vulnerability is exploited.