CVE-2017-13008: Out-of-bounds Read (CWE-125)
value: The IEEE 802.11 parser in tcpdump before 4.9.2 has a buffer over-read in print-802_11.c:parse_elements().
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-802_11.c, tests/TESTLIST, tests/ieee802.11_rates_oobr.out
Commit date: 2017-09-13 12:25:44 +0100
Commit message: CVE-2017-13008/IEEE 802.11: Fix TIM bitmap copy to copy from p + offset.

offset has already been advanced to point to the bitmap; we shouldn't
add the amount to advance again.

This fixes a buffer over-read discovered by Brian 'geeknik' Carpenter.

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

While we're at it, remove some redundant tests - we've already checked,
before the case statement, whether we have captured the entire
information element and whether the entire information element is
present in the on-the-wire packet; in the cases for particular IEs, we
only need to make sure we don't go past the end of the IE.

Diff: diff --git a/print-802_11.c b/print-802_11.c
index 17c1f70cb..d8bf039de 100644
--- a/print-802_11.c
+++ b/print-802_11.c
@@ -1037,14 +1037,10 @@ parse_elements(netdissect_options *ndo,
 			offset += 2;
 			length -= 2;
 			if (ssid.length != 0) {
 				if (ssid.length > sizeof(ssid.ssid) - 1)
 					return 0;
-				if (!ND_TTEST2(*(p + offset), ssid.length))
-					return 0;
-				if (length < ssid.length)
-					return 0;
 				memcpy(&ssid.ssid, p + offset, ssid.length);
 				offset += ssid.length;
 				length -= ssid.length;
 			}
 			ssid.ssid[ssid.length] = '\0';
@@ -1066,14 +1062,10 @@ parse_elements(netdissect_options *ndo,
 			length -= 2;
 			if (challenge.length != 0) {
 				if (challenge.length >
 				    sizeof(challenge.text) - 1)
 					return 0;
-				if (!ND_TTEST2(*(p + offset), challenge.length))
-					return 0;
-				if (length < challenge.length)
-					return 0;
 				memcpy(&challenge.text, p + offset,
 				    challenge.length);
 				offset += challenge.length;
 				length -= challenge.length;
 			}
@@ -1095,14 +1087,10 @@ parse_elements(netdissect_options *ndo,
 			offset += 2;
 			length -= 2;
 			if (rates.length != 0) {
 				if (rates.length > sizeof rates.rate)
 					return 0;
-				if (!ND_TTEST2(*(p + offset), rates.length))
-					return 0;
-				if (length < rates.length)
-					return 0;
 				memcpy(&rates.rate, p + offset, rates.length);
 				offset += rates.length;
 				length -= rates.length;
 			}
 			/*
@@ -1187,11 +1175,11 @@ parse_elements(netdissect_options *ndo,
 				return 0;
 			memcpy(&tim.count, p + offset, 3);
 			offset += 3;
 			length -= 3;
 
-			memcpy(tim.bitmap, p + offset + 3, tim.length - 3);
+			memcpy(tim.bitmap, p + offset, tim.length - 3);
 			offset += tim.length - 3;
 			length -= tim.length - 3;
 			/*
 			 * Present and not truncated.
 			 *
diff --git a/tests/TESTLIST b/tests/TESTLIST
index 5f18a0574..17ee6fb73 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -436,10 +436,11 @@ ipv6-next-header-oobr-1	ipv6-next-header-oobr-1.pcap	ipv6-next-header-oobr-1.out
 ipv6-next-header-oobr-2	ipv6-next-header-oobr-2.pcap	ipv6-next-header-oobr-2.out
 ipv6-rthdr-oobr		ipv6-rthdr-oobr.pcap		ipv6-rthdr-oobr.out
 ieee802.11_tim_ie_oobr	ieee802.11_tim_ie_oobr.pcap	ieee802.11_tim_ie_oobr.out
 decnet-shorthdr-oobr	decnet-shorthdr-oobr.pcap	decnet-shorthdr-oobr.out
 isakmp-3948-oobr-2	isakmp-3948-oobr-2.pcap		isakmp-3948-oobr-2.out
+ieee802.11_rates_oobr	ieee802.11_rates_oobr.pcap	ieee802.11_rates_oobr.out
 
 # bad packets from Kamil Frankowicz
 snmp-heapoverflow-1	snmp-heapoverflow-1.pcap	snmp-heapoverflow-1.out
 snmp-heapoverflow-2	snmp-heapoverflow-2.pcap	snmp-heapoverflow-2.out
 isoclns-heapoverflow-2	isoclns-heapoverflow-2.pcap	isoclns-heapoverflow-2.out	-e -c1
diff --git a/tests/ieee802.11_rates_oobr.out b/tests/ieee802.11_rates_oobr.out
new file mode 100644
index 000000000..222eed335
--- /dev/null
+++ b/tests/ieee802.11_rates_oobr.out
@@ -0,0 +1 @@
+fhset 48 fhpat 48 48dBm signal 48dB signal 48dB noise [|802.11]Beacon IBSS, PRIVACY[|802.11]
diff --git a/tests/ieee802.11_rates_oobr.pcap b/tests/ieee802.11_rates_oobr.pcap
new file mode 100644
index 000000000..bb2819a8c
Binary files /dev/null and b/tests/ieee802.11_rates_oobr.pcap differ

Vulnerable code: 				if (!ND_TTEST2(*(p + offset), ssid.length))
					return 0;
				if (length < ssid.length)
					return 0;
				if (!ND_TTEST2(*(p + offset), challenge.length))
					return 0;
				if (length < challenge.length)
					return 0;
				if (!ND_TTEST2(*(p + offset), rates.length))
					return 0;
				if (length < rates.length)
					return 0;
			memcpy(tim.bitmap, p + offset + 3, tim.length - 3);
Fixed code: 			memcpy(tim.bitmap, p + offset, tim.length - 3);
ieee802.11_rates_oobr	ieee802.11_rates_oobr.pcap	ieee802.11_rates_oobr.out
fhset 48 fhpat 48 48dBm signal 48dB signal 48dB noise [|802.11]Beacon IBSS, PRIVACY[|802.11]