Maintained by: NLnet Labs

[Unbound-users] VU#209659 CVE-2011-4528: Unbound denial of service vulnerabilities from nonstandard redirection and denial of existence

W.C.A. Wijngaards
Mon Dec 19 12:25:11 CET 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

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 <filename'
then run 'make install' to install unbound.

Patch:

Code patch:

Index: iterator/iter_scrub.c
===================================================================
- --- iterator/iter_scrub.c	(revision 2571)
+++ iterator/iter_scrub.c	(working copy)
@@ -187,11 +187,14 @@
 	size_t* snamelen)
 {
 	if(rrset->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 "


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQIcBAEBAgAGBQJO7x8WAAoJEJ9vHC1+BF+NQ/kP/RuIjGL6uQADV+mg2TLjgaPL
QbKKD/tjBgZxzS2X456UduRxMY+jdV4P0rvm5Frd5uL2ZB9vKA/6SVhiscR9IKZA
MCHg+AGQPAauX5blnMkGRnsWdOpWeTE7xAMidf6FHwq1fNwivDAJFxmJQNIsc5Xm
EvtOsxwyxOkhB1EVoslkUrBr24u1+lmnhK5OdtYU7GGn5cwlyGax6zEpZlgDsHBq
lZ945WIHSI7ZXhfzycEdOup0IKgcLx1cH63kuI/TyeZbFT+RlVG1LWoc2BNhhNbc
1m52rbzi8g6zlR/6STCwjLoYJ1K3uslKTd/lnDt3x8E4yTM2h9m72iwRfu1slMbV
54sYr/uJ9/lUIICJgoTyQ7Vzu+NftFdTcfH+IC2ipzYvsMFG/fRcmMfpo3kwlXtS
Emga+fd/a5qa/U4yB711oJxUV3adR0Kb61499JAr3dFIioMCkXW+gxB+qc8jhGWM
4hJNYcZsVLUlVGf1uJorMu2dB9etQlH69NqXEfbMAdPEpe32e0RO0hR2vqSGdtSH
xbIdOb7u7jSxIKTO8LB+xIwGvQzT4iJHhWI1zi7yuQjPlotnjsYPGR9lpv14GXn9
ULlji6E08ww0mQDl2tzWNMhedShRarSJY5aEW2HOK2QmwK82DBFraN3QXGB/HNrR
1rxArm1HnfvdwTK5Umx/
=XMh1
-----END PGP SIGNATURE-----