CVE-2017-13002: Out-of-bounds Read (CWE-125)
value: The AODV parser in tcpdump before 4.9.2 has a buffer over-read in print-aodv.c:aodv_extension().
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2017-09-14T06:29Z
Repository: https://github.com/the-tcpdump-group/tcpdump
Language: Other
Files changed: print-aodv.c, tests/TESTLIST, tests/hoobr_aodv_extension.out
Commit date: 2017-09-13 12:25:44 +0100
Commit message: CVE-2017-13002/AODV: Add some missing bounds checks.

In aodv_extension() do a bounds check on the extension header before we
look at it.

This fixes a buffer over-read discovered by Kamil Frankowicz.

Add a test using the capture file supplied by the reporter(s).

While we're at it, add the RFC number, and check the validity of the
length for the Hello extension.

Diff: diff --git a/print-aodv.c b/print-aodv.c
index 6cd0c9ea1..fe75db863 100644
--- a/print-aodv.c
+++ b/print-aodv.c
@@ -40,11 +40,13 @@
 
 #include "netdissect.h"
 #include "addrtoname.h"
 #include "extract.h"
 
-
+/*
+ * RFC 3561
+ */
 struct aodv_rreq {
 	uint8_t		rreq_type;	/* AODV message type (1) */
 	uint8_t		rreq_flags;	/* various flags */
 	uint8_t		rreq_zero0;	/* reserved, set to zero */
 	uint8_t		rreq_hops;	/* number of hops from originator */
@@ -176,16 +178,21 @@ static void
 aodv_extension(netdissect_options *ndo,
                const struct aodv_ext *ep, u_int length)
 {
 	const struct aodv_hello *ah;
 
+	ND_TCHECK(*ep);
 	switch (ep->type) {
 	case AODV_EXT_HELLO:
 		ah = (const struct aodv_hello *)(const void *)ep;
 		ND_TCHECK(*ah);
 		if (length < sizeof(struct aodv_hello))
 			goto trunc;
+		if (ep->length < 4) {
+			ND_PRINT((ndo, "\n\text HELLO - bad length %u", ep->length));
+			break;
+		}
 		ND_PRINT((ndo, "\n\text HELLO %ld ms",
 		    (unsigned long)EXTRACT_32BITS(&ah->interval)));
 		break;
 
 	default:
diff --git a/tests/TESTLIST b/tests/TESTLIST
index 5d164a6bf..358b5c273 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -457,10 +457,11 @@ hoobr_juniper3		hoobr_juniper3.pcap		hoobr_juniper3.out
 hoobr_parse_field	hoobr_parse_field.pcap		hoobr_parse_field.out
 hoobr_chdlc_print	hoobr_chdlc_print.pcap		hoobr_chdlc_print.out
 hoobr_lookup_nsap	hoobr_lookup_nsap.pcap		hoobr_lookup_nsap.out
 hoobr_rt6_print		hoobr_rt6_print.pcap		hoobr_rt6_print.out
 hoobr_nfs_printfh	hoobr_nfs_printfh.pcap		hoobr_nfs_printfh.out
+hoobr_aodv_extension	hoobr_aodv_extension.pcap	hoobr_aodv_extension.out
 
 # bad packets from Wilfried Kirsch
 slip-bad-direction	slip-bad-direction.pcap		slip-bad-direction.out	-ve
 
 # bad packets from Otto Airamo and Antti Levomäki
diff --git a/tests/hoobr_aodv_extension.out b/tests/hoobr_aodv_extension.out
new file mode 100644
index 000000000..79c81f561
--- /dev/null
+++ b/tests/hoobr_aodv_extension.out
@@ -0,0 +1,2 @@
+IP 48.48.48.48.654 > 48.48.48.48.12336:  aodv rrep 12308  prefix 16 hops 48
+	dst 48.48.48.48 dseq 808464432 src 48.48.48.48 808464432 ms [|hello]
diff --git a/tests/hoobr_aodv_extension.pcap b/tests/hoobr_aodv_extension.pcap
new file mode 100644
index 000000000..b02ab0507
Binary files /dev/null and b/tests/hoobr_aodv_extension.pcap differ

Fixed code: /*
 * RFC 3561
 */
	ND_TCHECK(*ep);
		if (ep->length < 4) {
			ND_PRINT((ndo, "\n\text HELLO - bad length %u", ep->length));
			break;
		}
hoobr_aodv_extension	hoobr_aodv_extension.pcap	hoobr_aodv_extension.out
IP 48.48.48.48.654 > 48.48.48.48.12336:  aodv rrep 12308  prefix 16 hops 48
	dst 48.48.48.48 dseq 808464432 src 48.48.48.48 808464432 ms [|hello]