rfc9267.original | rfc9267.txt | |||
---|---|---|---|---|
Independent Submission S. Dashevskyi | Independent Submission S. Dashevskyi | |||
Internet-Draft D. dos Santos | Request for Comments: 9267 D. dos Santos | |||
Intended status: Informational J. Wetzels | Category: Informational J. Wetzels | |||
Expires: November 18, 2022 A. Amri | ISSN: 2070-1721 A. Amri | |||
Forescout Technologies | Forescout Technologies | |||
May 18, 2022 | July 2022 | |||
Common implementation anti-patterns related | Common Implementation Anti-Patterns Related to Domain Name System (DNS) | |||
to Domain Name System (DNS) resource record (RR) processing | Resource Record (RR) Processing | |||
draft-dashevskyi-dnsrr-antipatterns-06 | ||||
Abstract | Abstract | |||
This memo describes common vulnerabilities related to Domain Name | This memo describes common vulnerabilities related to Domain Name | |||
System (DNS) response record (RR) processing as seen in several DNS | System (DNS) resource record (RR) processing as seen in several DNS | |||
client implementations. These vulnerabilities may lead to successful | client implementations. These vulnerabilities may lead to successful | |||
Denial-of-Service and Remote Code Execution attacks against the | Denial-of-Service and Remote Code Execution attacks against the | |||
affected software. Where applicable, violations of RFC 1035 are | affected software. Where applicable, violations of RFC 1035 are | |||
mentioned. | mentioned. | |||
Status of This Memo | Status of This Memo | |||
This Internet-Draft is submitted in full conformance with the | This document is not an Internet Standards Track specification; it is | |||
provisions of BCP 78 and BCP 79. | published for informational purposes. | |||
Internet-Drafts are working documents of the Internet Engineering | ||||
Task Force (IETF). Note that other groups may also distribute | ||||
working documents as Internet-Drafts. The list of current Internet- | ||||
Drafts is at https://datatracker.ietf.org/drafts/current/. | ||||
Internet-Drafts are draft documents valid for a maximum of six months | This is a contribution to the RFC Series, independently of any other | |||
and may be updated, replaced, or obsoleted by other documents at any | RFC stream. The RFC Editor has chosen to publish this document at | |||
time. It is inappropriate to use Internet-Drafts as reference | its discretion and makes no statement about its value for | |||
material or to cite them other than as "work in progress." | implementation or deployment. Documents approved for publication by | |||
the RFC Editor are not candidates for any level of Internet Standard; | ||||
see Section 2 of RFC 7841. | ||||
This Internet-Draft will expire on November 18, 2022. | Information about the current status of this document, any errata, | |||
and how to provide feedback on it may be obtained at | ||||
https://www.rfc-editor.org/info/rfc9267. | ||||
Copyright Notice | Copyright Notice | |||
Copyright (c) 2022 IETF Trust and the persons identified as the | Copyright (c) 2022 IETF Trust and the persons identified as the | |||
document authors. All rights reserved. | document authors. All rights reserved. | |||
This document is subject to BCP 78 and the IETF Trust's Legal | This document is subject to BCP 78 and the IETF Trust's Legal | |||
Provisions Relating to IETF Documents | Provisions Relating to IETF Documents | |||
(http://trustee.ietf.org/license-info) in effect on the date of | (https://trustee.ietf.org/license-info) in effect on the date of | |||
publication of this document. Please review these documents | publication of this document. Please review these documents | |||
carefully, as they describe your rights and restrictions with respect | carefully, as they describe your rights and restrictions with respect | |||
to this document. | to this document. | |||
Table of Contents | Table of Contents | |||
1. Introduction | 1. Introduction | |||
2. Compression Pointer and Offset Validation | 2. Compression Pointer and Offset Validation | |||
3. Label and Name Length Validation | 3. Label and Name Length Validation | |||
4. Null-terminator Placement Validation | 4. Null-Terminator Placement Validation | |||
5. Response Data Length Validation | 5. Response Data Length Validation | |||
6. Record Count Validation | 6. Record Count Validation | |||
7. Security Considerations | 7. Security Considerations | |||
8. IANA Considerations | 8. IANA Considerations | |||
9. References | 9. References | |||
9.1. Normative References | 9.1. Normative References | |||
9.2. Informative References | 9.2. Informative References | |||
Acknowledgements | Acknowledgements | |||
Authors' Addresses | Authors' Addresses | |||
1. Introduction | 1. Introduction | |||
Recently, there have been major vulnerabilities on DNS | Major vulnerabilities in DNS implementations recently became evident | |||
implementations that raised attention to this protocol as an | and raised attention to this protocol as an important attack vector, | |||
important attack vector, such as [SIGRED], [SADDNS], and | as discussed in [SIGRED], [SADDNS], and [DNSPOOQ], the latter being a | |||
[DNSPOOQ] - a set of 7 critical issues affecting the DNS | set of 7 critical issues affecting the DNS forwarder "dnsmasq". | |||
forwarder "dnsmasq". | ||||
The authors of this memo have analyzed the DNS client implementations | The authors of this memo have analyzed the DNS client implementations | |||
of several major TCP/IP protocol stacks and found a set of | of several major TCP/IP protocol stacks and found a set of | |||
vulnerabilities that share common implementation flaws | vulnerabilities that share common implementation flaws (anti- | |||
(anti-patterns). These flaws are related to processing DNS RRs | patterns). These flaws are related to processing DNS resource | |||
(discussed in [RFC1035]) and may lead to critical security | records (RRs) (discussed in [RFC1035]) and may lead to critical | |||
vulnerabilities. | security vulnerabilities. | |||
While implementation flaws may differ from one software project to | While implementation flaws may differ from one software project to | |||
another, these anti-patterns are highly likely to span across | another, these anti-patterns are highly likely to span multiple | |||
multiple implementations. In fact, one of the first CVEs related to | implementations. In fact, one of the first "Common Vulnerabilities | |||
one of the anti-patterns [CVE-2000-0333] dates back to the year 2000. | and Exposures" (CVE) documents related to one of the anti-patterns | |||
The observations are not limited to DNS client implementations. | [CVE-2000-0333] dates back to the year 2000. The observations are | |||
Any software that processes DNS RRs may be affected, such as | not limited to DNS client implementations. Any software that | |||
firewalls, intrusion detection systems, or general purpose DNS packet | processes DNS RRs may be affected, such as firewalls, intrusion | |||
dissectors (e.g., [CVE-2017-9345] in Wireshark). Similar issues may | detection systems, or general-purpose DNS packet dissectors (e.g., | |||
also occur in DNS-over-HTTPS [RFC8484] and DNS-over-TLS [RFC7858] | the DNS dissector in Wireshark; see [CVE-2017-9345]). Similar issues | |||
implementations. However, any implementation that deals with the DNS | may also occur in DNS-over-HTTPS [RFC8484] and DNS-over-TLS [RFC7858] | |||
wire format is subject to the considerations discussed in this draft. | implementations. However, any implementation that deals with the DNS | |||
wire format is subject to the considerations discussed in this | ||||
document. | ||||
[COMP-DRAFT] and [RFC5625] briefly mention some of these | [DNS-COMPRESSION] and [RFC5625] briefly mention some of these anti- | |||
anti-patterns, but the main purpose of this memo is to provide | patterns, but the main purpose of this memo is to provide technical | |||
technical details behind these anti-patterns, so that the common | details behind these anti-patterns, so that the common mistakes can | |||
mistakes can be eradicated. | be eradicated. | |||
We provide general recommendations on mitigating the anti-patterns. | We provide general recommendations on mitigating the anti-patterns. | |||
We also suggest that all implementations should drop | We also suggest that all implementations should drop malicious/ | |||
malicious/malformed DNS replies and log them (optionally). | malformed DNS replies and (optionally) log them. | |||
2. Compression Pointer and Offset Validation | 2. Compression Pointer and Offset Validation | |||
[RFC1035] defines the DNS message compression scheme that can be used | [RFC1035] defines the DNS message compression scheme that can be used | |||
to reduce the size of messages. When it is used, an entire domain | to reduce the size of messages. When it is used, an entire domain | |||
name or several name labels are replaced with a (compression) pointer | name or several name labels are replaced with a (compression) pointer | |||
to a prior occurrence of the same name. | to a prior occurrence of the same name. | |||
The compression pointer is a combination of two octets: the two most | The compression pointer is a combination of two octets: the two most | |||
significant bits are set to 1, and the remaining 14 bits are the | significant bits are set to 1, and the remaining 14 bits are the | |||
OFFSET field. This field specifies the offset from the beginning of | OFFSET field. This field specifies the offset from the beginning of | |||
the DNS header, at which another domain name or label is located: | the DNS header, at which another domain name or label is located: | |||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |||
| 1 1| OFFSET | | | 1 1| OFFSET | | |||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |||
The message compression scheme explicitly allows a domain name to be | The message compression scheme explicitly allows a domain name to be | |||
represented as: (1) a sequence of unpacked labels ending with a zero | represented as one of the following: (1) a sequence of unpacked | |||
octet; (2) a pointer; (3) a sequence of labels ending with a pointer. | labels ending with a zero octet, (2) a pointer, or (3) a sequence of | |||
labels ending with a pointer. | ||||
However, [RFC1035] does not explicitly state that blindly following | However, [RFC1035] does not explicitly state that blindly following | |||
compression pointers of any kind can be harmful [COMP-DRAFT], as we | compression pointers of any kind can be harmful [DNS-COMPRESSION], as | |||
could not have had any assumptions about various implementations | we could not have had any assumptions about various implementations | |||
that would follow. | that would follow. | |||
Yet, any DNS packet parser that attempts to decompress domain names | Yet, any DNS packet parser that attempts to decompress domain names | |||
without validating the value of OFFSET is likely susceptible to | without validating the value of OFFSET is likely susceptible to | |||
memory corruption bugs and buffer overruns. These bugs allow for easy | memory corruption bugs and buffer overruns. These bugs make it | |||
Denial-of-Service attacks, and may result in successful Remote Code | easier to perform Denial-of-Service attacks and may result in | |||
Execution attacks. | successful Remote Code Execution attacks. | |||
Pseudocode that illustrates a typical example of a broken domain name | Pseudocode that illustrates a typical example of a broken domain name | |||
parsing implementation is shown below (Snippet 1): | parsing implementation is shown below (Figure 1): | |||
1:decompress_domain_name(*name, *dns_payload) { | 1: decompress_domain_name(*name, *dns_payload) { | |||
2: | 2: | |||
3: name_buffer[255]; | 3: name_buffer[255]; | |||
4: copy_offset = 0; | 4: copy_offset = 0; | |||
5: | 5: | |||
6: label_len_octet = name; | 6: label_len_octet = name; | |||
7: dest_octet = name_buffer; | 7: dest_octet = name_buffer; | |||
8: | 8: | |||
9: while (*label_len_octet != 0x00) { | 9: while (*label_len_octet != 0x00) { | |||
10: | 10: | |||
11: if (is_compression_pointer(*label_len_octet)) { | 11: if (is_compression_pointer(*label_len_octet)) { | |||
12: ptr_offset = get_offset(label_len_octet, | 12: ptr_offset = get_offset(label_len_octet, | |||
label_len_octet+1); | label_len_octet+1); | |||
13: label_len_octet = dns_payload + ptr_offset + 1; | 13: label_len_octet = dns_payload + ptr_offset + 1; | |||
14: } | 14: } | |||
15: | 15: | |||
16: else { | 16: else { | |||
17: length = *label_len_octet; | 17: length = *label_len_octet; | |||
18: copy(dest_octet + copy_offset, | 18: copy(dest_octet + copy_offset, | |||
label_len_octet+1, *length); | label_len_octet+1, *length); | |||
19: | 19: | |||
20: copy_offset += length; | 20: copy_offset += length; | |||
21: label_len_octet += length + 1; | 21: label_len_octet += length + 1; | |||
22: } | 22: } | |||
23: | 23: | |||
24: } | 24: } | |||
25:} | 25: } | |||
Snippet 1 - A broken implementation of a function | ||||
that is used for decompressing DNS domain names (pseudocode) | Figure 1: A Broken Implementation of a Function That Is Used for | |||
Decompressing DNS Domain Names (Pseudocode) | ||||
Such implementations typically have a dedicated function for | Such implementations typically have a dedicated function for | |||
decompressing domain names (for example, see [CVE-2020-24338] and | decompressing domain names (for example, see [CVE-2020-24338] and | |||
[CVE-2020-27738]). Among other parameters, these functions may | [CVE-2020-27738]). Among other parameters, these functions may | |||
accept a pointer to the beginning of the first name label within a | accept a pointer to the beginning of the first name label within an | |||
RR ("name") and a pointer to the beginning of the DNS payload to be | RR ("name") and a pointer to the beginning of the DNS payload to be | |||
used as a starting point for the compression pointer | used as a starting point for the compression pointer ("dns_payload"). | |||
("dns_payload"). The destination buffer for the domain name | The destination buffer for the domain name ("name_buffer") is | |||
("name_buffer") is typically limited to 255 bytes as per | typically limited to 255 bytes as per [RFC1035] and can be allocated | |||
[RFC1035] and can be allocated either in the stack or in the heap | either in the stack or in the heap memory region. | |||
memory region. | ||||
The code of the function at Snippet 1 reads the domain name | The code of the function in Figure 1 reads the domain name label by | |||
label-by-label from a RR until it reaches the NUL octet ("0x00") that | label from an RR until it reaches the NUL octet ("0x00") that | |||
signifies the end of a domain name. If the current label length octet | signifies the end of a domain name. If the current label length | |||
("label_len_octet") is a compression pointer, the code extracts the | octet ("label_len_octet") is a compression pointer, the code extracts | |||
value of the compression offset and uses it to "jump" to another | the value of the compression offset and uses it to "jump" to another | |||
label length octet. If the current label length octet is not a | label length octet. If the current label length octet is not a | |||
compression pointer, the label bytes will be copied into the name | compression pointer, the label bytes will be copied into the name | |||
buffer, and the number of bytes copied will correspond to the value | buffer, and the number of bytes copied will correspond to the value | |||
of the current label length octet. After the copy operation, the code | of the current label length octet. After the copy operation, the | |||
will move on to the next label length octet. | code will move on to the next label length octet. | |||
The first issue with this implementation is due to unchecked | The first issue with this implementation is due to unchecked | |||
compression offset values. The second issue is due to the absence of | compression offset values. The second issue is due to the absence of | |||
checks that ensure that a pointer will eventually arrive at an | checks that ensure that a pointer will eventually arrive at a | |||
decompressed domain label. We describe these issues in more detail | decompressed domain label. We describe these issues in more detail | |||
below. | below. | |||
[RFC1035] states that "... [compression pointer is] a pointer to a | [RFC1035] states that a compression pointer is "a pointer to a prior | |||
prior occurrence of the same name". Also, according to [RFC1035], | occurance [sic] of the same name." Also, according to [RFC1035], the | |||
the maximum size of DNS packets that can be sent over the UDP | maximum size of DNS packets that can be sent over UDP is limited to | |||
protocol is limited to 512 octets. | 512 octets. | |||
The pseudocode at Snippet 1 violates these constraints, as it will | The pseudocode in Figure 1 violates these constraints, as it will | |||
accept a compression pointer that forces the code to read out of the | accept a compression pointer that forces the code to read outside the | |||
bounds of a DNS packet. For instance, the compression pointer of | bounds of a DNS packet. For instance, a compression pointer set to | |||
"0xffff" will produce the offset of 16383 octets, which is most | "0xffff" will produce an offset of 16383 octets, which is most | |||
definitely pointing to a label length octet somewhere past the | definitely pointing to a label length octet somewhere past the bounds | |||
original DNS packet. Supplying such offset values will most likely | of the original DNS packet. Supplying such offset values will most | |||
cause memory corruption issues and may lead to Denial-of-Service | likely cause memory corruption issues and may lead to Denial-of- | |||
conditions (e.g., a Null pointer dereference after "label_len_octet" | Service conditions (e.g., a Null pointer dereference after | |||
is set to an invalid address in memory). As an additional example, | "label_len_octet" is set to an invalid address in memory). For | |||
see [CVE-2020-25767], [CVE-2020-24339], and [CVE-2020-24335]. | additional examples, see [CVE-2020-25767], [CVE-2020-24339], and | |||
[CVE-2020-24335]. | ||||
The pseudocode at Snippet 1 allows for jumping from a compression | The pseudocode in Figure 1 allows jumping from a compression pointer | |||
pointer to another compression pointer and it does not restrict the | to another compression pointer and does not restrict the number of | |||
number of such jumps. That is, if a label length octet which is | such jumps. That is, if a label length octet that is currently being | |||
currently being parsed is a compression pointer, the code will | parsed is a compression pointer, the code will perform a jump to | |||
perform a jump to another label, and if that other label is a | another label, and if that other label is a compression pointer as | |||
compression pointer as well, the code will perform another jump, and | well, the code will perform another jump, and so forth until it | |||
so forth until it reaches an decompressed label. This may lead to | reaches a decompressed label. This may lead to unforeseen side | |||
unforeseen side-effects that result in security issues. | effects that result in security issues. | |||
Consider the excerpt from a DNS packet illustrated below: | Consider the DNS packet excerpt illustrated below: | |||
+----+----+----+----+----+----+----+----+----+----+----+----+ | +----+----+----+----+----+----+----+----+----+----+----+----+ | |||
+0x00 | ID | FLAGS | QCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | | +0x00 | ID | FLAGS | QDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | | |||
+----+----+----+----+----+----+----+----+----+----+----+----+ | +----+----+----+----+----+----+----+----+----+----+----+----+ | |||
->+0x0c |0xc0|0x0c| TYPE | CLASS |0x04| t | e | s | t |0x03| | ->+0x0c |0xc0|0x0c| TYPE | CLASS |0x04| t | e | s | t |0x03| | |||
| +----+--|-+----+----+----+----+----+----+----+----+----+----+ | | +----+--|-+----+----+----+----+----+----+----+----+----+----+ | |||
| +0x18 | c | o| | m |0x00| TYPE | CLASS | ................ | | | +0x18 | c | o| | m |0x00| TYPE | CLASS | ................ | | |||
| +----+--|-+----+----+----+----+----+----+----+----+----+----+ | | +----+--|-+----+----+----+----+----+----+----+----+----+----+ | |||
| | | | | | |||
---------------- | ----------------- | |||
The packet begins with a DNS header at the offset +0x00, and its DNS | The packet begins with a DNS header at offset +0x00, and its DNS | |||
payload contains several RRs. The first RR begins at the offset of | payload contains several RRs. The first RR begins at an offset of 12 | |||
12 octets (+0xc0) and its first label length octet is set to the | octets (+0x0c); its first label length octet is set to the value | |||
value "0xc0", which indicates that it is a compression pointer. The | "0xc0", which indicates that it is a compression pointer. The | |||
compression pointer offset is computed from the two octets "0xc00c" | compression pointer offset is computed from the two octets "0xc00c" | |||
and it is equal to 12. Since the broken implementation at Snippet 1 | and is equal to 12. Since the broken implementation in Figure 1 | |||
follows this offset value blindly, the pointer will jump back to | follows this offset value blindly, the pointer will jump back to the | |||
the first octet of the first RR (+0xc0) over and over again. The | first octet of the first RR (+0x0c) over and over again. The code in | |||
code at Snippet 1 will enter an infinite loop state, since it will | Figure 1 will enter an infinite-loop state, since it will never leave | |||
never leave the "TRUE" branch of the "while" loop. | the "TRUE" branch of the "while" loop. | |||
Apart from achieving infinite loops, the implementation flaws at | Apart from achieving infinite loops, the implementation flaws in | |||
Snippet 1 make it possible to achieve various pointer loops that have | Figure 1 make it possible to achieve various pointer loops that have | |||
other effects. For instance, consider the DNS packet excerpt shown | other undesirable effects. For instance, consider the DNS packet | |||
below: | excerpt shown below: | |||
+----+----+----+----+----+----+----+----+----+----+----+----+ | +----+----+----+----+----+----+----+----+----+----+----+----+ | |||
+0x00 | ID | FLAGS | QCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | | +0x00 | ID | FLAGS | QDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | | |||
+----+----+----+----+----+----+----+----+----+----+----+----+ | +----+----+----+----+----+----+----+----+----+----+----+----+ | |||
->+0x0c |0x04| t | e | s | t |0xc0|0x0c| ...................... | | ->+0x0c |0x04| t | e | s | t |0xc0|0x0c| ...................... | | |||
| +----+----+----+----+----+----+--|-+----+----+----+----+----+ | | +----+----+----+----+----+----+--|-+----+----+----+----+----+ | |||
| | | | | | |||
----------------------------------------- | ------------------------------------------ | |||
With such a domain name, the implementation at Snippet 1 will first | With such a domain name, the implementation in Figure 1 will first | |||
copy the domain label at the offset "0xc0" ("test"), then it will | copy the domain label at offset "0xc0" ("test"); it will then fetch | |||
fetch the next label length octet, which is a compression pointer | the next label length octet, which happens to be a compression | |||
("0xc0"). The compression pointer offset is computed from the two | pointer ("0xc0"). The compression pointer offset is computed from | |||
octets "0xc00c" and is equal to 12 octets. The code will jump back | the two octets "0xc00c" and is equal to 12 octets. The code will | |||
at the offset "0xc0" where the first label "test" is located. The | jump back to offset "0xc0" where the first label "test" is located. | |||
code will again copy the "test" label, and jump back to it, | The code will again copy the "test" label and then jump back to it, | |||
following the compression pointer, over and over again. | following the compression pointer, over and over again. | |||
Snippet 1 does not contain any logic that restricts multiple jumps | Figure 1 does not contain any logic that restricts multiple jumps | |||
from the same compression pointer and does not ensure that no more | from the same compression pointer and does not ensure that no more | |||
than 255 octets are copied into the name buffer ("name_buffer"). In | than 255 octets are copied into the name buffer ("name_buffer"). In | |||
fact, the code will continue to write the label "test" into it, | fact, | |||
overwriting the name buffer and the stack of the heap metadata. In | ||||
fact, attackers would have a significant degree of freedom in | ||||
constructing shell-code, since they can create arbitrary copy chains | ||||
with various combinations of labels and compression pointers. | ||||
Therefore, blindly following compression pointers may not only lead | * the code will continue to write the label "test" into it, | |||
to Denial-of-Service as pointed by [COMP-DRAFT], but also to | overwriting the name buffer and the stack of the heap metadata. | |||
successful Remote Code Execution attacks, as there may be other | ||||
implementation issues present within the corresponding code. | ||||
Some implementations may not follow [RFC1035], which states: "the | * attackers would have a significant degree of freedom in | |||
first two bits [of a compression pointer octet] are ones; this allows | constructing shell code, since they can create arbitrary copy | |||
a pointer to be distinguished from a label, the label must begin | chains with various combinations of labels and compression | |||
with two zero bits because labels are restricted to 63 octets or less | pointers. | |||
(the 10 and 01 combinations are reserved for future use)". Snippets 2 | ||||
and 3 show pseudocode that implements two functions that check | Therefore, blindly following compression pointers may lead not only | |||
whether a given octet is a compression pointer: correct and incorrect | to Denial-of-Service conditions, as pointed out by [DNS-COMPRESSION], | |||
implementations respectively. | but also to successful Remote Code Execution attacks, as there may be | |||
other implementation issues present within the corresponding code. | ||||
Some implementations may not follow [RFC1035], which states: | ||||
| The first two bits are ones. This allows a pointer to be | ||||
| distinguished from a label, since the label must begin with two | ||||
| zero bits because labels are restricted to 63 octets or less. | ||||
| (The 10 and 01 combinations are reserved for future use.) | ||||
Figures 2 and 3 show pseudocode that implements two functions that | ||||
check whether a given octet is a compression pointer; Figure 2 shows | ||||
a correct implementation, and Figure 3 shows an incorrect (broken) | ||||
implementation. | ||||
1: unsigned char is_compression_pointer(*octet) { | 1: unsigned char is_compression_pointer(*octet) { | |||
2: if ((*octet & 0xc0) == 0xc0) | 2: if ((*octet & 0xc0) == 0xc0) | |||
3: return true; | 3: return true; | |||
4: } else { | 4: } else { | |||
5: return false; | 5: return false; | |||
6: } | 6: } | |||
7: } | 7: } | |||
Snippet 2 - Correct compression pointer check | ||||
Figure 2: Correct Compression Pointer Check | ||||
1: unsigned char is_compression_pointer(*octet) { | 1: unsigned char is_compression_pointer(*octet) { | |||
2: if (*octet & 0xc0) { | 2: if (*octet & 0xc0) { | |||
3: return true; | 3: return true; | |||
4: } else { | 4: } else { | |||
5: return false; | 5: return false; | |||
6: } | 6: } | |||
7: } | 7: } | |||
Snippet 3 - Broken compression pointer check | ||||
The correct implementation (Snippet 2) ensures that the two most | Figure 3: Broken Compression Pointer Check | |||
The correct implementation (Figure 2) ensures that the two most | ||||
significant bits of an octet are both set, while the broken | significant bits of an octet are both set, while the broken | |||
implementation (Snippet 3) would consider an octet with only one of | implementation (Figure 3) would consider an octet with only one of | |||
the two bits set as a compression pointer. This is likely an | the two bits set to be a compression pointer. This is likely an | |||
implementation mistake rather than an intended violation of | implementation mistake rather than an intended violation of | |||
[RFC1035], because there are no benefits in supporting such | [RFC1035], because there are no benefits in supporting such | |||
compression pointer values. The implementations related to | compression pointer values. The implementations related to | |||
[CVE-2020-24338] and [CVE-2020-24335] had a broken | [CVE-2020-24338] and [CVE-2020-24335] had a broken compression | |||
compression pointer check illustrated on Snippet 3. | pointer check, similar to the code shown in Figure 3. | |||
While incorrect implementations alone do not lead to vulnerabilities, | While incorrect implementations alone do not lead to vulnerabilities, | |||
they may have unforeseen side-effects when combined with other | they may have unforeseen side effects when combined with other | |||
vulnerabilities. For instance, the first octet of the value "0x4130" | vulnerabilities. For instance, the first octet of the value "0x4130" | |||
may be incorrectly interpreted as a label length by a broken | may be incorrectly interpreted as a label length by a broken | |||
implementation. Such label length (65) is invalid, and is larger | implementation. Such a label length (65) is invalid and is larger | |||
than 63 (as per [RFC1035]), and a packet that has this value should | than 63 (as per [RFC1035]); a packet that has this value should be | |||
be discarded. However, the function shown on Snippet 3 will | discarded. However, the function shown in Figure 3 will consider | |||
consider "0x41" to be a valid compression pointer, and the packet | "0x41" to be a valid compression pointer, and the packet may pass the | |||
may pass the validation steps. | validation steps. | |||
This might give an additional leverage for attackers in constructing | This might give attackers additional leverage for constructing | |||
payloads and circumventing the existing DNS packet validation | payloads and circumventing the existing DNS packet validation | |||
mechanisms. | mechanisms. | |||
The first occurrence of a compression pointer in a RR (an octet with | The first occurrence of a compression pointer in an RR (an octet with | |||
the 2 highest bits set to 1) must resolve to an octet within a DNS | the two highest bits set to 1) must resolve to an octet within a DNS | |||
record with the value that is greater than 0 (i.e., it must not be a | record with a value that is greater than 0 (i.e., it must not be a | |||
Null-terminator) and less than 64. The offset at which this octet is | Null-terminator) and less than 64. The offset at which this octet is | |||
located must be smaller than the offset at which the compression | located must be smaller than the offset at which the compression | |||
pointer is located - once an implementation makes sure of that, | pointer is located; once an implementation makes sure of that, | |||
compression pointer loops can never occur. | compression pointer loops can never occur. | |||
In small DNS implementations (e.g., embedded TCP/IP stacks) the | In small DNS implementations (e.g., embedded TCP/IP stacks), support | |||
support for nested compression pointers (pointers that point to a | for nested compression pointers (pointers that point to a compressed | |||
compressed name) should be discouraged: there is very little to be | name) should be discouraged: there is very little to be gained in | |||
gained in terms of performance versus the high possibility of | terms of performance versus the high probability of introducing | |||
introducing errors, such as the ones discussed above. | errors such as those discussed above. | |||
The code that implements domain name parsing should check the offset | The code that implements domain name parsing should check the offset | |||
not only with respect to the bounds of a packet, but also its | with respect to not only the bounds of a packet but also its position | |||
position with respect to the compression pointer in question. A | with respect to the compression pointer in question. A compression | |||
compression pointer must not be "followed" more than once. We have | pointer must not be "followed" more than once. We have seen several | |||
seen several implementations using a check that ensures that | implementations using a check that ensures that a compression pointer | |||
a compression pointer is not followed more than several times. A | is not followed more than several times. A better alternative may be | |||
better alternative may be to ensure that the target of a compression | to ensure that the target of a compression pointer is always located | |||
pointer is always located before the location of the pointer in the | before the location of the pointer in the packet. | |||
packet. | ||||
3. Label and Name Length Validation | 3. Label and Name Length Validation | |||
[RFC1035] restricts the length of name labels to 63 octets, and | [RFC1035] restricts the length of name labels to 63 octets and | |||
lengths of domain names to 255 octets (i.e., label octets and label | lengths of domain names to 255 octets (i.e., label octets and label | |||
length octets). Some implementations do not explicitly enforce these | length octets). Some implementations do not explicitly enforce these | |||
restrictions. | restrictions. | |||
Consider the function "copy_domain_name()" shown on Snippet 4 below. | Consider the function "copy_domain_name()" shown in Figure 4 below. | |||
The function is a variant of the "decompress_domain_name()" function | The function is a variant of the "decompress_domain_name()" function | |||
(Snippet 1), with the difference that it does not support compressed | (Figure 1), with the difference that it does not support compressed | |||
labels, and copies only decompressed labels into the name buffer. | labels and only copies decompressed labels into the name buffer. | |||
1:copy_domain_name(*name, *dns_payload) { | 1: copy_domain_name(*name, *dns_payload) { | |||
2: | 2: | |||
3: name_buffer[255]; | 3: name_buffer[255]; | |||
4: copy_offset = 0; | 4: copy_offset = 0; | |||
5: | 5: | |||
6: label_len_octet = name; | 6: label_len_octet = name; | |||
7: dest_octet = name_buffer; | 7: dest_octet = name_buffer; | |||
8: | 8: | |||
9: while (*label_len_octet != 0x00) { | 9: while (*label_len_octet != 0x00) { | |||
10: | 10: | |||
11: if (is_compression_pointer(*label_len_octet)) { | 11: if (is_compression_pointer(*label_len_octet)) { | |||
12: length = 2; | 12: length = 2; | |||
13: label_len_octet += length + 1; | 13: label_len_octet += length + 1; | |||
14: } | 14: } | |||
15: | 15: | |||
16: else { | 16: else { | |||
17: length = *label_len_octet; | 17: length = *label_len_octet; | |||
18: copy(dest_octet + copy_offset, | 18: copy(dest_octet + copy_offset, | |||
label_len_octet+1, *length); | label_len_octet+1, *length); | |||
19: | 19: | |||
20: copy_offset += length; | 20: copy_offset += length; | |||
21: label_len_octet += length + 1; | 21: label_len_octet += length + 1; | |||
22: } | 22: } | |||
23: | 23: | |||
24: } | 24: } | |||
25:} | 25: } | |||
Snippet 4 - A broken implementation of a function | ||||
that is used for copying non-compressed domain names | Figure 4: A Broken Implementation of a Function That Is Used for | |||
Copying Non-compressed Domain Names | ||||
This implementation does not explicitly check for the value of the | This implementation does not explicitly check for the value of the | |||
label length octet: this value can be up to 255 octets, and a single | label length octet: this value can be up to 255 octets, and a single | |||
label can fill the name buffer. Depending on the memory layout of the | label can fill the name buffer. Depending on the memory layout of | |||
target, how the name buffer is allocated, and the size of the | the target, how the name buffer is allocated, and the size of the | |||
malformed packet, it is possible to trigger various memory corruption | malformed packet, it is possible to trigger various memory corruption | |||
issues. | issues. | |||
Both Snippets 1 and 4 restrict the size of the name buffer to 255 | Both Figures 1 and 4 restrict the size of the name buffer to 255 | |||
octets, however there are no restrictions on the actual number of | octets; however, there are no restrictions on the actual number of | |||
octets that will be copied into this buffer. In this particular case, | octets that will be copied into this buffer. In this particular | |||
a subsequent copy operation (if another label is present in the | case, a subsequent copy operation (if another label is present in the | |||
packet) will write past the name buffer, allowing to overwrite heap | packet) will write past the name buffer, allowing heap or stack | |||
or stack metadata in a controlled manner. | metadata to be overwritten in a controlled manner. | |||
Similar examples of vulnerable implementations can be found in the | Similar examples of vulnerable implementations can be found in the | |||
code relevant to [CVE-2020-25110], [CVE-2020-15795], and | code relevant to [CVE-2020-25110], [CVE-2020-15795], and | |||
[CVE-2020-27009]. | [CVE-2020-27009]. | |||
As a general recommendation, a domain label length octet must have | As a general recommendation, a domain label length octet must have a | |||
the value of more than 0 and less than 64 ([RFC1035]). If this is | value of more than 0 and less than 64 [RFC1035]. If this is not the | |||
not the case, an invalid value has been provided within the packet, | case, an invalid value has been provided within the packet, or a | |||
or a value at an invalid position might be interpreted as a domain | value at an invalid position might be interpreted as a domain name | |||
name length due to other errors in the packet (e.g., misplaced Null- | length due to other errors in the packet (e.g., misplaced Null- | |||
terminator or invalid compression pointer). | terminator or invalid compression pointer). | |||
The number of domain label characters must correspond to the value of | The number of domain label characters must correspond to the value of | |||
the domain label octet. To avoid possible errors when interpreting | the domain label octet. To avoid possible errors when interpreting | |||
the characters of a domain label, developers may consider | the characters of a domain label, developers may consider | |||
recommendations for the preferred domain name syntax outlined in | recommendations for the preferred domain name syntax outlined in | |||
[RFC1035]. | [RFC1035]. | |||
The domain name length must not be more than 255 octets, including | The domain name length must not be more than 255 octets, including | |||
the size of decompressed domain names. The NUL octet ("0x00") must | the size of decompressed domain names. The NUL octet ("0x00") must | |||
be present at the end of the domain name, and within the maximum name | be present at the end of the domain name and must be within the | |||
length (255 octets). | maximum name length (255 octets). | |||
4. Null-terminator Placement Validation | 4. Null-Terminator Placement Validation | |||
A domain name must end with a NUL ("0x00") octet, as per [RFC1035]. | A domain name must end with a NUL ("0x00") octet, as per [RFC1035]. | |||
The implementations shown at Snippets 1 and 4 assume that this is the | The implementations shown in Figures 1 and 4 assume that this is the | |||
case for the RRs that they process, however names that do not have a | case for the RRs that they process; however, names that do not have a | |||
NUL octet placed at the proper position within a RR are not | NUL octet placed at the proper position within an RR are not | |||
discarded. | discarded. | |||
This issue is closely related to the absence of label and name length | This issue is closely related to the absence of label and name length | |||
checks. For example, the logic behind Snippets 1 and 4 will continue | checks. For example, the logic behind Figures 1 and 4 will continue | |||
to copy octets into the name buffer, until a NUL octet is | to copy octets into the name buffer until a NUL octet is encountered. | |||
encountered. This octet can be placed at an arbitrary position | This octet can be placed at an arbitrary position within an RR or not | |||
within a RR, or not placed at all. | placed at all. | |||
Consider a pseudocode function shown on Snippet 5. The function | Consider the pseudocode function shown in Figure 5. The function | |||
returns the length of a domain name ("name") in octets to be used | returns the length of a domain name ("name") in octets to be used | |||
elsewhere (e.g., to allocate a name buffer of a certain size): for | elsewhere (e.g., to allocate a name buffer of a certain size): for | |||
compressed domain names the function returns 2, for decompressed | compressed domain names, the function returns 2; for decompressed | |||
names it returns their true length using the "strlen(3)" function. | names, it returns their true length using the "strlen(3)" function. | |||
1: get_name_length(*name) { | 1: get_name_length(*name) { | |||
2: | 2: | |||
3: if (is_compression_pointer(name)) | 3: if (is_compression_pointer(name)) | |||
4: return 2; | 4: return 2; | |||
5: | 5: | |||
6: name_len = strlen(name) + 1; | 6: name_len = strlen(name) + 1; | |||
7: return name_len; | 7: return name_len; | |||
8: } | 8: } | |||
Snippet 5 - A broken implementation of a function that returns the | ||||
length of a domain name | Figure 5: A Broken Implementation of a Function That Returns the | |||
Length of a Domain Name | ||||
"strlen(3)" is a standard C library function that returns the length | "strlen(3)" is a standard C library function that returns the length | |||
of a given sequence of characters terminated by the NUL ("0x00") | of a given sequence of characters terminated by the NUL ("0x00") | |||
octet. Since this function also expects names to be explicitly | octet. Since this function also expects names to be explicitly Null- | |||
Null-terminated, the return value "strlen(3)" may be also controlled | terminated, the return value "strlen(3)" may also be controlled by | |||
by attackers. Through the value of "name_len" attackers may control | attackers. Through the value of "name_len", attackers may control | |||
the allocation of internal buffers, or specify the number by octets | the allocation of internal buffers or specify the number by octets | |||
copied into these buffers, or other operations depending on the | copied into these buffers, or they may perform other operations, | |||
implementation specifics. | depending on the implementation specifics. | |||
The absence of explicit checks for the NUL octet placement may also | The absence of explicit checks for placement of the NUL octet may | |||
facilitate controlled memory reads and writes. An example of | also facilitate controlled memory reads and writes. An example of | |||
vulnerable implementations can be found in the code relevant to | vulnerable implementations can be found in the code relevant to | |||
[CVE-2020-25107], [CVE-2020-17440], [CVE-2020-24383], and | [CVE-2020-25107], [CVE-2020-17440], [CVE-2020-24383], and | |||
[CVE-2020-27736]. | [CVE-2020-27736]. | |||
As a general recommendation for mitigating such issues, developers | As a general recommendation for mitigating such issues, developers | |||
should never trust user data to be Null-terminated. For example, to | should never trust user data to be Null-terminated. For example, to | |||
fix/mitigate the issue in the code Snippet 5, developers should use | fix/mitigate the issue shown in the code in Figure 5, developers | |||
the function "strnlen(3)" that reads at most X characters(the second | should use the function "strnlen(3)", which reads at most X | |||
argument of the function), and ensure that X is not larger than the | characters (the second argument of the function), and ensure that X | |||
buffer allocated for the name. | is not larger than the buffer allocated for the name. | |||
5. Response Data Length Validation | 5. Response Data Length Validation | |||
As stated in [RFC1035], every RR contains a variable length string of | As stated in [RFC1035], every RR contains a variable-length string of | |||
octets that contains the retrieved resource data (RDATA) (e.g., an IP | octets that contains the retrieved resource data (RDATA) (e.g., an IP | |||
address that corresponds to a domain name in question). The length of | address that corresponds to a domain name in question). The length | |||
the RDATA field is regulated by the resource data length field | of the RDATA field is regulated by the resource data length field | |||
(RDLENGTH), that is also present in an RR. | (RDLENGTH), which is also present in an RR. | |||
Implementations that process RRs may not check for the validity of | Implementations that process RRs may not check for the validity of | |||
the RDLENGTH field value, when retrieving RDATA. Failing to do so may | the RDLENGTH field value when retrieving RDATA. Failing to do so may | |||
lead to out-of-bound read issues (similarly to the label and name | lead to out-of-bound read issues, whose impact may vary | |||
length validation issues discussed in Section 3), whose impact may | significantly, depending on the implementation specifics. We have | |||
vary significantly depending on the implementation specifics. We have | ||||
observed instances of Denial-of-Service conditions and information | observed instances of Denial-of-Service conditions and information | |||
leaks. | leaks. | |||
Therefore, the value of the data length byte in response DNS records | Therefore, the value of the data length byte in response DNS records | |||
(RDLENGTH) must reflect the number of bytes available in the field | (RDLENGTH) must reflect the number of bytes available in the field | |||
that describes the resource (RDATA). The format of RDATA must | that describes the resource (RDATA). The format of RDATA must | |||
conform to the TYPE and CLASS fields of the RR. | conform to the TYPE and CLASS fields of the RR. | |||
Examples of vulnerable implementations can be found in the code | Examples of vulnerable implementations can be found in the code | |||
relevant to [CVE-2020-25108], [CVE-2020-24336], and [CVE-2020-27009]. | relevant to [CVE-2020-25108], [CVE-2020-24336], and [CVE-2020-27009]. | |||
6. Record Count Validation | 6. Record Count Validation | |||
According to [RFC1035], the DNS header contains four two-octet | According to [RFC1035], the DNS header contains four two-octet fields | |||
fields that specify the amount of question records (QDCOUNT), answer | that specify the amount of question records (QDCOUNT), answer records | |||
records (ANCOUNT), authority records (NSCOUNT), and additional | (ANCOUNT), authority records (NSCOUNT), and additional records | |||
records (ARCOUNT). | (ARCOUNT). | |||
Figure 6 illustrates a recurring implementation anti-pattern for a | ||||
function that processes DNS RRs. The function | ||||
"process_dns_records()" extracts the value of ANCOUNT ("num_answers") | ||||
and the pointer to the DNS data payload ("data_ptr"). The function | ||||
processes answer records in a loop, decrementing the "num_answers" | ||||
value after processing each record until the value of "num_answers" | ||||
becomes zero. For simplicity, we assume that there is only one | ||||
domain name per answer. Inside the loop, the code calculates the | ||||
domain name length ("name_length") and adjusts the data payload | ||||
pointer ("data_ptr") by the offset that corresponds to "name_length + | ||||
1", so that the pointer lands on the first answer record. Next, the | ||||
answer record is retrieved and processed, and the "num_answers" value | ||||
is decremented. | ||||
1: process_dns_records(dns_header, ...) { | 1: process_dns_records(dns_header, ...) { | |||
// ... | // ... | |||
2: num_answers = dns_header->ancount | 2: num_answers = dns_header->ancount | |||
3: data_ptr = dns_header->data | 3: data_ptr = dns_header->data | |||
4: | 4: | |||
5: while (num_answers > 0) { | 5: while (num_answers > 0) { | |||
6: name_length = get_name_length(data_ptr); | 6: name_length = get_name_length(data_ptr); | |||
7: data_ptr += name_length + 1; | 7: data_ptr += name_length + 1; | |||
8: | 8: | |||
9: answer = (struct dns_answer_record *)data_ptr; | 9: answer = (struct dns_answer_record *)data_ptr; | |||
10: | 10: | |||
11: // process the answer record | 11: // process the answer record | |||
12: | 12: | |||
13: --num_answers; | 13: --num_answers; | |||
14: } | 14: } | |||
// ... | // ... | |||
15: } | 15: } | |||
Snippet 6 - A broken implementation of a RR processing function | ||||
Snippet 6 illustrates a recurring implementation anti-pattern for a | Figure 6: A Broken Implementation of a Function That Processes RRs | |||
function that processes DNS RRs. The function "process_dns_records()" | ||||
extracts the value of ANCOUNT ("num_answers") and the pointer to the | ||||
DNS data payload ("data_ptr"). The function processes answer records | ||||
in a loop decrementing the "num_answers" value after processing each | ||||
record, until the value of "num_answers" becomes zero. For | ||||
simplicity, we assume that there is only one domain name per answer. | ||||
Inside the loop, the code calculates the domain name length | ||||
"name_length", and adjusts the data payload pointer "data_ptr" by the | ||||
offset that corresponds to "name_length + 1", so that the pointer | ||||
lands on the first answer record. Next, the answer record is | ||||
retrieved and processed, and the "num_answers" value is decremented. | ||||
If the ANCOUNT number retrieved from the header | If the ANCOUNT number retrieved from the header | |||
("dns_header->ancount") is not checked against the amount of data | ("dns_header->ancount") is not checked against the amount of data | |||
available in the packet and it is, e.g., larger than the number of | available in the packet and it is, for example, larger than the | |||
answer records available, the data pointer "data_ptr" will read out | number of answer records available, the data pointer ("data_ptr") | |||
of the bounds of the packet. This may result in Denial-of-Service | will read outside the bounds of the packet. This may result in | |||
conditions. | Denial-of-Service conditions. | |||
In this section, we used an example of processing answer records. | In this section, we used an example of processing answer records. | |||
However, the same logic is often reused for implementing the | However, the same logic is often reused for implementing the | |||
processing of other types of records: e.g., the number of Question | processing of other types of records, e.g., the number of question | |||
(QCOUNT), Authority (NSCOUNT), and Additional (ARCOUNT) records. The | (QDCOUNT), authority (NSCOUNT), and additional (ARCOUNT) records. | |||
number of these records specified must correspond to the actual data | The specified numbers of these records must correspond to the actual | |||
present within the packet. Therefore, all record count fields must | data present within the packet. Therefore, all record count fields | |||
be checked before fully parsing the contents of a packet. | must be checked before fully parsing the contents of a packet. | |||
Specifically, Section 6.3 of[RFC5625] recommends that such malformed | Specifically, Section 6.3 of [RFC5625] recommends that such malformed | |||
DNS packets should be dropped, and (optionally) logged. | DNS packets should be dropped and (optionally) logged. | |||
Examples of vulnerable implementations can be found in the code | Examples of vulnerable implementations can be found in the code | |||
relevant to [CVE-2020-25109], [CVE-2020-24340],[CVE-2020-24334], and | relevant to [CVE-2020-25109], [CVE-2020-24340], [CVE-2020-24334], and | |||
[CVE-2020-27737]. | [CVE-2020-27737]. | |||
7. Security Considerations | 7. Security Considerations | |||
Security issues are discussed throughout this memo. The document | Security issues are discussed throughout this memo; it discusses | |||
discusses implementation flaws (anti-patterns) that affect the | implementation flaws (anti-patterns) that affect the functionality of | |||
functionality of processing DNS RRs. The presence of such | processing DNS RRs. The presence of such anti-patterns leads to bugs | |||
anti-patterns leads to bugs causing buffer overflows, | that cause buffer overflows, read-out-of-bounds, and infinite-loop | |||
read-out-of-bounds, and infinite loop issues. These issues have the | issues. These issues have the following security impacts: | |||
following security impact: Information Leak, Denial-of-Service, and | information leaks, Denial-of-Service attacks, and Remote Code | |||
Remote Code Execution. | Execution attacks. | |||
The document lists general recommendation for the developers of DNS | This document lists general recommendations for the developers of DNS | |||
record parsing functionality that allow to prevent such | record parsing functionality that allow those developers to prevent | |||
implementation flaws, e.g., by rigorously checking the data received | such implementation flaws, e.g., by rigorously checking the data | |||
over the wire before processing it. | received over the wire before processing it. | |||
8. IANA Considerations | 8. IANA Considerations | |||
This document introduces no new IANA considerations. Please see | This document has no IANA actions. Please see [RFC6895] for a | |||
[RFC6895] for a complete review of the IANA considerations | complete review of the IANA considerations introduced by DNS. | |||
introduced by DNS. | ||||
9. References | 9. References | |||
9.1 Normative References | 9.1. Normative References | |||
[RFC1035] | [RFC1035] Mockapetris, P., "Domain names - implementation and | |||
Mockapetris, P., "Domain names - implementation and | specification", STD 13, RFC 1035, DOI 10.17487/RFC1035, | |||
specification", RFC 1035, November 1987, | November 1987, <https://www.rfc-editor.org/info/rfc1035>. | |||
<https://www.rfc-editor.org/info/rfc1035>. | ||||
[RFC5625] | [RFC5625] Bellis, R., "DNS Proxy Implementation Guidelines", | |||
Bellis, R., "DNS Proxy Implementation Guidelines", RFC | BCP 152, RFC 5625, DOI 10.17487/RFC5625, August 2009, | |||
5625, August 2009, | <https://www.rfc-editor.org/info/rfc5625>. | |||
<https://www.rfc-editor.org/info/rfc5625>. | ||||
9.2 Informative References | 9.2. Informative References | |||
[SIGRED] | [CVE-2000-0333] | |||
Common Vulnerabilities and Exposures, "CVE-2020-1350: | Common Vulnerabilities and Exposures, "CVE-2000-0333: A | |||
A remote code execution vulnerability in Windows Domain | denial-of-service vulnerability in tcpdump, Ethereal, and | |||
Name System servers", July 2020, <https://cve.mitre.org/ | other sniffer packages via malformed DNS packets", 2000, | |||
cgi-bin/cvename.cgi?name=CVE-2020-1350>. | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
2000-0333>. | ||||
[SADDNS] | [CVE-2017-9345] | |||
Man, K., Qian, Z., Wang, Z., Zheng, X., Huang, Y., Duan, | Common Vulnerabilities and Exposures, "CVE-2017-9345: An | |||
H., "DNS Cache Poisoning Attack Reloaded: Revolutions | infinite loop in the DNS dissector of Wireshark", 2017, | |||
with Side Channels", November 2020, Proc. of ACM CCS'20, | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
<https://dl.acm.org/doi/pdf/10.1145/3372297.3417280>. | 2017-9345>. | |||
[DNSPOOQ] | [CVE-2020-15795] | |||
Kol, M., Oberman, S., "DNSpooq: Cache Poisoning and RCE | Common Vulnerabilities and Exposures, "CVE-2020-15795: A | |||
in popular DNS Forwarder dnsmasq", January 2021, technical | denial-of-service and remote code execution vulnerability | |||
report, <https://www.jsof-tech.com/wp-content/uploads/ | DNS domain name label parsing functionality of Nucleus | |||
2021/01/DNSpooq-Technical-WP.pdf>. | NET", 2021, <https://cve.mitre.org/cgi-bin/ | |||
cvename.cgi?name=CVE-2020-15795>. | ||||
[CVE-2000-0333] | [CVE-2020-17440] | |||
Common Vulnerabilities and Exposures, "CVE-2000-0333: | Common Vulnerabilities and Exposures, "CVE-2020-17440 A | |||
A denial-of-service vulnerability in tcpdump, Ethereal, | denial-of-service vulnerability in the DNS name parsing | |||
and other sniffer packages via malformed DNS packets", | implementation of uIP", 2020, <https://cve.mitre.org/cgi- | |||
2000, <https://cve.mitre.org/cgi-bin/cvename.cgi?name= | bin/cvename.cgi?name=CVE-2020-17440>. | |||
CVE-2000-0333>. | ||||
[CVE-2020-24338] | [CVE-2020-24334] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24338: | Common Vulnerabilities and Exposures, "CVE-2020-24334: An | |||
A denial-of-service and remote code execution | out-of-bounds read and denial-of-service vulnerability in | |||
vulnerability in the DNS domain name record | the DNS response parsing functionality of uIP", 2020, | |||
decompression functionality of picoTCP", December 2020, | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
<https://cve.mitre.org/cgi-bin/cvename.cgi?name= | 2020-24334>. | |||
CVE-2020-24338> | ||||
[CVE-2020-27738] | [CVE-2020-24335] | |||
Common Vulnerabilities and Exposures, "CVE-2020-27738: | Common Vulnerabilities and Exposures, "CVE-2020-24335: A | |||
A denial-of-service and remote code execution | memory corruption vulnerability in domain name parsing | |||
vulnerability DNS domain name record decompression | routines of uIP", 2020, <https://cve.mitre.org/cgi-bin/ | |||
functionality of Nucleus NET", April 2021, | cvename.cgi?name=CVE-2020-24335>. | |||
<https://cve.mitre.org/cgi-bin/cvename.cgi?name= | ||||
CVE-2020-27738>. | ||||
[CVE-2020-25767] | [CVE-2020-24336] | |||
Common Vulnerabilities and Exposures, "CVE-2020-25767: | Common Vulnerabilities and Exposures, "CVE-2020-24336: A | |||
An out-of-bounds read and denial-of-service vulnerability | buffer overflow vulnerability in the DNS implementation of | |||
in the DNS name parsing routine of HCC Embedded | Contiki and Contiki-NG", 2020, <https://cve.mitre.org/cgi- | |||
NicheStack", August 2021, <https://cve.mitre.org/ | bin/cvename.cgi?name=CVE-2020-24336>. | |||
cgi-bin/cvename.cgi?name=CVE-2020-25767>. | ||||
[CVE-2020-24339] | [CVE-2020-24338] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24339: | Common Vulnerabilities and Exposures, "CVE-2020-24338: A | |||
An out-of-bounds read and denial-of-service | denial-of-service and remote code execution vulnerability | |||
vulnerability in the DNS domain name record | in the DNS domain name record decompression functionality | |||
decompression functionality of picoTCP", December 2020, | of picoTCP", 2020, <https://cve.mitre.org/cgi-bin/ | |||
https://cve.mitre.org/cgi-bin/cvename.cgi?name= | cvename.cgi?name=CVE-2020-24338>. | |||
CVE-2020-24339>. | ||||
[CVE-2020-24335] | [CVE-2020-24339] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24335: | Common Vulnerabilities and Exposures, "CVE-2020-24339: An | |||
A memory corruption vulnerability in domain name parsing | out-of-bounds read and denial-of-service vulnerability in | |||
routines of uIP", December 2020, <https://cve.mitre.org/ | the DNS domain name record decompression functionality of | |||
cgi-bin/cvename.cgi?name=CVE-2020-24335>. | picoTCP", 2020, <https://cve.mitre.org/cgi-bin/ | |||
cvename.cgi?name=CVE-2020-24339>. | ||||
[CVE-2020-25110] | [CVE-2020-24340] | |||
Common Vulnerabilities and Exposures, "CVE-2020-25110: | Common Vulnerabilities and Exposures, "CVE-2020-24340: An | |||
A denial-of-service and remote code execution | out-of-bounds read and denial-of-service vulnerability in | |||
vulnerability in the DNS implementation of Ethernut | the DNS response parsing functionality of picoTCP", 2020, | |||
Nut/OS", December 2020, <https://cve.mitre.org/cgi-bin/ | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
cvename.cgi?name=CVE-2020-25110>. | 2020-24340>. | |||
[CVE-2020-15795] | [CVE-2020-24383] | |||
Common Vulnerabilities and Exposures, "CVE-2020-15795: | Common Vulnerabilities and Exposures, "CVE-2020-24383: An | |||
A denial-of-service and remote code execution | information leak and denial-of-service vulnerability while | |||
vulnerability DNS domain name label parsing | parsing mDNS resource records in FNET", 2020, | |||
functionality of Nucleus NET", April 2021, | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
<https://cve.mitre.org/cgi-bin/cvename.cgi?name= | 2020-24383>. | |||
CVE-2020-15795>. | ||||
[CVE-2020-27009] | [CVE-2020-25107] | |||
Common Vulnerabilities and Exposures, "CVE-2020-27009: | Common Vulnerabilities and Exposures, "CVE-2020-25107: A | |||
A denial-of-service and remote code execution | denial-of-service and remote code execution vulnerability | |||
vulnerability DNS domain name record decompression | in the DNS implementation of Ethernut Nut/OS", 2020, | |||
functionality of Nucleus NET", April 2021, | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
<https://cve.mitre.org/cgi-bin/cvename.cgi?name= | 2020-25107>. | |||
CVE-2020-27009>. | ||||
[CVE-2020-25107] | [CVE-2020-25108] | |||
Common Vulnerabilities and Exposures, "CVE-2020-25107: | Common Vulnerabilities and Exposures, "CVE-2020-25108: A | |||
A denial-of-service and remote code execution | denial-of-service and remote code execution vulnerability | |||
vulnerability in the DNS implementation of Ethernut | in the DNS implementation of Ethernut Nut/OS", 2020, | |||
Nut/OS", December 2020, <https://cve.mitre.org/cgi-bin/ | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
cvename.cgi?name=CVE-2020-25107>. | 2020-25108>. | |||
[CVE-2020-17440] | [CVE-2020-25109] | |||
Common Vulnerabilities and Exposures, "CVE-2020-17440 | Common Vulnerabilities and Exposures, "CVE-2020-25109: A | |||
A denial-of-service vulnerability in the DNS name | denial-of-service and remote code execution vulnerability | |||
parsing implementation of uIP", December 2020, | in the DNS implementation of Ethernut Nut/OS", 2020, | |||
<https://cve.mitre.org/cgi-bin/cvename.cgi?name= | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
CVE-2020-17440>. | 2020-25109>. | |||
[CVE-2020-24383] | [CVE-2020-25110] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24383: | Common Vulnerabilities and Exposures, "CVE-2020-25110: A | |||
An information leak and denial-of-service vulnerability | denial-of-service and remote code execution vulnerability | |||
while parsing mDNS resource records in FNET", December | in the DNS implementation of Ethernut Nut/OS", 2020, | |||
2020, <https://cve.mitre.org/cgi-bin/cvename.cgi?name= | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
CVE-2020-24383>. | 2020-25110>. | |||
[CVE-2020-27736] | [CVE-2020-25767] | |||
Common Vulnerabilities and Exposures, "CVE-2020-27736: | Common Vulnerabilities and Exposures, "CVE-2020-25767: An | |||
An information leak and denial-of-service vulnerability | out-of-bounds read and denial-of-service vulnerability in | |||
in the DNS name parsing functionality of Nucleus NET", | the DNS name parsing routine of HCC Embedded NicheStack", | |||
April 2021, <https://cve.mitre.org/cgi-bin/cvename.cgi? | 2021, <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
name=CVE-2020-27736>. | 2020-25767>. | |||
[CVE-2020-25108] | [CVE-2020-27009] | |||
Common Vulnerabilities and Exposures, "CVE-2020-25108: | Common Vulnerabilities and Exposures, "CVE-2020-27009: A | |||
A denial-of-service and remote code execution | denial-of-service and remote code execution vulnerability | |||
vulnerability in the DNS implementation of Ethernut | DNS domain name record decompression functionality of | |||
Nut/OS", December 2020, <https://cve.mitre.org/cgi-bin/ | Nucleus NET", 2021, <https://cve.mitre.org/cgi-bin/ | |||
cvename.cgi?name=CVE-2020-25108>. | cvename.cgi?name=CVE-2020-27009>. | |||
[CVE-2020-24336] | [CVE-2020-27736] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24336: | Common Vulnerabilities and Exposures, "CVE-2020-27736: An | |||
A buffer overflow vulnerability in the DNS | information leak and denial-of-service vulnerability in | |||
implementation of Contiki and Contiki-NG", December | the DNS name parsing functionality of Nucleus NET", 2021, | |||
2020, <https://cve.mitre.org/cgi-bin/cvename.cgi?name= | <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
CVE-2020-24336>. | 2020-27736>. | |||
[CVE-2020-25109] | [CVE-2020-27737] | |||
Common Vulnerabilities and Exposures, "CVE-2020-25109: | Common Vulnerabilities and Exposures, "CVE-2020-27737: An | |||
A denial-of-service and remote code execution | information leak and denial-of-service vulnerability in | |||
vulnerability in the DNS implementation of Ethernut | the DNS response parsing functionality of Nucleus NET", | |||
Nut/OS", December 2020, <https://cve.mitre.org/cgi-bin/ | 2021, <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE- | |||
cvename.cgi?name=CVE-2020-25109>. | 2020-27737>. | |||
[CVE-2020-24340] | [CVE-2020-27738] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24340: | Common Vulnerabilities and Exposures, "CVE-2020-27738: A | |||
An out-of-bounds read and denial-of-service | denial-of-service and remote code execution vulnerability | |||
vulnerability in the DNS response parsing functionality | DNS domain name record decompression functionality of | |||
of picoTCP", December 2020, <https://cve.mitre.org/ | Nucleus NET", 2021, <https://cve.mitre.org/cgi-bin/ | |||
cgi-bin/cvename.cgi?name=CVE-2020-24340>. | cvename.cgi?name=CVE-2020-27738>. | |||
[CVE-2020-24334] | [DNS-COMPRESSION] | |||
Common Vulnerabilities and Exposures, "CVE-2020-24334: | Koch, P., "A New Scheme for the Compression of Domain | |||
An out-of-bounds read and denial-of-service | Names", Work in Progress, Internet-Draft, draft-ietf- | |||
vulnerability in the DNS response parsing functionality | dnsind-local-compression-05, 30 June 1999, | |||
of uIP", December 2020, <https://cve.mitre.org/cgi-bin/ | <https://datatracker.ietf.org/doc/html/draft-ietf-dnsind- | |||
cvename.cgi?name=CVE-2020-24334>. | local-compression-05>. | |||
[CVE-2020-27737] | [DNSPOOQ] Kol, M. and S. Oberman, "DNSpooq: Cache Poisoning and RCE | |||
Common Vulnerabilities and Exposures, "CVE-2020-27737: | in Popular DNS Forwarder dnsmasq", JSOF Technical Report, | |||
An information leak and denial-of-service vulnerability | January 2021, <https://www.jsof-tech.com/wp- | |||
in the DNS response parsing functionality of Nucleus | content/uploads/2021/01/DNSpooq-Technical-WP.pdf>. | |||
NET", April 2021, <https://cve.mitre.org/cgi-bin/ | ||||
cvename.cgi?name=CVE-2020-27737>. | ||||
[CVE-2017-9345] | [RFC6895] Eastlake 3rd, D., "Domain Name System (DNS) IANA | |||
Common Vulnerabilities and Exposures, "CVE-2017-9345: | Considerations", BCP 42, RFC 6895, DOI 10.17487/RFC6895, | |||
An infinite loop in the DNS dissector of Wireshark", | April 2013, <https://www.rfc-editor.org/info/rfc6895>. | |||
2017, <https://cve.mitre.org/cgi-bin/cvename.cgi?name= | ||||
CVE-2017-9345>. | ||||
[COMP-DRAFT] | [RFC7858] Hu, Z., Zhu, L., Heidemann, J., Mankin, A., Wessels, D., | |||
Koch, P., "A New Scheme for the Compression of | and P. Hoffman, "Specification for DNS over Transport | |||
Domain Names", Internet-Draft, draft-ietf-dnsind-local- | Layer Security (TLS)", RFC 7858, DOI 10.17487/RFC7858, May | |||
compression-05, June 1999, Work in progress, | 2016, <https://www.rfc-editor.org/info/rfc7858>. | |||
<https://tools.ietf.org/html/draft-ietf-dnsind-local- | ||||
compression-05>. | ||||
[RFC6895] | [RFC8484] Hoffman, P. and P. McManus, "DNS Queries over HTTPS | |||
Eastlake 3rd, D., "Domain Name System (DNS) IANA | (DoH)", RFC 8484, DOI 10.17487/RFC8484, October 2018, | |||
Considerations", RFC 6895, April 2013, | <https://www.rfc-editor.org/info/rfc8484>. | |||
<https://www.rfc-editor.org/info/rfc6982>. | ||||
[RFC8484] | [SADDNS] Man, K., Qian, Z., Wang, Z., Zheng, X., Huang, Y., and H. | |||
Hoffman, P., McManus, P., "DNS Queries over HTTPS | Duan, "DNS Cache Poisoning Attack Reloaded: Revolutions | |||
(DoH)", RFC 8484, October 2018, | with Side Channels", Proc. 2020 ACM SIGSAC Conference on | |||
<https://www.rfc-editor.org/info/rfc8484>. | Computer and Communications Security, CCS '20, | |||
DOI 10.1145/3372297.3417280, November 2020, | ||||
<https://dl.acm.org/doi/pdf/10.1145/3372297.3417280>. | ||||
[RFC7858] | [SIGRED] Common Vulnerabilities and Exposures, "CVE-2020-1350: A | |||
Hu, Z. et al, "Specification for DNS over Transport | remote code execution vulnerability in Windows Domain Name | |||
Layer Security (TLS)", RFC 7858, May 2016, | System servers", 2020, <https://cve.mitre.org/cgi-bin/ | |||
<https://www.rfc-editor.org/info/rfc7858>. | cvename.cgi?name=CVE-2020-1350>. | |||
Acknowledgements | Acknowledgements | |||
We would like to thank Shlomi Oberman, who has greatly contributed to | We would like to thank Shlomi Oberman, who has greatly contributed to | |||
the research that led to the creation of this document. | the research that led to the creation of this document. | |||
Authors' Addresses | Authors' Addresses | |||
Stanislav Dashevskyi | Stanislav Dashevskyi | |||
Forescout Technologies | Forescout Technologies | |||
John F. Kennedylaan, 2 | John F. Kennedylaan, 2 | |||
Eindhoven, 5612AB | 5612AB Eindhoven | |||
The Netherlands | Netherlands | |||
Email: stanislav.dashevskyi@forescout.com | Email: stanislav.dashevskyi@forescout.com | |||
Daniel dos Santos | Daniel dos Santos | |||
Forescout Technologies | Forescout Technologies | |||
John F. Kennedylaan, 2 | John F. Kennedylaan, 2 | |||
Eindhoven, 5612AB | 5612AB Eindhoven | |||
The Netherlands | Netherlands | |||
Email: daniel.dossantos@forescout.com | Email: daniel.dossantos@forescout.com | |||
Jos Wetzels | Jos Wetzels | |||
Forescout Technologies | Forescout Technologies | |||
John F. Kennedylaan, 2 | John F. Kennedylaan, 2 | |||
Eindhoven, 5612AB | 5612AB Eindhoven | |||
The Netherlands | Netherlands | |||
Email: jos.wetzels@forescout.com | Email: jos.wetzels@forescout.com | |||
Amine Amri | Amine Amri | |||
Forescout Technologies | Forescout Technologies | |||
John F. Kennedylaan, 2 | John F. Kennedylaan, 2 | |||
Eindhoven, 5612AB | 5612AB Eindhoven | |||
The Netherlands | Netherlands | |||
Email: amine.amri@forescout.com | Email: amine.amri@forescout.com | |||
End of changes. 148 change blocks. | ||||
505 lines changed or deleted | 501 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. |