-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Advisory: ISC BIND Logic Error TSIG Remote Denial of Service Advisory ID: TKADV2020-002 Revision: 1.0 Release Date: 21-May-2020 Last Modified: 21-May-2020 Date Reported: 24-Mar-2020 Author: Tobias Klein (tk at trapkit.de) Affected Software: According to the vendor, the following versions are affected: ISC BIND 9.0.0 to 9.11.18, 9.12.0 to 9.12.4-P2, 9.14.0 to 9.14.11, 9.16.0 to 9.16.2, and releases 9.17.0 to 9.17.1 of the 9.17 experimental development branch. All releases in the obsolete 9.13 and 9.15 development branches. All releases of BIND Supported Preview Edition from 9.9.3-S1 to 9.11.18-S1. Vendor URL: https://www.isc.org/bind/ Time-to-fix: 57 days Solution Status: Fixed (patched releases of ISC BIND are available) CVE-ID: CVE-2020-8617 ========================== Vulnerability Description: ========================== ISC BIND is prone to a remote denial of service vulnerability. This issue is caused by a logic error when processing specially crafted TSIG resource records in DNS queries. A remote attacker who can deliberately trigger the condition can cause BIND to exit, denying service to other clients. This vulnerability affects both recursive and authoritative DNS servers and can be triggered with a single UDP packet. The vulnerability is present for any server with a TSIG key in its configuration. Since BIND, by default, configures a local session key even on servers whose configuration does not otherwise make use of it, almost all current BIND servers are vulnerable. For more information on the vulnerability please see "FAQ and Supplemental Information for CVE-2020-8617" [REF1]. ================== Technical Details: ================== The function dns_tsig_verify() found in lib/dns/tsig.c is responsible for verifying the transaction signature (TSIG). However, there are different code paths where, if an invalid signature is found in a DNS query, it is possible to have the function return a misleading error code. This logic error then leads to an INSIST assertation failure in dns_tsig_sign(), which is also found in lib/dns/tsig.c. bind-9.16.1/lib/dns/tsig.c: .. 1070 isc_result_t 1071 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, 1072 dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2) { .. 1099 msg->verified_sig = 0; 1100 msg->tsigstatus = dns_tsigerror_badsig; .. 1234 if (tsig.siglen > 0) { .. 1363 } else if (tsig.error != dns_tsigerror_badsig && 1364 tsig.error != dns_tsigerror_badkey) 1365 { 1366 tsig_log(msg->tsigkey, 2, "signature was empty"); 1367 return (DNS_R_TSIGVERIFYFAILURE); 1368 } 1369 1370 /* 1371 * Here at this point, the MAC has been verified. Even if any of 1372 * the following code returns a TSIG error, the reply will be 1373 * signed and WILL always include the request MAC in the digest 1374 * computation. 1375 */ 1376 1377 /* 1378 * Is the time ok? 1379 */ 1380 if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { 1381 msg->tsigstatus = dns_tsigerror_badtime; 1382 tsig_log(msg->tsigkey, 2, "signature has expired"); 1383 ret = DNS_R_CLOCKSKEW; 1384 goto cleanup_context; 1385 } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) { 1386 msg->tsigstatus = dns_tsigerror_badtime; 1387 tsig_log(msg->tsigkey, 2, "signature is in the future"); 1388 ret = DNS_R_CLOCKSKEW; 1389 goto cleanup_context; 1390 } .. 1425 cleanup_context: 1426 if (ctx != NULL) { 1427 dst_context_destroy(&ctx); 1428 } 1429 1430 return (ret); 1431 } .. In line 1099, the variable msg->verified_sig is initialized with zero, indicating an unverified signature or, more specifically, an unverified MAC (see RFC 2845). In line 1100 the variable msg->tsigstatus is initialized with the error code dns_tsigerror_badsig (which is equivalent to BADSIG as specified in RFC 2845). Then, in line 1234, it is checked if the length of the MAC (MAC Size) found in the TSIG resource record is greater than zero. If this is not the case, then the error code in the TSIG resource record is checked (see lines 1363 and 1364). This is where the logic error happens. TSIG error codes are intended to notify the client that an error occurred. So checking the error code only makes sense when processing TSIG resource records found in DNS responses. However, BIND will also accept and process TSIG error codes found in DNS queries. If the TSIG error code found in a DNS query matches either dns_tsigerror_badsig or dns_tsigerror_badkey (which is equivalent to BADKEY as specified in RFC 2845), then the execution will continue at line 1380. At this point, the variable msg->verified_sig still contains the value 0, indicating an unverified MAC (although otherwise described in the comment found at line 1371). In lines 1380 and 1385, it is then checked if the server time is outside the time interval specified by the two timer values in the TSIG resource record (which is: Time Signed, plus/minus Fudge). If the server time is outside the specified time interval, then the error code dns_tsigerror_badtime (which is equivalent to BADTIME as specified in RFC 2845) will be assigned to the variable msg->tsigstatus (see lines 1381 and 1386), indicating a timing skew. Next, the function returns with DNS_R_CLOCKSKEW (see lines 1383, 1388 and 1430). To summarize: By crafting a TSIG resource record with a zero-length signature (MAC size == 0 and empty MAC), an error code of BADSIG or BADKEY, and a time interval that is outside of the server time, it is possible to return from dns_tsig_verify(), and at the same time ensure, that the variable msg->tsigstatus contains the error code dns_tsigerror_badtime and the variable msg->verified_sig is set to 0. bind-9.16.1/lib/dns/message.c: .. 2677 isc_result_t 2678 dns_message_reply(dns_message_t *msg, bool want_question_section) { .. 2724 msg->querytsigstatus = msg->tsigstatus; .. Later on in the execution, the function dns_message_reply() is called. In line 2724 of this function, the value of the variable msg->tsigstatus is assigned to the variable msg->querytsigstatus. As a result, the variable msg->querytsigstatus now contains the value of the error code dns_tsigerror_badtime. bind-9.16.1/lib/dns/tsig.c: .. 756 isc_result_t 757 dns_tsig_sign(dns_message_t *msg) { .. 809 tsig.error = msg->querytsigstatus; .. 826 if ((key->key != NULL) && (tsig.error != dns_tsigerror_badsig) && 827 (tsig.error != dns_tsigerror_badkey)) 828 { .. 857 INSIST(msg->verified_sig); .. Then, even later on in the execution, the function dns_tsig_sign() is called. In line 809 of this function, the value of the variable msg->querytsigstatus is assigned to the variable tsig.error. As a result, the variable tsig.error now contains the value of the error code dns_tsigerror_badtime. Then, in lines 826 and 827 it is checked, among other things, whether the error code stored in tsig.error matches either dns_tsigerror_badsig or dns_tsigerror_badkey. As tsig.error contains the value of the error code dns_tsigerror_badtime, the if condition is evaluated as true and the code inside the if block is executed. The INSIST assertation at line 857 then fails because msg->verified_sig has a value of 0, causing BIND to exit. ========= Solution: ========= Upgrade to the patched release most closely related to your current version of BIND (see also [REF1] and [REF2]). Or apply a patch for this problem to an older version of BIND (see [REF3], [REF4] and [REF5]). ==================== Disclosure Timeline: ==================== 24-Mar-2020 - Initial vendor notification. 24-Mar-2020 - Initial vendor response. 17-Apr-2020 - Status update by ISC. 19-May-2020 - Patched releases of BIND are available. ISC derestricts access to the issue tracker entry for the bug, making the initial draft release of this advisory publicly accessible (see [REF6]). 21-May-2020 - Release date of this security advisory. ======== Credits: ======== Vulnerability found and advisory written by Tobias Klein. =========== References: =========== [REF1] https://kb.isc.org/docs/cve-2020-8617-faq-and-supplemental-information [REF2] https://kb.isc.org/docs/cve-2020-8617 [REF3] https://downloads.isc.org/isc/bind9/9.11.19/patches/CVE-2020-8617.patch [REF4] https://downloads.isc.org/isc/bind9/9.14.12/patches/CVE-2020-8617.patch [REF5] https://downloads.isc.org/isc/bind9/9.16.3/patches/CVE-2020-8617.patch [REF6] https://gitlab.isc.org/isc-projects/bind9/-/issues/1703 URL for this advisory: https://www.trapkit.de/advisories/TKADV2020-002.txt URL for PGP signature key: https://www.trapkit.de/advisories/tk-advisories-signature-key.asc ================= Revision History: ================= Revision 0.1 - Initial draft release to the vendor Revision 1.0 - Public release =========== Disclaimer: =========== The information within this advisory may change without notice. Use of this information constitutes acceptance for use in an AS IS condition. There are no warranties, implied or express, with regard to this information. In no event shall the author be liable for any direct or indirect damages whatsoever arising out of or in connection with the use or spread of this information. Any use of this information is at the user's own risk. Copyright 2020 Tobias Klein. All rights reserved. -----BEGIN PGP SIGNATURE----- iF0EARECAB0WIQQf8YTj2CneP4UWV66RfGBwAhuEQQUCXsbFgAAKCRCRfGBwAhuE QcUiAKCbn5H4yfNfc0PcX33Aod+STCsZGwCdHqbHeKi0ygVn8MjmSVLBoFpMOAA= =90SX -----END PGP SIGNATURE-----