This text is on http://www.unbound.net/downloads/CVE-2011-4528.txt Subject: Unbound denial of service vulnerabilities from nonstandard redirection and denial of existence [ VU#209659 CVE-2011-4528 ] == Summary Unbound crashes when confronted with a non-standard response from a server for a domain. This domain produces duplicate RRs from a certain type and is DNSSEC signed. Unbound also crashes when confronted with a query that eventually, and under specific circumstances, resolves to a domain that misses expected NSEC3 records. These two problems were discovered within 24 hours, hence a combined vulnerability disclosure. By constructing the non standard responses an attacker can use these vulnerabilities for a DOS attack. To our knowledge 'denial of service' is the only type of exploit possible. NLnet Labs has patched the code. == Description 1: crash on signed duplicate Resource Records There are authoritative servers that erroneously send duplicated redirection Resource Records. Unbound has had a workaround that deals with this problem since version 1.0.1 whereby it ignores the duplicate answers. At the time, likely, no DNSSEC signed versions of such zones existed and only recently such misbehaving authority servers also started serving signed duplicate RRs causing improper memory allocation in a portion of the workaround code. Referencing this improper allocated data causes a crash which can look like 'uninitialised lock', segmentation faults or free() errors as it tries to free memory that was never allocated. == Description 2: crash on missing NSEC3 Resource Records. If an authority server sends a reply for an NSEC3-signed zone, and Unbound is configured to validate that zone, then a malformed response can trigger an assertion failure: when an authority server sends a response that contains RR types that trigger special processing and where part of the non-existence proof is missing then an assertion failure is triggered in unbound. This response case was observed in the wild on authority servers that host zones at different points in the hierarchy at the same time. The code crashes at assertion failure validator/val_nsec3.c:1214: nsec3_do_prove_nodata: assertion ce.nc_rrset failed Or, if assertions are not compiled it, it crashes soon after as it attempts to access an expected NSEC3 RR. == Workaround If the misbehaving domain is known then it can be blocked block domain names that exploit this with local-zone: "misbehaving.example.com" refuse lines in config. There is no easy way to determine what misbehaving domains, except by carefully analyzing the unbound log files with a high verbosity. == Solution Download patched version of unbound, or apply the patch manually. + Downloading Patched Versions * 1.4.14 is released with the patch, but 1.4.14rc1 is vulnerable. http://www.unbound.net/downloads/unbound-1.4.14.tar.gz * 1.4.13p2 can be downloaded, it is 1.4.13 with the patch applied. http://www.unbound.net/downloads/unbound-1.4.13p2.tar.gz sha1 474339a182147ee91ec712057f75f417a455a8de sha256 2f6814a4cc33883964c2833075990328fa330f966c3804ad20a92807428c22c1 + Applying the Patch manually The patch to apply can be downloaded here and is verbatim included at the end of this description. For unbound version 1.4.0 - 1.4.13 the patch is: http://www.unbound.net/downloads/patch_CVE-2011-4528_unbound_140-1413.diff For unbound version 1.0.1 - 1.3.4 the patch is: http://www.unbound.net/downloads/patch_CVE-2011-4528_unbound_101-134.diff (different patch because surrounding code was changed, same contents). Apply the patch on unbound source directory with 'patch -p0 rr_count != 1) { + struct rr_parse* sig; verbose(VERB_ALGO, "Found CNAME rrset with " "size > 1: %u", (unsigned)rrset->rr_count); /* use the first CNAME! */ rrset->rr_count = 1; rrset->size = rrset->rr_first->size; + for(sig=rrset->rrsig_first; sig; sig=sig->next) + rrset->size += sig->size; rrset->rr_last = rrset->rr_first; rrset->rr_first->next = NULL; } Index: validator/val_nsec3.c =================================================================== --- validator/val_nsec3.c (revision 2573) +++ validator/val_nsec3.c (working copy) @@ -1099,6 +1099,10 @@ return sec_status_bogus; } + if(!ce.nc_rrset) { + verbose(VERB_ALGO, "nsec3 nodata proof: no next closer nsec3"); + return sec_status_bogus; + } /* We need to make sure that the covering NSEC3 is opt-out. */ log_assert(ce.nc_rrset); if(!nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) { Before 1.4.0 the val_nsec3.c file has to be patched with: Index: validator/val_nsec3.c =================================================================== --- validator/val_nsec3.c (revision 2573) +++ validator/val_nsec3.c (working copy) @@ -1227,6 +1227,10 @@ * covering NSEC3 was opt-out -- the proveClosestEncloser step already * checked to see if the closest encloser was a delegation or DNAME. */ + if(!ce.nc_rrset) { + verbose(VERB_ALGO, "nsec3 nodata proof: no next closer nsec3"); + return sec_status_bogus; + } log_assert(ce.nc_rrset); if(!nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) { verbose(VERB_ALGO, "nsec3 provenods: covering NSEC3 was not "