CVE-2017-13037 (published 2017-09-14T06:29Z)

The IP parser in tcpdump before 4.9.2 has a buffer over-read in print-ip.c:ip_printts().

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-125
cwe_name: Out-of-bounds Read
description: The product reads data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/the-tcpdump-group/tcpdump
commit_details: repo_url: https://github.com/the-tcpdump-group/tcpdump
author: Guy Harris
author_date: 2017-03-24 18:42:09-07:00
msg: CVE-2017-13037/IP: Add bounds checks when printing time stamp options.

This fixes a buffer over-read discovered by Bhargava Shastry,
SecT/TU Berlin.

Add a test using the capture file supplied by the reporter(s), modified
so the capture file won't be rejected as an invalid capture.
repository: repo_url: https://github.com/the-tcpdump-group/tcpdump
repo_name: the-tcpdump-group/tcpdump
description: the TCPdump network dissector
repo_language: C
owner: the-tcpdump-group
file_changes: filename: print-ip.c
change_type: ModificationType.MODIFY
diff: @@ -168,7 +168,7 @@ nextproto4_cksum(netdissect_options *ndo,
 	return (in_cksum(vec, 2));
 }
 
-static void
+static int
 ip_printts(netdissect_options *ndo,
            register const u_char *cp, u_int length)
 {
@@ -179,16 +179,18 @@ ip_printts(netdissect_options *ndo,
 
 	if (length < 4) {
 		ND_PRINT((ndo, "[bad length %u]", length));
-		return;
+		return (0);
 	}
 	ND_PRINT((ndo, " TS{"));
 	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
 	if ((length - 4) & (hoplen-1))
 		ND_PRINT((ndo, "[bad length %u]", length));
+	ND_TCHECK(cp[2]);
 	ptr = cp[2] - 1;
 	len = 0;
 	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
 		ND_PRINT((ndo, "[bad ptr %u]", cp[2]));
+	ND_TCHECK(cp[3]);
 	switch (cp[3]&0xF) {
 	case IPOPT_TS_TSONLY:
 		ND_PRINT((ndo, "TSONLY"));
@@ -217,6 +219,7 @@ ip_printts(netdissect_options *ndo,
 	for (len = 4; len < length; len += hoplen) {
 		if (ptr == len)
 			type = " ^ ";
+		ND_TCHECK2(cp[len], hoplen);
 		ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
 		       hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len])));
 		type = " ";
@@ -229,6 +232,10 @@ done:
 		ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4));
 	else
 		ND_PRINT((ndo, "}"));
+	return (0);
+
+trunc:
+	return (-1);
 }
 
 /*
@@ -278,7 +285,8 @@ ip_optprint(netdissect_options *ndo,
 			return;
 
 		case IPOPT_TS:
-			ip_printts(ndo, cp, option_len);
+			if (ip_printts(ndo, cp, option_len) == -1)
+				goto trunc;
 			break;
 
 		case IPOPT_RR:       /* fall through */

programming_language: C
filename: TESTLIST
change_type: ModificationType.MODIFY
diff: @@ -552,6 +552,7 @@ pim_header_asan-4	pim_header_asan-4.pcap		pim_header_asan-4.out	-v
 ip6_frag_asan		ip6_frag_asan.pcap		ip6_frag_asan.out	-v
 radius_attr_asan	radius_attr_asan.pcap		radius_attr_asan.out	-v
 ospf6_decode_v3_asan	ospf6_decode_v3_asan.pcap	ospf6_decode_v3_asan.out -v
+ip_ts_opts_asan		ip_ts_opts_asan.pcap		ip_ts_opts_asan.out	-v
 
 # RTP tests
 # fuzzed pcap

programming_language: Shell
filename: ip_ts_opts_asan.out
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+IP (tos 0xe2,ECT(0), id 32, offset 0, flags [+, DF, rsvd], proto ICMP (1), length 65319, options (timestamp TS{[bad length 14]TS+ADDR ^ 1229070338@0.0.52.112[|ip]), bad cksum a09b (->90a7)!)
+    149.8.33.81 > 95.18.83.227: [|icmp]

programming_language: Batchfile