< draft-dashevskyi-dnsrr-antipatterns-03.txt   draft-dashevskyi-dnsrr-antipatterns-04.txt >
Independent Submission S. Dashevskyi Independent Submission S. Dashevskyi
Internet-Draft D. dos Santos Internet-Draft D. dos Santos
Intended status: Informational J. Wetzels Intended status: Informational J. Wetzels
Expires: October 21, 2022 A. Amri Expires: November 6, 2022 A. Amri
Forescout Technologies Forescout Technologies
April 21, 2022 May 6, 2022
Common implementation anti-patterns related Common implementation anti-patterns related
to Domain Name System (DNS) resource record (RR) processing to Domain Name System (DNS) resource record (RR) processing
draft-dashevskyi-dnsrr-antipatterns-03 draft-dashevskyi-dnsrr-antipatterns-04
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) response 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.
skipping to change at line 36 skipping to change at line 36
Internet-Drafts are working documents of the Internet Engineering Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet- working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/. Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress." material or to cite them other than as "work in progress."
This Internet-Draft will expire on October 21, 2022. This Internet-Draft will expire on November 6, 2022.
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 (http://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
skipping to change at line 178 skipping to change at line 178
[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 a
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"). The destination buffer for the domain name ("dns_payload"). The destination buffer for the domain name
("name_buffer") is typically limited to 255 bytes as per ("name_buffer") is typically limited to 255 bytes as per
[RFC1035] and can be allocated either in the stack or in the heap [RFC1035] and can be allocated 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 at Snippet 1 reads the domain name
label-by-label from a RR until it reaches the NULL octet (0x00) that label-by-label from a 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 octet
("label_len_octet") is a compression pointer, the code extracts the ("label_len_octet") is a compression pointer, the code extracts the
value of the compression offset and uses it to "jump" to another 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 code
will move on to the next label length octet. 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
skipping to change at line 206 skipping to change at line 206
the maximum size of DNS packets that can be sent over the UDP the maximum size of DNS packets that can be sent over the UDP
protocol is limited to 512 octets. protocol is limited to 512 octets.
The pseudocode at Snippet 1 violates these constraints, as it will The pseudocode at Snippet 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 out of the
bounds of a DNS packet. For instance, the compression pointer of bounds of a DNS packet. For instance, the compression pointer of
"0xffff" will produce the offset of 16383 octets, which is most "0xffff" will produce the 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
original DNS packet. Supplying such offset values will most likely original DNS packet. Supplying such offset values will most likely
cause memory corruption issues and may lead to Denial-of-Service cause memory corruption issues and may lead to Denial-of-Service
conditions (e.g., a NULL pointer dereference after "label_len_octet" conditions (e.g., a Null pointer dereference after "label_len_octet"
is set to an invalid address in memory). As an additional example, is set to an invalid address in memory). As an additional example,
see [CVE-2020-25767], [CVE-2020-24339], and [CVE-2020-24335]. see [CVE-2020-25767], [CVE-2020-24339], and [CVE-2020-24335].
The pseudocode at Snippet 1 allows for jumping from a compression The pseudocode at Snippet 1 allows for jumping from a compression
pointer to another compression pointer and it does not restrict the pointer to another compression pointer and it does not restrict the
number of such jumps. That is, if a label length octet which is number of such jumps. That is, if a label length octet which is
currently being parsed is a compression pointer, the code will currently being parsed is a compression pointer, the code will
perform a jump to another label, and if that other label is a perform a jump to another label, and if that other label is a
compression pointer as well, the code will perform another jump, and compression pointer as well, the code will perform another jump, and
so forth until it reaches an decompressed label. This may lead to so forth until it reaches an decompressed label. This may lead to
skipping to change at line 332 skipping to change at line 332
consider "0x41" to be a valid compression pointer, and the packet consider "0x41" to be a valid compression pointer, and the packet
may pass the validation steps. may pass the validation steps.
This might give an additional leverage for attackers in constructing This might give an additional leverage for attackers in 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 a RR (an octet with
the 2 highest bits set to 1) must resolve to an octet within a DNS the 2 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 the 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) the
support for nested compression pointers (pointers that point to a support for nested compression pointers (pointers that point to a
compressed name) should be discouraged: there is very little to be compressed name) should be discouraged: there is very little to be
gained in terms of performance versus the high possibility of gained in terms of performance versus the high possibility of
introducing errors, such as the ones discussed above. introducing errors, such as the ones discussed above.
skipping to change at line 416 skipping to change at line 416
or stack metadata in a controlled manner. or stack metadata 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
the value of more than 0 and less than 64 ([RFC1035]). If this is the value of more than 0 and less than 64 ([RFC1035]). If this is
not the case, an invalid value has been provided within the packet, not the case, an invalid value has been provided within the packet,
or a value at an invalid position might be interpreted as a domain or a value at an invalid position might be interpreted as a domain
name length due to other errors in the packet (e.g., misplaced NULL name 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 NULL 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 within the maximum name
length (255 octets). length (255 octets).
4. NULL-terminator Placement Validation 4. Null-terminator Placement Validation
A domain name must end with a NULL ("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 at Snippets 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
NULL octet placed at the proper position within a RR are not NUL octet placed at the proper position within a 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 Snippets 1 and 4 will continue
to copy octets into the name buffer, until a NULL octet is to copy octets into the name buffer, until a NUL octet is
encountered. This octet can be placed at an arbitrary position encountered. This octet can be placed at an arbitrary position
within a RR, or not placed at all. within a RR, or not placed at all.
Consider a pseudocode function shown on Snippet 5. The function Consider a pseudocode function shown on Snippet 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) {
skipping to change at line 462 skipping to change at line 462
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 Snippet 5 - A broken implementation of a function that returns the
length of a domain name 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 NULL ("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-terminated, the return value "strlen(3)" may be also controlled Null-terminated, the return value "strlen(3)" may be also controlled
by attackers. Through the value of "name_len" attackers may control by 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 other operations depending on the
implementation specifics. implementation specifics.
The absence of explicit checks for the NULL octet placement may also The absence of explicit checks for the NUL octet placement may also
facilitate controlled memory reads and writes. An example of 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 in the code Snippet 5, developers should use
the function "strnlen(3)" that reads at most X characters(the second the function "strnlen(3)" that reads at most X characters(the second
argument of the function), and ensure that X is not larger than the argument of the function), and ensure that X is not larger than the
buffer allocated for the name. 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 of
 End of changes. 18 change blocks. 
18 lines changed or deleted 18 lines changed or added

This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/