Analysis of ISC BIND TKEY Query Response Handling DoS (CVE-2016-9131)
Another TKEY record-related bug in BIND has been fixed with a patch from the Internet Systems Consortium (ISC) that was released just after the New Year. This bug may take down BIND recursive servers by sending a simple query response with TKEY record, thereby causing a denial of service (DoS).
This potential DoS vulnerability is caused by an assertion failure in Resolver.c when caching the DNS response with TKEY Record. In this post we will analyze the BIND source codes and expose the root cause of this vulnerability.
The TKEY record (record type 249) is used to operate the secret keys information shared between DNS resolvers and servers. It is not supposed to be in the DNS ANY query response, which responds to the DNS query with Type ANY, nor stored or cached by DNS recursive servers. This bug is caused by a mismatch error when DNS recursive servers try to cache the TKEY record in the DNS ANY query response.
The following code snippet was taken from BIND version 9.10.4-P4. Comments added by me have been highlighted.
Resolver.c:
5246 static inline isc_result_t
5247 cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
5248 isc_stdtime_t now)
5249 {
…
// caching the TKEY Record in the DNS ANY query response
5620 result = dns_db_addrdataset(fctx->cache,
5621 node, NULL, now,
5622 rdataset,
5623 options,
5624 addedrdataset);
db.c:
749 isc_result_t
750 dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
751 isc_stdtime_t now, dns_rdataset_t *rdataset,
752 unsigned int options, dns_rdataset_t *addedrdataset)
753 {
754 /*
755 * Add 'rdataset' to 'node' in version 'version' of 'db'.
756 */
757
758 REQUIRE(DNS_DB_VALID(db));
759 REQUIRE(node != NULL);
760 REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
761 ((db->attributes & DNS_DBATTR_CACHE) != 0 &&
762 version == NULL && (options & DNS_DBADD_MERGE) == 0));
763 REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
764 (options & DNS_DBADD_MERGE) != 0);
765 REQUIRE(DNS_RDATASET_VALID(rdataset));
766 REQUIRE(dns_rdataset_isassociated(rdataset));
//db->rdclass comes from the ANY query which is "1", rdataset->rdclass is the "Class" property of TKEY record, which is "0xff", they doesn't match and assertion failure occurs.
767 REQUIRE(rdataset->rdclass == db->rdclass);
Following is the image showing the abortion of the affected DNS server:
Please note that authentication is NOT required to exploit this vulnerability.
Fortinet released IPS signature ISC.BIND.TKEY.Query.Reponse.Handling.DoS to address this vulnerability.