📜 ⬆️ ⬇️

DHCP security in Windows 10: disassemble critical vulnerability CVE-2019-0726



Image: Pexels

With the release of the January Windows updates, the news of the critically dangerous vulnerability CVE-2019-0547 in DHCP clients shook the public. The high CVSS rating and the fact that Microsoft did not immediately publish the evaluation of exploitability warmed up the interest, thus complicating the decision of users to urgently update their systems. Some publications even suggested that the absence of the index can be interpreted as evidence that a working exploit will appear in the near future.
')
Solutions like MaxPatrol 8 are able to identify computers vulnerable to certain attacks on a network. Other solutions, such as PT NAD, themselves detect similar attacks. To make this possible, it is necessary to describe both the rules for identifying vulnerabilities in products and the rules for detecting attacks on these products. In turn, in order to make this possible, it is necessary for each individual vulnerability to figure out the vector, method and conditions of its operation, that is, literally all the details and nuances associated with the operation. It requires a much more complete and deeper understanding than that which can usually be compiled from the descriptions on vendor sites or in CVE, like:

Vulnerability is manifested for the reason that the operating system incorrectly processes objects in memory.

So, to add to the company's products the rules for detecting attacks on a new vulnerability in DHCP, as well as the rules for identifying devices susceptible to it, it was necessary to understand the details. In the case of binary vulnerabilities, patch-diff is often used to gain insight into the underlying errors, that is, a comparison of changes made to the binary code of an application, library, or operating system kernel by a specific patch, update, correcting this error. But the first stage is always a reconnaissance.

Note : To go directly to the description of the vulnerability, bypassing its underlying DHCP concepts, you can skip the first few pages and refer directly to the “DecodeDomainSearchListData Function” section.

Reconnaissance


Contact the search engine and view all the currently known details of the vulnerability. At this time, the details of the minimum, and they are all free processing of information, gleaned from the original publication on the MSRC website. This situation is quite typical for errors found by Microsoft experts during an internal audit.

From the publication, we find out that we are confronted with a memory corruption vulnerability, which is contained in both client and server systems Windows 10 version 1803 and manifests itself at the moment when the attacker sends in a special way the generated responses to the DHCP client. After a couple of days from that moment, exploitation indexes will also appear on the page:



As you can see, the MSRC has been rated “2 - Exploitation Less Likely”. This means that the error with a high probability is either non-exploitable at all, or the operation is fraught with such difficulties, overcoming of which will require too much labor. It should be recognized that Microsoft does not tend to underestimate such estimates. This is partly affected by the risk of reputational losses, and partly by some independence of the response center within the company. Therefore, suppose: once in the report, the threat of exploitation is indicated as unlikely, for sure it is. Actually, this could have completed the analysis, but it would not be superfluous to double-check and at least find out what was the vulnerability. In the end, despite all indisputable individuality, mistakes tend to repeat themselves and manifest themselves in other places.

From the same page, download the security update patch provided as a .msu archive, unpack it and look for files most likely related to processing DHCP responses on the client side. Recently, it has become much more difficult to do this, since updates were not delivered as separate packages, correcting specific errors, but as one cumulative package, including all monthly corrections. This greatly increased the extra noise, that is, changes that were not related to our task.

Among the entire set of files, the search reveals several libraries suitable for the filter, which we compare with their versions on the unpatched system. The dhcpcore.dll library looks the most promising. At the same time, BinDiff produces minimal changes:



Actually, other than cosmetic changes made to a single function - DecodeDomainSearchListData. If you are familiar with DHCP and its not-too-used options, you can already assume that this function handles the list. If not, then go to the second stage - the study of the protocol.

DHCP and its options


DHCP ( RFC 2131 | wiki ) is an extensible protocol whose ability to replenish its capabilities is provided by the options field. Each option is described by a unique tag (number, identifier), the size occupied by the data contained in the option, and the data itself. This practice is typical of network protocols, and one of these “implanted” options in the protocol is the Domain Search Option, described in RFC 3397 . It allows the DHCP server to set standard domain name terminations on clients that will be used as DNS suffixes for a connection that is configured in this way.

Let, for example, the following endings of names be given on our client:

.microsoft.com .wikipedia.org 



Then, in any attempt to determine the address by the domain name, the DNS queries will be substituted with the suffixes from this list in turn until a successful mapping is found. For example, if a user entered ru in the browser address bar, then DNS queries will be generated first for ru.microsoft.com, then for ru.wikipedia.org:



In fact, modern browsers are too smart, and therefore for names that are not similar to the FQDN, they react by redirecting to a search engine. Therefore, below we enclose a conclusion of less spoiled utilities:



It might seem to the reader that this is a vulnerability, because the ability to replace DNS suffixes using a DHCP server, which any device on the network can identify itself, poses a threat to clients requesting any kind of network parameters via DHCP. . But no: as follows from the RFC, this is considered to be quite legitimate, documented behavior. Actually, the DHCP server is essentially one of those trusted components that can have a strong impact on the devices accessing them.

Domain Search option


Domain Search Option is numbered 0x77 (119). Like all options, it is encoded with a single-byte tag with an option number. Like most other options, right after the tag is the one-byte size of the data following the size. Option instances may appear in a DHCP message more than once. In this case, the data from all such sections are concatenated in the sequence in which they appear in the message.



In the example presented, taken from RFC 3397 , the data is divided into three sections, each 9 bytes. As it is easy to understand from the image, the names of subdomains in the full domain name are encoded with a single-byte name length, immediately followed by the name itself. The encoding of a fully qualified domain name ends with a null byte (that is, a subdomain name size of zero).

In addition, the option uses the simplest method of data compression, or rather, just reparse points. Instead of the domain name size, the field may contain the value 0xc0. Then the next byte specifies the offset relative to the beginning of the option data by which the end of the domain name should be searched.

Thus, in this example, a list of two domain suffixes is encoded:

 .eng.apple.com .marketing.apple.com 

DecodeDomainSearchListData function


So, the DHCP option number 0x77 (119) allows the server to configure DNS suffixes on clients. But not on machines with Windows operating systems. Microsoft systems have traditionally ignored this option, so historically, the end of DNS names, if necessary, has been rolled through group policies. This continued until recently, when in the next release of Windows 10, version 1803, processing for the Domain Search Option was added. Judging by the name of the function in dhcpcore.dll, to which changes have been made, it is in the added handler that the error in question lies.

Getting Started. We brush a little code and find out the following. The DecodeDomainSearchListData procedure, in full accordance with the name, decodes data from the Domain Search Option of a message received from the server. At the input, it receives a data array packed by the method described in the previous paragraph, and at the output it generates a null-terminated string containing a list of domain name endings, separated by commas. For example, the data from the example above, this function converts to a string:

  eng.apple.com,marketing.apple.com 

Called DecodeDomainSearchListData from the UpdateDomainSearchOption procedure, which writes the returned list to the "DhcpDomainSearchList" registry key:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{INTERFACE_GUID}\
storing the basic parameters of a specific network interface.



The DecodeDomainSearchListData function performs in two passes. On the first pass, it performs all actions, except for writing to the output buffer. Thus, the first pass is devoted to calculating the amount of memory required to accommodate the returned data. In the second pass, memory is already allocated for this data and the allocated memory is filled. The function is rather small, about 250 instructions, and its main job is to process each of the three possible variants of the symbol represented in the incoming stream: 1) 0x00, 2) 0xc0, or 3) all other values. Estimated correction of a DHCP error is, by and large, reduced to adding a check of the size of the resulting buffer at the beginning of the second pass. If this size is zero, then the memory for the buffer is not allocated and the function immediately terminates execution and returns an error:



It turns out, the vulnerability manifests itself in cases where the size of the target buffer is equal to zero. In this case, at the very beginning of execution, the function checks incoming data, the size of which cannot be less than two bytes. Therefore, for operation, it is required to select the thus formed non-empty domain suffix option so that the size of the output buffer is zero.

Exploitation


The first thing that comes to mind is that you can use the previously described reparse points to ensure that non-empty data at the input generates an empty string at the output:



A server configured to send an option with such content in the response will indeed cause an access violation on non-upgraded clients. This happens for the following reason. At each step, when the function parses a part of the fully qualified domain name, it copies it into the target buffer and puts a period after it. In the example taken from the RFC, the data will be copied to the buffer in the following order:

 1). eng. 2). eng.apple. 3). eng.apple.com. 

Then, when in the input data there is a zero domain size, the function replaces the previous character of the target buffer from a dot to a comma:

 4). eng.apple.com, 

and continues to parse:

 5). eng.apple.com,marketing. 6). eng.apple.com,marketing.apple. 7). eng.apple.com,marketing.apple.com. 8). eng.apple.com,marketing.apple.com, 

At the end of the input data, it remains only to replace the last comma with a null character and it turns out to be a line ready for entry into the registry:

 9). eng.apple.com,marketing.apple.com 

What happens when an attacker sends a buffer formed in the manner described above? If you look at the example, you can see that the list contained in it consists of one element - an empty string. On the first pass, the function calculates the size of the output data. Since the data does not contain a single non-zero domain name, the size is zero.

On the second pass, a block of dynamic memory is allocated for placing data in it and copying the data itself. But the parse function immediately encounters a null character, meaning the end of the domain name, and therefore, as was said, replaces the previous character from a dot to a comma. And here we face a problem. The iterator of the target buffer is in zero position. No previous character. The previous character belongs to the header of the dynamic memory block. And this very character will be replaced with 0x2c, that is, with a comma.

However, this happens only on 32-bit systems. Using unsigned int to store the current position of the target buffer iterator makes its own adjustments to processing on x64-systems. Let's pay closer attention to the piece of code responsible for writing a comma to the buffer:



Subtracting a unit from the current position is done using the 32-bit eax register, while when addressing the buffer, the code refers to the full 64-bit rax register. In the AMD64 architecture, any operations with 32-bit registers reset the most significant part of the register. This means that in the rax register, which previously contained zero, after subtraction, not the value –1, but 0xffffffff will be stored. Therefore, on 64-bit systems, the value 0x2c will be written to the address buf [0xffffffff], that is, far beyond the boundaries of the memory allocated for the buffer.

The obtained data are in good agreement with Microsoft’s operational rating, because in order to exploit this vulnerability, an attacker needs to learn how to remotely perform heap spraying on a DHCP client and at the same time have sufficient control over the dynamic memory allocation in order to record preset values, namely, a comma and zero byte, was produced in the prepared address and led to controlled negative consequences. Otherwise, writing data to an unreconciled address will have the effect of dropping the svchost.exe process along with all the services that are hosted on it at that moment - and then restarting these services with the operating system. The fact that attackers in certain conditions can also use for their own benefit.

That, it would seem, is all that can be said about the error under investigation. Only remains the feeling that this is not the end. As if we did not consider all the options. There must be something more that is hidden in these lines.

CVE-2019-0726


Probably the way it is. If you look closely at the type of data provoking an error and compare it with how exactly this error occurs, you will notice that the list of domain names can be changed so that the resulting buffer will be non-zero size, but trying to write beyond it is all same will be produced. To do this, the first item in the list must be an empty string, and all others may contain normal domain endings. For example:



The presented option includes two elements. The first domain suffix is ​​empty, it immediately ends with a null byte. The second suffix is ​​.ru. The calculated size of the string at the output will be equal to three bytes, which will allow to overcome the check on the voidness of the target buffer imposed by the January update. At the same time, a zero at the very beginning of the data will force the function to write a comma to the resulting string in the resulting character, but since the current position of the iterator in the string is zero, as in the case discussed earlier, writing will occur again outside the allocated buffer.

Now it is necessary to confirm the obtained theoretical results in practice. We simulate a situation in which the DHCP server sends a message with the option presented in response to a request from the client, and immediately catch an exception when trying to write a comma to the position 0xffffffff of the buffer allocated for the resulting string:



Here, the r8 register contains a pointer to the incoming options, rdi is the address of the allocated target buffer, and rax is the position in this buffer to which the character is to be written. We obtained such results on a completely updated system (as of January 2019).

We write about the problem found in Microsoft and ... they lose the letter. Yes, this sometimes happens even with reputable vendors. No system is perfect, and in this case it is necessary to look for other ways of communication. Therefore, a week later, without even receiving an auto reply during this time, we contact directly the manager via Twitter and, after a few days of analyzing the application, we find out that the details sent have nothing to do with CVE-2019-0547 and represent an independent vulnerability for which New CVE ID. A month later, in March, the corresponding correction is released, and the error gets the number CVE-2019-0726 .

This is how it is sometimes possible in attempts to understand the details of a 1-day vulnerability to accidentally detect 0-day, simply by trusting your intuition.

Author : Mikhail Tsvetkov, Specialist, Application Technologies Analysis Department, Positive Technologies.

Source: https://habr.com/ru/post/448378/


All Articles