CVE-2017-13015: Out-of-bounds Read (CWE-125)
value: The EAP parser in tcpdump before 4.9.2 has a buffer over-read in print-eap.c:eap_print().
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-eap.c, tests/TESTLIST, tests/eap_extract_read2_asan.out
Commit date: 2017-09-13 12:25:44 +0100
Commit message: CVE-2017-13015/EAP: Add more bounds checks.

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.

Diff: diff --git a/print-eap.c b/print-eap.c
index 125e1ee102..d76aea3395 100644
--- a/print-eap.c
+++ b/print-eap.c
@@ -180,25 +180,28 @@ eap_print(netdissect_options *ndo,
     tptr += sizeof(const struct eap_frame_t);
     tlen -= sizeof(const struct eap_frame_t);
 
     switch (eap->type) {
     case EAP_FRAME_TYPE_PACKET:
+        ND_TCHECK_8BITS(tptr);
         type = *(tptr);
+        ND_TCHECK_16BITS(tptr+2);
         len = EXTRACT_16BITS(tptr+2);
         ND_PRINT((ndo, ", %s (%u), id %u, len %u",
                tok2str(eap_code_values, "unknown", type),
                type,
                *(tptr+1),
                len));
 
         ND_TCHECK2(*tptr, len);
 
         if (type <= 2) { /* For EAP_REQUEST and EAP_RESPONSE only */
+            ND_TCHECK_8BITS(tptr+4);
             subtype = *(tptr+4);
             ND_PRINT((ndo, "\n\t\t Type %s (%u)",
-                   tok2str(eap_type_values, "unknown", *(tptr+4)),
-                   *(tptr + 4)));
+                   tok2str(eap_type_values, "unknown", subtype),
+                   subtype));
 
             switch (subtype) {
             case EAP_TYPE_IDENTITY:
                 if (len - 5 > 0) {
                     ND_PRINT((ndo, ", Identity: "));
@@ -220,46 +223,53 @@ eap_print(netdissect_options *ndo,
                  * one or more octets indicating
                  * the desired authentication
                  * type one octet per type
                  */
                 while (count < len) {
+                    ND_TCHECK_8BITS(tptr+count);
                     ND_PRINT((ndo, " %s (%u),",
                            tok2str(eap_type_values, "unknown", *(tptr+count)),
                            *(tptr + count)));
                     count++;
                 }
                 break;
 
             case EAP_TYPE_TTLS:
-                ND_PRINT((ndo, " TTLSv%u",
-                       EAP_TTLS_VERSION(*(tptr + 5)))); /* fall through */
             case EAP_TYPE_TLS:
+                ND_TCHECK_8BITS(tptr + 5);
+                if (subtype == EAP_TYPE_TTLS)
+                    ND_PRINT((ndo, " TTLSv%u",
+                           EAP_TTLS_VERSION(*(tptr + 5))));
                 ND_PRINT((ndo, " flags [%s] 0x%02x,",
                        bittok2str(eap_tls_flags_values, "none", *(tptr+5)),
                        *(tptr + 5)));
 
                 if (EAP_TLS_EXTRACT_BIT_L(*(tptr+5))) {
+                    ND_TCHECK_32BITS(tptr + 6);
 		    ND_PRINT((ndo, " len %u", EXTRACT_32BITS(tptr + 6)));
                 }
                 break;
 
             case EAP_TYPE_FAST:
+                ND_TCHECK_8BITS(tptr + 5);
                 ND_PRINT((ndo, " FASTv%u",
                        EAP_TTLS_VERSION(*(tptr + 5))));
                 ND_PRINT((ndo, " flags [%s] 0x%02x,",
                        bittok2str(eap_tls_flags_values, "none", *(tptr+5)),
                        *(tptr + 5)));
 
                 if (EAP_TLS_EXTRACT_BIT_L(*(tptr+5))) {
+                    ND_TCHECK_32BITS(tptr + 6);
                     ND_PRINT((ndo, " len %u", EXTRACT_32BITS(tptr + 6)));
                 }
 
                 /* FIXME - TLV attributes follow */
                 break;
 
             case EAP_TYPE_AKA:
             case EAP_TYPE_SIM:
+                ND_TCHECK_8BITS(tptr + 5);
                 ND_PRINT((ndo, " subtype [%s] 0x%02x,",
                        tok2str(eap_aka_subtype_values, "unknown", *(tptr+5)),
                        *(tptr + 5)));
 
                 /* FIXME - TLV attributes follow */
diff --git a/tests/TESTLIST b/tests/TESTLIST
index b16737cf6a..a20e59898f 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -510,10 +510,11 @@ wb-oobr			wb-oobr.pcap			wb-oobr.out	-v
 
 # bad packets from Bhargava Shastry
 lldp_asan		lldp_asan.pcap			lldp_asan.out	-v
 extract_read2_asan	extract_read2_asan.pcap		extract_read2_asan.out	-v
 getname_2_read4_asan	getname_2_read4_asan.pcap	getname_2_read4_asan.out	-v
+eap_extract_read2_asan	eap_extract_read2_asan.pcap	eap_extract_read2_asan.out	-v
 
 # RTP tests
 # fuzzed pcap
 rtp-seg-fault-1  rtp-seg-fault-1.pcap  rtp-seg-fault-1.out  -v -T rtp
 rtp-seg-fault-2  rtp-seg-fault-2.pcap  rtp-seg-fault-2.out  -v -T rtp
diff --git a/tests/eap_extract_read2_asan.out b/tests/eap_extract_read2_asan.out
new file mode 100644
index 0000000000..da96d48045
--- /dev/null
+++ b/tests/eap_extract_read2_asan.out
@@ -0,0 +1,2 @@
+EAP packet (0) v155, len 0
+	[|EAP]
diff --git a/tests/eap_extract_read2_asan.pcap b/tests/eap_extract_read2_asan.pcap
new file mode 100644
index 0000000000..26e334eb47
Binary files /dev/null and b/tests/eap_extract_read2_asan.pcap differ

Vulnerable code:                    tok2str(eap_type_values, "unknown", *(tptr+4)),
                   *(tptr + 4)));
                ND_PRINT((ndo, " TTLSv%u",
                       EAP_TTLS_VERSION(*(tptr + 5)))); /* fall through */
Fixed code:         ND_TCHECK_8BITS(tptr);
        ND_TCHECK_16BITS(tptr+2);
            ND_TCHECK_8BITS(tptr+4);
                   tok2str(eap_type_values, "unknown", subtype),
                   subtype));
                    ND_TCHECK_8BITS(tptr+count);
                ND_TCHECK_8BITS(tptr + 5);
                if (subtype == EAP_TYPE_TTLS)
                    ND_PRINT((ndo, " TTLSv%u",
                           EAP_TTLS_VERSION(*(tptr + 5))));
                    ND_TCHECK_32BITS(tptr + 6);
                ND_TCHECK_8BITS(tptr + 5);
                    ND_TCHECK_32BITS(tptr + 6);
                ND_TCHECK_8BITS(tptr + 5);
eap_extract_read2_asan	eap_extract_read2_asan.pcap	eap_extract_read2_asan.out	-v
EAP packet (0) v155, len 0
	[|EAP]