<?xmlversion='1.0' encoding='utf-8'?>version="1.0" encoding="UTF-8"?> <!DOCTYPE rfcSYSTEM "rfc2629.dtd"[ <!ENTITYRFC1035 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.1035.xml">nbsp " "> <!ENTITYRFC5625 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5625.xml">zwsp "​"> <!ENTITYI-D.ietf-dnsind-local-compression SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-dnsind-local-compression.xml">nbhy "‑"> <!ENTITYRFC6895 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6895.xml"> <!ENTITY RFC8484 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8484.xml"> <!ENTITY RFC7858 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7858.xml">wj "⁠"> ]> <rfc xmlns:xi="http://www.w3.org/2001/XInclude" submissionType="independent"docName="draft-dashevskyi-dnsrr-antipatterns-06"category="info"ipr="trust200902">docName="draft-dashevskyi-dnsrr-antipatterns-06" number="9267" ipr="trust200902" obsoletes="" updates="" xml:lang="en" symRefs="true" sortRefs="true" tocInclude="true" version="3"> <!-- xml2rfc v2v3 conversion 3.12.7 --> <!-- Generated by id2xml 1.5.0 on 2022-05-24T23:44:10Z --><?rfc strict="yes"?> <?rfc compact="yes"?> <?rfc subcompact="no"?> <?rfc symrefs="yes"?> <?rfc sortrefs="no"?> <?rfc text-list-symbols="o*+-"?> <?rfc toc="yes"?><front> <titleabbrev="Common implementation anti-patterns rela">Common implementation anti-patterns relatedabbrev="Vulnerabilities in DNS RR Processing">Common Implementation Anti-Patterns Related to Domain Name System (DNS)resource recordResource Record (RR)processing</title>Processing</title> <seriesInfo name="RFC" value="9267"/> <author initials="S." surname="Dashevskyi" fullname="Stanislav Dashevskyi"> <organization>Forescout Technologies</organization><address><postal><address> <postal> <street>John F. Kennedylaan, 2</street> <city>Eindhoven</city> <code>5612AB</code><country>The Netherlands</country><country>Netherlands</country> </postal> <email>stanislav.dashevskyi@forescout.com</email> </address> </author> <author initials="D." surname="dos Santos" fullname="Daniel dos Santos"> <organization>Forescout Technologies</organization><address><postal><address> <postal> <street>John F. Kennedylaan, 2</street> <city>Eindhoven</city> <code>5612AB</code><country>The Netherlands</country><country>Netherlands</country> </postal> <email>daniel.dossantos@forescout.com</email> </address> </author> <author initials="J." surname="Wetzels" fullname="Jos Wetzels"> <organization>Forescout Technologies</organization><address><postal><address> <postal> <street>John F. Kennedylaan, 2</street> <city>Eindhoven</city> <code>5612AB</code><country>The Netherlands</country><country>Netherlands</country> </postal> <email>jos.wetzels@forescout.com</email> </address> </author> <author initials="A." surname="Amri" fullname="Amine Amri"> <organization>Forescout Technologies</organization><address><postal><address> <postal> <street>John F. Kennedylaan, 2</street> <city>Eindhoven</city> <code>5612AB</code><country>The Netherlands</country><country>Netherlands</country> </postal> <email>amine.amri@forescout.com</email> </address> </author> <date year="2022"month="May"/> <!-- [rfced] Please insert any keywords (beyond those that appear in the title) for use on https://www.rfc-editor.org/search. --> <keyword>example</keyword> <abstract><t>month="July"/> <keyword>vulnerabilities</keyword> <keyword>vulnerability</keyword> <abstract> <t> This memo describes common vulnerabilities related to Domain Name System (DNS)responseresource record (RR) processing as seen in several DNS client implementations. These vulnerabilities may lead to successful Denial-of-Service and Remote Code Execution attacks against the affected software. Where applicable, violations of RFC 1035 are mentioned.</t> </abstract> </front> <middle> <sectiontitle="Introduction" anchor="sect-1"><t> Recently, there have been majoranchor="sect-1" numbered="true" toc="default"> <name>Introduction</name> <t> Major vulnerabilitiesonin DNS implementationsthatrecently became evident and raised attention to this protocol as an important attack vector,suchas discussed in <xreftarget="SIGRED"/>,target="SIGRED" format="default"/>, <xreftarget="SADDNS"/>,target="SADDNS" format="default"/>, and <xreftarget="DNSPOOQ"/> -target="DNSPOOQ" format="default"/>, the latter being a set of 7 critical issues affecting the DNS forwarder "dnsmasq".</t> <t> The authors of this memo have analyzed the DNS client implementations of several major TCP/IP protocol stacks and found a set of vulnerabilities that share common implementation flaws (anti-patterns). These flaws are related to processing DNSRRsresource records (RRs) (discussed in <xreftarget="RFC1035"/>)target="RFC1035" format="default"/>) and may lead to critical security vulnerabilities.</t> <t> While implementation flaws may differ from one software project to another, these anti-patterns are highly likely to spanacrossmultiple implementations. In fact, one of the firstCVEs"Common Vulnerabilities and Exposures" (CVE) documents related to one of the anti-patterns <xreftarget="CVE-2000-0333"/>target="CVE-2000-0333" format="default"/> dates back to the year 2000. The observations are not limited to DNS client implementations. Any software that processes DNS RRs may be affected, such as firewalls, intrusion detection systems, orgeneral purposegeneral-purpose DNS packet dissectors (e.g.,<xref target="CVE-2017-9345"/>the DNS dissector inWireshark).Wireshark; see <xref target="CVE-2017-9345" format="default"/>). Similar issues may also occur in DNS-over-HTTPS <xreftarget="RFC8484"/>target="RFC8484" format="default"/> and DNS-over-TLS <xreftarget="RFC7858"/>target="RFC7858" format="default"/> implementations. However, any implementation that deals with the DNS wire format is subject to the considerations discussed in thisdraft.</t>document.</t> <t> <xreftarget="I-D.ietf-dnsind-local-compression"/>target="I-D.ietf-dnsind-local-compression" format="default"/> and <xreftarget="RFC5625"/>target="RFC5625" format="default"/> briefly mention some of these anti-patterns, but the main purpose of this memo is to provide technical details behind these anti-patterns, so that the common mistakes can be eradicated.</t> <t> We provide general recommendations on mitigating the anti-patterns. We also suggest that all implementations should drop malicious/malformed DNS replies and (optionally) logthem (optionally).</t>them.</t> </section> <sectiontitle="Compressionanchor="sect-2" numbered="true" toc="default"> <name>Compression Pointer and OffsetValidation" anchor="sect-2"><t>Validation</name> <t> <xreftarget="RFC1035"/>target="RFC1035" format="default"/> defines the DNS message compression scheme that can be used to reduce the size of messages. When it is used, an entire domain name or several name labels are replaced with a (compression) pointer to a prior occurrence of the same name.</t> <t> 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 OFFSET field. This field specifies the offset from the beginning of the DNS header, at which another domain name or label is located:</t><figure><artwork><![CDATA[<artwork name="" type="" align="left" alt=""><![CDATA[ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | 1 1| OFFSET | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ ]]></artwork></figure><t> The message compression scheme explicitly allows a domain name to be representedas:as one of the following: (1) a sequence of unpacked labels ending with a zerooctet;octet, (2) apointer;pointer, or (3) a sequence of labels ending with a pointer.</t> <t> However, <xreftarget="RFC1035"/>target="RFC1035" format="default"/> does not explicitly state that blindly following compression pointers of any kind can be harmful <xreftarget="I-D.ietf-dnsind-local-compression"/>,target="I-D.ietf-dnsind-local-compression" format="default"/>, as we could not have had any assumptions about various implementations that would follow.</t> <t> Yet, any DNS packet parser that attempts to decompress domain names without validating the value of OFFSET is likely susceptible to memory corruption bugs and buffer overruns. These bugsallow for easymake it easier to perform Denial-of-Serviceattacks,attacks and may result in successful Remote Code Execution attacks.</t> <t> Pseudocode that illustrates a typical example of a broken domain name parsing implementation is shown below(Snippet 1):</t> <figure><artwork><![CDATA[ 1:decompress_domain_name(*name,(<xref target="snippet_1"/>):</t> <figure anchor="snippet_1"> <name>A Broken Implementation of a Function That Is Used for Decompressing DNS Domain Names (Pseudocode)</name> <sourcecode name="" type="pseudocode"><![CDATA[ 1: decompress_domain_name(*name, *dns_payload) { 2: 3: name_buffer[255]; 4: copy_offset = 0; 5: 6: label_len_octet = name; 7: dest_octet = name_buffer; 8: 9: while (*label_len_octet != 0x00) { 10: 11: if (is_compression_pointer(*label_len_octet)) { 12: ptr_offset = get_offset(label_len_octet, label_len_octet+1); 13: label_len_octet = dns_payload + ptr_offset + 1; 14: } 15: 16: else { 17: length = *label_len_octet; 18: copy(dest_octet + copy_offset, label_len_octet+1, *length); 19: 20: copy_offset += length; 21: label_len_octet += length + 1; 22: } 23: 24: }25:} Snippet 1 - A broken implementation of a function that is used for decompressing DNS domain names (pseudocode) ]]></artwork>25: } ]]></sourcecode> </figure> <t> Such implementations typically have a dedicated function for decompressing domain names (for example, see <xreftarget="CVE-2020-24338"/>target="CVE-2020-24338" format="default"/> and <xreftarget="CVE-2020-27738"/>).target="CVE-2020-27738" format="default"/>). Among other parameters, these functions may accept a pointer to the beginning of the first name label withinaan RR ("name") and a pointer to the beginning of the DNS payload to be used as a starting point for the compression pointer ("dns_payload"). The destination buffer for the domain name ("name_buffer") is typically limited to 255 bytes as per <xreftarget="RFC1035"/>target="RFC1035" format="default"/> and can be allocated either in the stack or in the heap memory region.</t> <t> The code of the functionat Snippet 1in <xref target="snippet_1"/> reads the domain namelabel-by-labellabel by label fromaan RR until it reaches the NUL octet ("0x00") that signifies the end of a domain name. If the current label length octet ("label_len_octet") is a compression pointer, the code extracts 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 compression pointer, the label bytes will be copied into the name buffer, and the number of bytes copied will correspond to the value of the current label length octet. After the copy operation, the code will move on to the next label length octet.</t> <t> The first issue with this implementation is due to unchecked compression offset values. The second issue is due to the absence of checks that ensure that a pointer will eventually arrive atana decompressed domain label. We describe these issues in more detail below.</t> <t> <!-- DNE; fixed --> <xreftarget="RFC1035"/>target="RFC1035" format="default"/> states that"... [compression pointer is]a compression pointer is "a pointer to a prioroccurrenceoccurance [sic] of the samename".name." Also, according to <xreftarget="RFC1035"/>,target="RFC1035" format="default"/>, the maximum size of DNS packets that can be sent overtheUDPprotocolis limited to 512 octets.</t> <t> The pseudocodeat Snippet 1in <xref target="snippet_1"/> violates these constraints, as it will accept a compression pointer that forces the code to readout ofoutside the bounds of a DNS packet. For instance,thea compression pointerofset to "0xffff" will producethean offset of 16383 octets, which is most definitely pointing to a label length octet somewhere past the bounds of the original DNS packet. Supplying such offset values will most likely cause memory corruption issues and may lead to Denial-of-Service conditions (e.g., a Null pointer dereference after "label_len_octet" is set to an invalid address in memory).As anFor additionalexample,examples, see <xreftarget="CVE-2020-25767"/>,target="CVE-2020-25767" format="default"/>, <xreftarget="CVE-2020-24339"/>,target="CVE-2020-24339" format="default"/>, and <xreftarget="CVE-2020-24335"/>.</t>target="CVE-2020-24335" format="default"/>.</t> <t> The pseudocodeat Snippet 1in <xref target="snippet_1"/> allowsforjumping from a compression pointer to another compression pointer anditdoes not restrict the number of such jumps. That is, if a label length octetwhichthat is currently being parsed is a compression pointer, the code will perform a jump to another label, and if that other label is a compression pointer as well, the code will perform another jump, and so forth until it reachesana decompressed label. This may lead to unforeseenside-effectsside effects that result in security issues.</t> <t>Consider theexcerpt from aDNS packet excerpt illustrated below:</t><figure><artwork><![CDATA[<artwork name="" type="" align="left" alt=""><![CDATA[ +----+----+----+----+----+----+----+----+----+----+----+----+ +0x00 | ID | FLAGS |QCOUNTQDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | +----+----+----+----+----+----+----+----+----+----+----+----+ ->+0x0c |0xc0|0x0c| TYPE | CLASS |0x04| t | e | s | t |0x03| | +----+--|-+----+----+----+----+----+----+----+----+----+----+ | +0x18 | c | o| | m |0x00| TYPE | CLASS | ................ | | +----+--|-+----+----+----+----+----+----+----+----+----+----+ | |--------------------------------- ]]></artwork></figure><t> The packet begins with a DNS header attheoffset +0x00, and its DNS payload contains several RRs. The first RR begins atthean offset of 12 octets(+0xc0) and(+0x0c); its first label length octet is set to the value "0xc0", which indicates that it is a compression pointer. The compression pointer offset is computed from the two octets "0xc00c" anditis equal to 12. Since the broken implementationat Snippet 1in <xref target="snippet_1"/> follows this offset value blindly, the pointer will jump back to the first octet of the first RR(+0xc0)(+0x0c) over and over again. The codeat Snippet 1in <xref target="snippet_1"/> will enter aninfinite loopinfinite-loop state, since it will never leave the "TRUE" branch of the "while" loop.</t> <t> Apart from achieving infinite loops, the implementation flawsat Snippet 1in <xref target="snippet_1"/> make it possible to achieve various pointer loops that have other undesirable effects. For instance, consider the DNS packet excerpt shown below:</t><figure><artwork><![CDATA[<artwork name="" type="" align="left" alt=""><![CDATA[ +----+----+----+----+----+----+----+----+----+----+----+----+ +0x00 | ID | FLAGS |QCOUNTQDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | +----+----+----+----+----+----+----+----+----+----+----+----+ ->+0x0c |0x04| t | e | s | t |0xc0|0x0c| ...................... | | +----+----+----+----+----+----+--|-+----+----+----+----+----+ | |----------------------------------------------------------------------------------- ]]></artwork></figure><t> With such a domain name, the implementationat Snippet 1in <xref target="snippet_1"/> will first copy the domain label attheoffset "0xc0"("test"), then("test"); it will then fetch the next label length octet, whichishappens to be a compression pointer ("0xc0"). The compression pointer offset is computed from the two octets "0xc00c" and is equal to 12 octets. The code will jump backat theto offset "0xc0" where the first label "test" is located. The code will again copy the "test"label,label and then jump back to it, following the compression pointer, over and over again.</t> <t>Snippet 1<xref target="snippet_1"/> does not contain any logic that restricts multiple jumps from the same compression pointer and does not ensure that no more than 255 octets are copied into the name buffer ("name_buffer"). Infact, thefact,</t> <ul spacing="normal"> <li>the code will continue to write the label "test" into it, overwriting the name buffer and the stack of the heapmetadata. In fact, attackersmetadata.</li> <li>attackers would have a significant degree of freedom in constructingshell-code,shell code, since they can create arbitrary copy chains with various combinations of labels and compressionpointers.</t> <t> Therefore,pointers.</li> </ul> <t>Therefore, blindly following compression pointers may lead not onlyleadto Denial-of-Service conditions, as pointed out by <xreftarget="I-D.ietf-dnsind-local-compression"/>,target="I-D.ietf-dnsind-local-compression" format="default"/>, but also to successful Remote Code Execution attacks, as there may be other implementation issues present within the corresponding code.</t> <t> Some implementations may not follow <xreftarget="RFC1035"/>,target="RFC1035" format="default"/>, which states:"the<!-- DNE; fixed --> </t> <blockquote>The first two bits[of a compression pointer octet]areones; thisones. 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 orless (theless. (The 10 and 01 combinations are reserved for futureuse)". Snippets 2use.)</blockquote> <t> Figures <xref target="snippet_2" format="counter"/> and3<xref target="snippet_3" format="counter"/> show pseudocode that implements two functions that check whether a given octet is a compressionpointer:pointer; <xref target="snippet_2"/> shows a correct implementation, and <xref target="snippet_3"/> shows an incorrectimplementations respectively.</t> <figure><artwork><![CDATA[(broken) implementation.</t> <figure anchor="snippet_2"> <name>Correct Compression Pointer Check</name> <sourcecode name="" type="pseudocode" ><![CDATA[ 1: unsigned char is_compression_pointer(*octet) { 2: if ((*octet & 0xc0) == 0xc0) 3: return true; 4: } else { 5: return false; 6: } 7: }Snippet 2 - Correct compression pointer check]]></sourcecode> </figure> <figure anchor="snippet_3"> <name>Broken Compression Pointer Check</name> <sourcecode name="" type="pseudocode"><![CDATA[ 1: unsigned char is_compression_pointer(*octet) { 2: if (*octet & 0xc0) { 3: return true; 4: } else { 5: return false; 6: } 7: }Snippet 3 - Broken compression pointer check ]]></artwork>]]></sourcecode> </figure> <t> The correct implementation(Snippet 2)(<xref target="snippet_2"/>) ensures that the two most significant bits of an octet are both set, while the broken implementation(Snippet 3)(<xref target="snippet_3"/>) would consider an octet with only one of the two bits setasto be a compression pointer. This is likely an implementation mistake rather than an intended violation of[RFC1035],<xref target="RFC1035" format="default"/>, because there are no benefits in supporting such compression pointer values. The implementations related to[CVE-2020-24338]<xref target="CVE-2020-24338" format="default"/> and[CVE-2020-24335]<xref target="CVE-2020-24335" format="default"/> had a broken compression pointercheck illustrated on Snippet 3.</t>check, similar to the code shown in <xref target="snippet_3"/>.</t> <t> While incorrect implementations alone do not lead to vulnerabilities, they may have unforeseenside-effectsside effects when combined with other vulnerabilities. For instance, the first octet of the value "0x4130" may be incorrectly interpreted as a label length by a broken implementation. Such a label length (65) isinvalid,invalid and is larger than 63 (as per <xreftarget="RFC1035"/>), andtarget="RFC1035" format="default"/>); a packet that has this value should be discarded. However, the function shownon Snippet 3in <xref target="snippet_3"/> will consider "0x41" to be a valid compression pointer, and the packet may pass the validation steps.</t> <t> This might giveanattackers additional leverage forattackers inconstructing payloads and circumventing the existing DNS packet validation mechanisms.</t> <t> The first occurrence of a compression pointer inaan RR (an octet with the2two highest bits set to 1) must resolve to an octet within a DNS record withthea 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 located must be smaller than the offset at which the compression pointer islocated -located; once an implementation makes sure of that, compression pointer loops can never occur.</t> <t> In small DNS implementations (e.g., embedded TCP/IPstacks) thestacks), support for nested compression pointers (pointers that point to a compressed name) should be discouraged: there is very little to be gained in terms of performance versus the highpossibilityprobability of introducingerrors,errors such asthe onesthose discussed above.</t> <t> The code that implements domain name parsing should check the offsetnot onlywith respect to not only the bounds of apacket,packet but also its position with respect to the compression pointer in question. A compression pointer must not be "followed" more than once. We have seen several implementations using a check that ensures that a compression pointer is not followed more than several times. A better alternative may be to ensure that the target of a compression pointer is always located before the location of the pointer in the packet.</t> </section> <sectiontitle="Labelanchor="sect-3" numbered="true" toc="default"> <name>Label and Name LengthValidation" anchor="sect-3"><t>Validation</name> <t> <xreftarget="RFC1035"/>target="RFC1035" format="default"/> restricts the length of name labels to 63octets,octets and lengths of domain names to 255 octets (i.e., label octets and label length octets). Some implementations do not explicitly enforce these restrictions.</t> <t> Consider the function "copy_domain_name()" shownon Snippet 4in <xref target="snippet_4"/> below. The function is a variant of the "decompress_domain_name()" function(Snippet 1),(<xref target="snippet_1"/>), with the difference that it does not support compressedlabels,labels andcopiesonly copies decompressed labels into the name buffer.</t><figure><artwork><![CDATA[ 1:copy_domain_name(*name,<figure anchor="snippet_4"> <name>A Broken Implementation of a Function That Is Used for Copying Non-&wj;compressed Domain Names</name> <sourcecode name="" type="pseudocode" ><![CDATA[ 1: copy_domain_name(*name, *dns_payload) { 2: 3: name_buffer[255]; 4: copy_offset = 0; 5: 6: label_len_octet = name; 7: dest_octet = name_buffer; 8: 9: while (*label_len_octet != 0x00) { 10: 11: if (is_compression_pointer(*label_len_octet)) { 12: length = 2; 13: label_len_octet += length + 1; 14: } 15: 16: else { 17: length = *label_len_octet; 18: copy(dest_octet + copy_offset, label_len_octet+1, *length); 19: 20: copy_offset += length; 21: label_len_octet += length + 1; 22: } 23: 24: }25:} Snippet 4 - A broken implementation of a function that is used for copying non-compressed domain names ]]></artwork>25: } ]]></sourcecode> </figure> <t> 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 can fill the name buffer. Depending on the memory layout of the target, how the name buffer is allocated, and the size of the malformed packet, it is possible to trigger various memory corruption issues.</t> <t> BothSnippets 1Figures <xref target="snippet_1" format="counter"/> and4<xref target="snippet_4" format="counter"/> restrict the size of the name buffer to 255octets, howeveroctets; however, there are no restrictions on the actual number of octets that will be copied into this buffer. In this particular case, a subsequent copy operation (if another label is present in the packet) will write past the name buffer, allowingto overwriteheap or stack metadata to be overwritten in a controlled manner.</t> <t> Similar examples of vulnerable implementations can be found in the code relevant to <xreftarget="CVE-2020-25110"/>,target="CVE-2020-25110" format="default"/>, <xreftarget="CVE-2020-15795"/>,target="CVE-2020-15795" format="default"/>, and <xreftarget="CVE-2020-27009"/>.</t>target="CVE-2020-27009" format="default"/>.</t> <t> As a general recommendation, a domain label length octet must havethea value of more than 0 and less than 64(<xref target="RFC1035"/>).<xref target="RFC1035" format="default"/>. If this is 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 name length due to other errors in the packet (e.g., misplaced Null-terminator or invalid compression pointer).</t> <t> The number of domain label characters must correspond to the value of the domain label octet. To avoid possible errors when interpreting the characters of a domain label, developers may consider recommendations for the preferred domain name syntax outlined in <xreftarget="RFC1035"/>.</t>target="RFC1035" format="default"/>.</t> <t> The domain name length must not be more than 255 octets, including the size of decompressed domain names. The NUL octet ("0x00") must be present at the end of the domainname,name and must be within the maximum name length (255 octets).</t> </section> <sectiontitle="Null-terminatoranchor="sect-4" numbered="true" toc="default"> <name>Null-Terminator PlacementValidation" anchor="sect-4"><t>Validation</name> <t> A domain name must end with a NUL ("0x00") octet, as per <xreftarget="RFC1035"/>.target="RFC1035" format="default"/>. The implementations shownat Snippets 1in Figures <xref target="snippet_1" format="counter"/> and4<xref target="snippet_4" format="counter"/> assume that this is the case for the RRs that theyprocess, howeverprocess; however, names that do not have a NUL octet placed at the proper position withinaan RR are not discarded.</t> <t> This issue is closely related to the absence of label and name length checks. For example, the logic behindSnippets 1Figures <xref target="snippet_1" format="counter"/> and4<xref target="snippet_4" format="counter"/> will continue to copy octets into the namebuffer,buffer until a NUL octet is encountered. This octet can be placed at an arbitrary position withina RR,an RR or not placed at all.</t> <t> Considerathe pseudocode function shownon Snippet 5.in <xref target="snippet_5"/>. The function 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 compressed domainnamesnames, the function returns2,2; for decompressednamesnames, it returns their true length using the "strlen(3)" function.</t><figure><artwork><![CDATA[<figure anchor="snippet_5"> <name>A Broken Implementation of a Function That Returns the Length of a Domain Name</name> <sourcecode name="" type="pseudocode"><![CDATA[ 1: get_name_length(*name) { 2: 3: if (is_compression_pointer(name)) 4: return 2; 5: 6: name_len = strlen(name) + 1; 7: return name_len; 8: }Snippet 5 - A broken implementation of a function that returns the length of a domain name ]]></artwork></figure>]]></sourcecode> </figure> <t> "strlen(3)" is a standard C library function that returns the length of a given sequence of characters terminated by the NUL ("0x00") octet. Since this function also expects names to be explicitly Null-terminated, the return value "strlen(3)" maybealso be controlled by attackers. Through the value of"name_len""name_len", attackers may control the allocation of internalbuffers,buffers or specify the number by octets copied into these buffers, or they may perform otheroperationsoperations, depending on the implementation specifics.</t> <t> The absence of explicit checks for placement of the NUL octetplacementmay also facilitate controlled memory reads and writes. An example of vulnerable implementations can be found in the code relevant to <xreftarget="CVE-2020-25107"/>,target="CVE-2020-25107" format="default"/>, <xreftarget="CVE-2020-17440"/>,target="CVE-2020-17440" format="default"/>, <xreftarget="CVE-2020-24383"/>,target="CVE-2020-24383" format="default"/>, and <xreftarget="CVE-2020-27736"/>.</t>target="CVE-2020-27736" format="default"/>.</t> <t> As a general recommendation for mitigating such issues, developers should never trust user data to be Null-terminated. For example, to fix/mitigate the issue shown in the codeSnippet 5,in <xref target="snippet_5"/>, developers should use the function"strnlen(3)" that"strnlen(3)", which reads at most Xcharacters(thecharacters (the second argument of the function), and ensure that X is not larger than the buffer allocated for the name.</t> </section> <sectiontitle="Responseanchor="sect-5" numbered="true" toc="default"> <name>Response Data LengthValidation" anchor="sect-5"><t>Validation</name> <t> As stated in <xreftarget="RFC1035"/>,target="RFC1035" format="default"/>, every RR contains avariable lengthvariable-length string of octets that contains the retrieved resource data (RDATA) (e.g., an IP address that corresponds to a domain name in question). The length of the RDATA field is regulated by the resource data length field (RDLENGTH),thatwhich is also present in an RR.</t> <t> Implementations that process RRs may not check for the validity of the RDLENGTH fieldvalue,value when retrieving RDATA. Failing to do so may lead to out-of-bound readissues (similarly to the label and name length validation issues discussed in <xref target="sect-3"/>),issues, whose impact may varysignificantlysignificantly, depending on the implementation specifics. We have observed instances of Denial-of-Service conditions and information leaks.</t> <t> Therefore, the value of the data length byte in response DNS records (RDLENGTH) must reflect the number of bytes available in the field that describes the resource (RDATA). The format of RDATA must conform to the TYPE and CLASS fields of the RR.</t> <t> Examples of vulnerable implementations can be found in the code relevant to <xreftarget="CVE-2020-25108"/>,target="CVE-2020-25108" format="default"/>, <xreftarget="CVE-2020-24336"/>,target="CVE-2020-24336" format="default"/>, and <xreftarget="CVE-2020-27009"/>.</t>target="CVE-2020-27009" format="default"/>.</t> </section> <sectiontitle="Recordanchor="sect-6" numbered="true" toc="default"> <name>Record CountValidation" anchor="sect-6"><t>Validation</name> <t> According to <xreftarget="RFC1035"/>,target="RFC1035" format="default"/>, the DNS header contains four two-octet fields that specify the amount of question records (QDCOUNT), answer records (ANCOUNT), authority records (NSCOUNT), and additional records (ARCOUNT).</t><figure><artwork><![CDATA[ 1: process_dns_records(dns_header, ...) { // ... 2: num_answers = dns_header->ancount 3: data_ptr = dns_header->data 4: 5: while (num_answers > 0) { 6: name_length = get_name_length(data_ptr); 7: data_ptr += name_length + 1; 8: 9: answer = (struct dns_answer_record *)data_ptr; 10: 11: // process the answer record 12: 13: --num_answers; 14: } // ... 15: } Snippet 6 - A broken implementation of a RR processing function ]]></artwork> </figure><t>Snippet 6<xref target="snippet_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 alooploop, decrementing the "num_answers" value after processing eachrecord,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",("name_length") and adjusts the data payload pointer"data_ptr"("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.</t> <figure anchor="snippet_6"> <name>A Broken Implementation of a Function That Processes RRs</name> <sourcecode name="" type="pseudocode" ><![CDATA[ 1: process_dns_records(dns_header, ...) { // ... 2: num_answers = dns_header->ancount 3: data_ptr = dns_header->data 4: 5: while (num_answers > 0) { 6: name_length = get_name_length(data_ptr); 7: data_ptr += name_length + 1; 8: 9: answer = (struct dns_answer_record *)data_ptr; 10: 11: // process the answer record 12: 13: --num_answers; 14: } // ... 15: } ]]></sourcecode> </figure> <t> If the ANCOUNT number retrieved from the header ("dns_header->ancount") is not checked against the amount of data available in the packet and it is,e.g.,for example, larger than the number of answer records available, the data pointer"data_ptr"("data_ptr") will readout ofoutside the bounds of the packet. This may result in Denial-of-Service conditions.</t> <t> In this section, we used an example of processing answer records. However, the same logic is often reused for implementing the processing of other types ofrecords:records, e.g., the number ofQuestion (QCOUNT), Authorityquestion (QDCOUNT), authority (NSCOUNT), andAdditionaladditional (ARCOUNT) records. Thenumberspecified numbers of these recordsspecifiedmust correspond to the actual data present within the packet. Therefore, all record count fields must be checked before fully parsing the contents of a packet. Specifically,Section 6.3 of<xref target="RFC5625"/><xref target="RFC5625" sectionFormat="of" section="6.3"/> recommends that such malformed DNS packets should bedropped,dropped and (optionally) logged.</t> <t> Examples of vulnerable implementations can be found in the code relevant to <xreftarget="CVE-2020-25109"/>,target="CVE-2020-25109" format="default"/>, <xref target="CVE-2020-24340" format="default"/>, <xreftarget="CVE-2020-24340"/>,<xref target="CVE-2020-24334"/>,target="CVE-2020-24334" format="default"/>, and <xreftarget="CVE-2020-27737"/>.</t>target="CVE-2020-27737" format="default"/>.</t> </section> <sectiontitle="Security Considerations" anchor="sect-7"><t>anchor="sect-7" numbered="true" toc="default"> <name>Security Considerations</name> <t> Security issues are discussed throughout thismemo. The documentmemo; it discusses implementation flaws (anti-patterns) that affect the functionality of processing DNS RRs. The presence of such anti-patterns leads to bugscausingthat cause buffer overflows, read-out-of-bounds, andinfinite loopinfinite-loop issues. These issues have the following securityimpact: Information Leak, Denial-of-Service,impacts: information leaks, Denial-of-Service attacks, and Remote CodeExecution.</t>Execution attacks.</t> <t>TheThis document lists generalrecommendationrecommendations for the developers of DNS record parsing functionality that allow those developers to prevent such implementation flaws, e.g., by rigorously checking the data received over the wire before processing it.</t> </section> <sectiontitle="IANA Considerations" anchor="sect-8"><t>anchor="sect-8" numbered="true" toc="default"> <name>IANA Considerations</name> <t> This documentintroduceshas nonewIANAconsiderations.actions. Please see <xreftarget="RFC6895"/>target="RFC6895" format="default"/> for a complete review of the IANA considerations introduced by DNS.</t> </section> </middle> <back><references title="Normative References"> &RFC1035; &RFC5625;<displayreference target="I-D.ietf-dnsind-local-compression" to="DNS-COMPRESSION"/> <references> <name>References</name> <references> <name>Normative References</name> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.1035.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5625.xml"/> </references><references title="Informative References"><references> <name>Informative References</name> <reference anchor="SIGRED"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-1350"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-1350"> <front> <title>CVE-2020-1350: A remote code execution vulnerability in Windows Domain Name System servers</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="July"year="2020"/> </front> </reference> <reference anchor="SADDNS" target="https://dl.acm.org/doi/pdf/10.1145/3372297.3417280"> <front> <title>DNS Cache Poisoning Attack Reloaded: Revolutions with Side Channels</title> <author initials="K." surname="Man" fullname="Keyu Man"> <organization/> </author> <author initials="Z." surname="Qian" fullname="Zhiyun Qian"> <organization/> </author> <author initials="Z." surname="Wang" fullname="Zhongjie Wang"> <organization/> </author> <author initials="X." surname="Zheng" fullname="Xiaofeng Zheng"> <organization/> </author> <author initials="Y." surname="Huang" fullname="Youjun Huang"> <organization/> </author> <author initials="H." surname="Duan" fullname="Haixin Duan"> <organization/> </author> <date month="November" year="2020"/> </front><seriesInfo name="Proc. of<refcontent>Proc. 2020 ACMCCS'20" value=""/>SIGSAC Conference on Computer and Communications Security, CCS '20</refcontent> <seriesInfo name="DOI" value="10.1145/3372297.3417280"/> </reference> <reference anchor="DNSPOOQ" target="https://www.jsof-tech.com/wp-content/uploads/2021/01/DNSpooq-Technical-WP.pdf"> <front> <title>DNSpooq: Cache Poisoning and RCE inpopularPopular DNS Forwarder dnsmasq</title> <author initials="M." surname="Kol" fullname="Moshe Kol"> <organization/> </author> <author initials="S."surname="Oberma"surname="Oberman" fullname="ShlomiOberma">Oberman"> <organization/> </author> <date month="January" year="2021"/> </front><seriesInfo name="technical report" value=""/><refcontent>JSOF Technical Report</refcontent> </reference> <reference anchor="CVE-2000-0333"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2000-0333"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2000-0333"> <front> <title>CVE-2000-0333: A denial-of-service vulnerability in tcpdump, Ethereal, and other sniffer packages via malformed DNS packets</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <date year="2000"/> </front> </reference> <reference anchor="CVE-2020-24338"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24338"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24338"> <front> <title>CVE-2020-24338: A denial-of-service and remote code execution vulnerability in the DNS domain name record decompression functionality of picoTCP</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-27738"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27738"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27738"> <front> <title>CVE-2020-27738: A denial-of-service and remote code execution vulnerability DNS domain name record decompression functionality of Nucleus NET</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="April"year="2021"/> </front> </reference> <reference anchor="CVE-2020-25767"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25767"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25767"> <front> <title>CVE-2020-25767: An out-of-bounds read and denial-of-service vulnerability in the DNS name parsing routine of HCC Embedded NicheStack</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="August"year="2021"/> </front> </reference> <reference anchor="CVE-2020-24339"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24339"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24339"> <front> <title>CVE-2020-24339: An out-of-bounds read and denial-of-service vulnerability in the DNS domain name record decompression functionality of picoTCP</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-24335"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24335"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24335"> <front> <title>CVE-2020-24335: A memory corruption vulnerability in domain name parsing routines of uIP</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-25110"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25110"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25110"> <front> <title>CVE-2020-25110: A denial-of-service and remote code execution vulnerability in the DNS implementation of Ethernut Nut/OS</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-15795"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15795"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15795"> <front> <title>CVE-2020-15795: A denial-of-service and remote code execution vulnerability DNS domain name label parsing functionality of Nucleus NET</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="April"year="2021"/> </front> </reference> <reference anchor="CVE-2020-27009"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27009"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27009"> <front> <title>CVE-2020-27009: A denial-of-service and remote code execution vulnerability DNS domain name record decompression functionality of Nucleus NET</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="April"year="2021"/> </front> </reference> <reference anchor="CVE-2020-25107"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25107"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25107"> <front> <title>CVE-2020-25107: A denial-of-service and remote code execution vulnerability in the DNS implementation of Ethernut Nut/OS</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-17440"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-17440"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-17440"> <front> <title>CVE-2020-17440 A denial-of-service vulnerability in the DNS name parsing implementation of uIP</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-24383"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24383"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24383"> <front> <title>CVE-2020-24383: An information leak and denial-of-service vulnerability while parsing mDNS resource records in FNET</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-27736"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27736"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27736"> <front> <title>CVE-2020-27736: An information leak and denial-of-service vulnerability in the DNS name parsing functionality of Nucleus NET</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="April"year="2021"/> </front> </reference> <reference anchor="CVE-2020-25108"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25108"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25108"> <front> <title>CVE-2020-25108: A denial-of-service and remote code execution vulnerability in the DNS implementation of Ethernut Nut/OS</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-24336"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24336"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24336"> <front> <title>CVE-2020-24336: A buffer overflow vulnerability in the DNS implementation of Contiki and Contiki-NG</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-25109"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25109"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25109"> <front> <title>CVE-2020-25109: A denial-of-service and remote code execution vulnerability in the DNS implementation of Ethernut Nut/OS</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-24340"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24340"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24340"> <front> <title>CVE-2020-24340: An out-of-bounds read and denial-of-service vulnerability in the DNS response parsing functionality of picoTCP</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-24334"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24334"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-24334"> <front> <title>CVE-2020-24334: An out-of-bounds read and denial-of-service vulnerability in the DNS response parsing functionality of uIP</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="December"year="2020"/> </front> </reference> <reference anchor="CVE-2020-27737"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27737"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27737"> <front> <title>CVE-2020-27737: An information leak and denial-of-service vulnerability in the DNS response parsing functionality of Nucleus NET</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <datemonth="April"year="2021"/> </front> </reference> <reference anchor="CVE-2017-9345"target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9345"><front>target="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9345"> <front> <title>CVE-2017-9345: An infinite loop in the DNS dissector of Wireshark</title> <author> <organization>Common Vulnerabilities and Exposures</organization> </author> <date year="2017"/> </front> </reference>&I-D.ietf-dnsind-local-compression; &RFC6895; &RFC8484; &RFC7858;<!-- draft-ietf-dnsind-local-compression (Expired) --> <xi:include href="https://datatracker.ietf.org/doc/bibxml3/reference.I-D.ietf-dnsind-local-compression.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6895.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8484.xml"/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7858.xml"/> </references> </references> <sectiontitle="Acknowledgements" numbered="no" anchor="acknowledgements"><t>numbered="false" anchor="acknowledgements" toc="default"> <name>Acknowledgements</name> <t> We would like to thankShlomi Oberman,<contact fullname="Shlomi Oberman"/>, who has greatly contributed to the research that led to the creation of this document.</t> </section> </back> </rfc>