Source: securityboulevard.com – Author: Or Yair
Author:
Or Yair, Security Research Team Lead
SafeBreach Labs Researchers have developed a zero-click PoC exploit that crashes unpatched Windows Servers using the Windows Lightweight Directory Access Protocol (LDAP) remote code execution vulnerability.
Active Directory Domain Controllers (DCs) are considered to be one of the crown jewels in organizational computer networks. Vulnerabilities found in DCs are usually much more critical than those found in usual workstations. The ability to run code on a DC or to elevate users’ privileges through a DC heavily affects network security posture; this would provide adversaries the ability to take over the entirety of agents and servers under this domain.
On December 10, 2024, a remote code execution (RCE) vulnerability found by Yuki Chen (@guhe120) that affects any DC was published on the Microsoft Security Response Center (MSRC) website as part of the latest Patch Tuesday update. This vulnerability was assigned as CVE-2024-49112 and was given the CVSS severity score of 9.8 out of 10. However, a public exploit or blogpost explaining the vulnerability or exploitation path was not published anywhere.
The SafeBreach Labs team regularly undertakes projects that we feel can help both our customers, who represent some of the largest brands in the world, and the security community at large. Given the severity of this vulnerability’s consequences and the attention it has received from both since it was fixed, we decided as a team to prioritize it and are proud of the findings we have identified that will help enterprises address any potential exposures.
High-Level Summary
SafeBreach Labs developed a proof of concept exploit for CVE-2024-49112 that crashes any unpatched Windows Server (not just DCs) with no pre-requisites except that the DNS server of the victim DC has Internet connectivity.

The attack flow:
- The attacker sends a DCE/RPC request to the Victim Server Machine
- The Victim is triggered to send a DNS SRV query about SafeBreachLabs.pro
- The Attacker’s DNS server responds with the Attacker’s hostname machine and LDAP port
- The Victim sends a broadcast NBNS request to find the IP address of the received hostname (of the Attacker’s)
- The Attacker sends an NBNS response with its IP Address
- The Victim becomes an LDAP client and sends a CLDAP request to the Attacker’s machine
- The Attacker sends a CLDAP referral response packet with a specific value resulting in LSASS to crash and force a reboot of the Victim server

We believe our findings are significant for a number of reasons. First, we have shown the criticality of this vulnerability by proving that it can be used to crash multiple unpatched Windows servers. According to Microsoft’s classification, this vulnerability can be further exploited to lead to remote code execution. Second, we did verify that Microsoft’s patch fixes the integer overflow vulnerability and the exploit is not capable of crashing patched servers. Finally, we provided a public PoC that organizations can use to test and verify that their servers are protected. For more details, please see the GitHub repository noted at the end of this blog.
The vulnerability that the SafeBreach Labs PoC exploits affects technology that is in widespread use across enterprise networks, and this flaw could help attackers propagate more easily and effectively. SafeBreach helps large enterprises identify and address potential exposures, including vulnerabilities like CVE-2024-49112, and SafeBreach customers will soon have access to new capabilities to test their internal networks against this and other vulnerabilities. Keep an eye on www.safebreach.com for news to come.
Technical Deep Dive
Below, we will explain the exact technical details of how the SafeBreach Labs research team identified the exploitation path that triggers the vulnerability and crashes a DC (or any Windows Server), provide a step-by-step exploitation summary, and share a proof-of-concept (PoC) tool that executes these steps.
CVE-2024-49112
CVE-2024-49112 was titled as “Windows Lightweight Directory Access Protocol (LDAP) Remote Code Execution Vulnerability”. LDAP is the protocol that workstations and servers in Microsoft’s Active Directory use to access and maintain directory services information. The title of the vulnerability means that the vulnerability probably has something to do with LDAP-related code. On MSRC’s page for the CVE, Microsoft provided the following context:
“How could an attacker exploit this vulnerability?
A remote unauthenticated attacker who successfully exploited this vulnerability would gain the ability to execute arbitrary code within the context of the LDAP service. However successful exploitation is dependent upon what component is targeted.
In the context of exploiting a domain controller for an LDAP server, to be successful an attacker must send specially crafted RPC calls to the target to trigger a lookup of the attacker’s domain to be performed in order to be successful.
In the context of exploiting an LDAP client application, to be successful an attacker must convince or trick the victim into performing a domain controller lookup for the attacker’s domain or into connecting to a malicious LDAP server. However, unauthenticated RPC calls would not succeed.“
Based on this information—and assuming the accuracy of Microsoft’s documentation— we made the following assumptions:
- The attacker does not need to authenticate
- The vulnerability is an integer overflow type and is sourced in an executable or a Dynamic-Linked Library (DLL) that implements an LDAP client logic
- There are RPC calls that we can leverage in order to affect a DC to query an LDAP server controlled by an attacker
- In the context of a DC, the vulnerability probably lies in lsass.exe or in one of the DLLs that it loads, as lsass.exe implements the LDAP service on a DC
- Thus, the RPC interface with the RPC call that has the vulnerable LDAP client code is located in lsass.exe or in one of the DLLs that it loads as well
In addition, we also found an interesting insight by Artur Marzano (@MacmodSec) on X that suggested the potential location where Microsoft’s patch for the vulnerability was made, in wldap32.dll:

This insight fits perfectly with the documentation in MSRC’s website, as wldap32.dll implements the logic of an LDAP client.
Triggering a Remote LDAP Request
We started with proving the first step of exploitation against a DC—affecting it to query an LDAP server controlled by us. We needed to find an RPC call sourced in lsass.exe itself or in a DLL loaded into lsass.exe that imports functions from wldap32.dll. Using RpcView, we listed the available RPC interfaces loaded into lsass.exe:

Out of these RPC interfaces, we listed only the ones sourced in DLLs that are dependent on wldap32.dll and use its exported functions. We were looking for RPC interfaces that did not require authentication, as we assumed that the attacker does not need to authenticate. Two interesting interfaces we found that offered several interestingly named RPC calls that seemed related to LDAP queries and could possibly trigger one were located in lsasrv.dll and netlogon.dll:


Using IDA, we searched from the bottom up for RPC calls that actively use one of the functions imported from wldap32.dll. After a long search, we found DsrGetDcNameEx2. According to Microsoft’s documentation:
“The DsrGetDcNameEx2 method SHOULD return information about a domain controller (DC) in the specified domain and site. If the AccountName parameter is not NULL, and a DC matching the requested capabilities (as defined in the Flags parameter) responds during this method call, then that DC will have verified that the DC account database contains an account for the AccountName specified.
NET_API_STATUS DsrGetDcNameEx2(
[in, unique, string] LOGONSRV_HANDLE ComputerName,
[in, unique, string] wchar_t* AccountName,
[in] ULONG AllowableAccountControlBits,
[in, unique, string] wchar_t* DomainName,
[in, unique] GUID* DomainGuid,
[in, unique, string] wchar_t* SiteName,
[in] ULONG Flags,
[out] PDOMAIN_CONTROLLER_INFOW* DomainControllerInfo
);
”
This function looked pretty promising. It actively retrieves a hostname of a domain controller, in addition to verifying that a specific account exists in it. Both the domain name and the account are specified by the caller. That means that if the function uses LDAP in order to fulfil its purpose, we have what we need.
Moving forward, we needed to understand each one of DsrGetDcNameEx2 ‘s arguments and the values that we would set for them:
- ComputerName: The hostname of the target DC – This would be set to the victim’s hostname (further research revealed that this value does not matter at all for the function)
- AccountName: The account name that will be searched in the queried attacker’s domain —it can be any name—we don’t care if it exists or not
- AllowableAccountControlBits: Controls what will be queried about “AccountName” – can be 0 – we don’t really care about the queried account
- DomainName: The domain that will be queried – we set this to the domain name of the attacker
- SiteName: The site in which the DC must be located – can be set to NULL
- Flags – extra configuration for the call – we wanted the default behavior first, so we set it to 0
- DomainControllerInfo – Output parameter, where the returned information will be placed
For testing purposes, we installed two new DCs in the same subnet, and created two new root domains in each one of them. One was called SBRESEARCH.LAB and the other TESTDOMAIN.LAB. The goal was to run on the DC at SBRESEARCH.LAB (the attacker), and get the DC at TESTDOMAIN.LAB (the victim) to query the LDAP server on the DC at SBRESEARCH.LAB.
So running on the attacker DC, we called the DsrGetDcNameEx2 function on the victim DC. The arguments for the call were:
- ComputerName – WIN-ELD41******
- AccountName – blabla
- AllowableAccountControlBits – 0
- DomainName – SBRESEARCH.LAB
- SiteName – NULL
- Flags – 0
Unfortunately, this was not enough. Looking in Wireshark at the packets that were sent and received by the victim, we did not see any LDAP request initiated by the victim. However, Wireshark did show us something else very interesting. We saw that the victim sent a DNS query to its DNS server about a subdomain of SBRESEARCH.LAB. The DNS query was replied with an error code specifying that the DNS server did not find any record about that domain. Then it made perfect sense why the call failed. The only way for the victim DC to get a successful answer about this query is if the attacker DC was its DNS server. But we can’t just change a DNS server of a DC; that alone is likely to be considered a vulnerability:

The specific DNS query that was sent was of type SRV. DNS SRV queries specify a domain name, to which another domain name and a port are mapped in the response. The specific full domain name of the two queries sent by the victim DC were:
- _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.SBRESEARCH.LAB
- _ldap._tcp.dc._msdcs.SBRESEARCH.LAB
Great! It looked like the victim DC really was looking for an LDAP server on our attacker domain. If we could just get this DNS query to be solved successfully, then the LDAP query by the victim would potentially happen. But if we couldn’t change the victim’s DNS server, what else could we do?
Do we have to control the victim’s DNS server in order to get the query to be solved successfully? The victim’s DNS server does not know SBRESEARCH.LAB, but it does know other domains. Not all the domain names that are known to the victim’s DNS server were manually configured on it. This DNS server knows “google.com” of course. What did Google do in order to be known by this DNS server? They bought a domain on the Internet, so this is exactly what we did as well.
We bought the domain “safebreachlabs.pro” to create two SRV records for:
- _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.safebreachlabs.pro
- _ldap._tcp.dc._msdcs.safebreachlabs.pro
These SRV records need to return a domain name (IP is not supported) and a port, which are likely to be contacted by the victim as the LDAP server. At first sight, it looks like this might mean that the victim will have to contact an LDAP server that has a public IP on the Internet, which is a requirement that we prefer not to have, as a firewall might block such communication. But, if we already have access to the DC’s subnet, we can maybe set the domain name that the SRV record returns to be the hostname of the computer that we control in the subnet. So, we mapped both SRV records to the hostname of the attacker DC, and port 389 (its LDAP server).
Following that, we ran another test. Running on the attacker DC, we again called the DsrGetDcNameEx2 function on the victim DC, but this time changed the DomainName parameter to be “safebreachlabs.pro” instead of “SBRESEARCH.LAB”, and it worked. The victim DC issued an LDAP query to our attacker DC.

As you can see in the image above, the query is sent in Connectionless LDAP (CLDAP) and uses UDP instead of TCP. Using Windbg, we were able to verify that even though this request is being made in CLDAP, it is still performed by wldap32.dll.
Sending a Malicious LDAP Response
Once we managed to get the victim DC to query our attacker LDAP server, we could move on to understand what needed to be in the response for that query. That is in order to get the victim to execute the assumed vulnerable function found by Artur Marzano – LdapChaseReferral.
Referrals allow an Active Directory tree to be partitioned between multiple LDAP servers.
When an LDAP server can’t answer a request, it can reply with referrals to other servers that may provide the answers for the query. Then, the client can “chase” these referrals and query the referred servers instead. It’s important to note that a client is not obligated to “chase” these referrals. However, in our case it does chase them.
In order for a server to indicate that it does not have the answer for the query and refer the client to different servers, it needs to reply with the “referral” LDAP result code (equals to 10). The response must also contain valid LDAP URLs (starts with “ldap://” or “ldaps://”).

Going back to our exploitation scenario, in order to trigger the LdapChaseReferral function, we created our own custom LDAP UDP server that allowed us to send such a referral response packet.
Looking at the logic of the patch, Microsoft added a condition that verifies that a certain value is not bigger than another value. Based on the logs printed next to this logic, these compared values are named as “lm_referral” and “referral table size”. “lm_referral” is taken from an “ldap_message” struct (probably our response message) and “referral table size” is taken from an “ldap_connection” struct. The condition checks whether the “lm_referral” value is inside the range of the “referral table”. This range is the “referral table size”.
In the vulnerable version without the patch, this “lm_referral” value is indeed used to access a certain offset inside the referral table:

In our tests with Windbg, we saw that the value in “lm_referral” is always equal to 0, while the pointer to the referral table is also equal to 0. However, the condition determining whether the code accesses the “referral table” only verifies whether the “lm_referral” value is not zero. That means that in order to trigger the vulnerability we must control the “lm_referral” variable and make it non-zero. If we succeed, then the code will dereference a pointer that we can control using lm_referral’s value.
Searching for where the “lm_referral” variable inside the “ldap_message” struct is populated, we looked for other occurrences in wldap32.dll where the offset of “lm_referral” inside the “ldap_message” struct is being used (+0x3C). This resulted in two functions: LdapInitialDecodeMessage and LdapChaseReferral:

Then we identified the code that sets “lm_referral” in LdapInitialDecodeMessage:

What we saw is that “msgid” and “lm_referral” are taken from the same part of the packet.
In the above screenshot, the “value_from_response_packet” must be a 4-byte DWORD in order to make “lm_referral” a non-zero WORD, due to the shift by 25.
In the default response packet that we sent using our custom UDP LDAP server, we can fully control the value of “value_from_response_packet” (seen in the above screenshot), and it is one byte long. What we learned is that this value is prefixed with its length.
Then we understood what we needed to do in order to set a non-zero value for “lm_referral”:
- Change the byte that represents the length of “value_from_response_packet” (combination of “lm_referral” and “lm_msgid”) to 4 instead of 1.
- Now “value_from_response_packet” is 4 bytes long, and we can set the most significant byte from it, which will affect “lm_referral”. Keep in mind that we can set this byte only to a value that can be divided equally by 2, or otherwise we affect the value of “lm_msgid”
These two actions will point the flow of the code into the scope of the vulnerable code and create an access violation once the dereferencing happens:

Since “ref_table” is equal to NULL, and “lm_referral” at this point is a non-zero value, the last line of code in the above image will trigger a dereference for a non-existent address.

Next Steps
Based on the initial research outlined here, we will continue working towards the implementation of a full RCE chain. In order to not crash, and continue the exploit, we are planning to find a way to assign a non-NULL value into the referral table, while setting a value for “lm_referral” that will affect the code to dereference an address outside of this table.
Exploit PoC
We have created a research repository that includes a PoC of the LDAP Nightmare exploit that organizations can use to test and verify that their servers are protected against this vulnerability.
Affected Windows Servers
While our research focused on the testing of a Windows Server 2022 (DC) and Windows server 2019 (non DC), we believe this exploit path and PoC are applicable for any Windows Server version until the patch point.
Mitigation
To mitigate the risk of this vulnerability, organizations should implement the patch released by Microsoft detailed here. As noted above, SafeBreach Labs verified that the patch sufficiently prevents the exploitation and crashing of the tested servers. We believe patching this vulnerability is time critical, but also understand that patching a DC and Windows Servers must be done carefully and with the proper caution.
As such, we suggest organizations implement detections to monitor suspicious CLDAP referral responses (with the specific malicious value set), suspicious DsrGetDcNameEx2 calls, and suspicious DNS SRV queries until a patch can be applied.
Conclusion
This research set out to explore whether the LDAP CVE-2024-49112 vulnerability could be exploited. Our research proved that not only can it be exploited against Domain Controllers, it also affects any unpatched Windows Server.
In addition, we provided an exploit PoC for testing purposes, noted in the section above.
For more in-depth information about this research, please:
- Contact your customer success representative if you are a current SafeBreach customer
- Schedule a one-on-one discussion with a SafeBreach expert
- Contact Kesselring PR for media inquiries
Credits
We would also like to give credit to the talented individuals below for their work:
- Yuki Chen (@guhe120) – CVE-2024-49112
- Artur Marzano (@MacmodSec)
About Our Researchers
- Or Yair (@oryair1999)
- Shahak Morag (@ShahakMo)
Original Post URL: https://securityboulevard.com/2025/01/ldapnightmare-safebreach-labs-publishes-first-proof-of-concept-exploit-for-cve-2024-49112/
Category & Tags: Security Bloggers Network – Security Bloggers Network
Views: 15