aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni <matzeton@googlemail.com>2021-10-18 23:16:32 +0200
committerGitHub <noreply@github.com>2021-10-18 23:16:32 +0200
commited51987e3a4838dd9aef27dfab2c0651f2f52836 (patch)
treefde07d774b7ef89b3d4b400f0c2af3f07f4f70ce
parent7d3c3b23f8b9749690b8c5f345b7bc489b3666ac (diff)
Fix broken fuzz_process_packet fuzzer by adding a call to ndpi_finalize_initialization(). (#1334)
* fixed several memory errors (heap-overflow, unitialized memory, etc) * ability to build fuzz_process_packet with a main() allowing to replay crash data generated with fuzz_process_packet by LLVMs libfuzzer * temporarily disable fuzzing if `tests/do.sh` executed with env FUZZY_TESTING_ENABLED=1 Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r--example/reader_util.c5
-rw-r--r--fuzz/Makefile.am11
-rw-r--r--fuzz/fuzz_process_packet.c62
-rw-r--r--src/include/ndpi_main.h2
-rw-r--r--src/lib/ndpi_main.c28
-rw-r--r--src/lib/protocols/bittorrent.c7
-rw-r--r--src/lib/protocols/http.c4
-rw-r--r--src/lib/protocols/irc.c18
-rw-r--r--src/lib/protocols/kerberos.c35
-rw-r--r--src/lib/protocols/ntp.c2
-rw-r--r--src/lib/protocols/ppstream.c2
-rw-r--r--src/lib/protocols/tls.c97
-rwxr-xr-xtests/do.sh.in3
-rw-r--r--tests/pcap/fuzz-2021-10-13.pcapbin0 -> 239 bytes
-rw-r--r--tests/result/fuzz-2021-10-13.pcap.out12
15 files changed, 212 insertions, 76 deletions
diff --git a/example/reader_util.c b/example/reader_util.c
index 453660ce7..35632920e 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -980,7 +980,7 @@ static struct ndpi_flow_info *get_ndpi_flow_info6(struct ndpi_workflow * workflo
u_int8_t l4proto = iph6->ip6_hdr.ip6_un1_nxt;
u_int16_t ip_len = ntohs(iph6->ip6_hdr.ip6_un1_plen);
const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr));
- if(ndpi_handle_ipv6_extension_headers(NULL, &l4ptr, &ip_len, &l4proto) != 0) {
+ if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &l4proto) != 0) {
return(NULL);
}
iph.protocol = l4proto;
@@ -1908,8 +1908,9 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow,
return(nproto); /* Too short for IPv6 payload*/
const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr));
+ u_int16_t ipsize = header->caplen - ip_offset;
- if(ndpi_handle_ipv6_extension_headers(NULL, &l4ptr, &ip_len, &proto) != 0) {
+ if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &proto) != 0) {
return(nproto);
}
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
index 7858c3371..ade21ac5a 100644
--- a/fuzz/Makefile.am
+++ b/fuzz/Makefile.am
@@ -1,4 +1,4 @@
-bin_PROGRAMS = fuzz_process_packet fuzz_ndpi_reader fuzz_ndpi_reader_with_main
+bin_PROGRAMS = fuzz_process_packet fuzz_process_packet_with_main fuzz_ndpi_reader fuzz_ndpi_reader_with_main
fuzz_process_packet_SOURCES = fuzz_process_packet.c
fuzz_process_packet_CFLAGS =
@@ -13,6 +13,15 @@ fuzz_process_packet_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
$(fuzz_process_packet_LDFLAGS) $(LDFLAGS) -o $@
+fuzz_process_packet_with_main_SOURCES = fuzz_process_packet.c
+fuzz_process_packet_with_main_CFLAGS = -DBUILD_MAIN
+fuzz_process_packet_with_main_LDADD = ../src/lib/libndpi.a
+fuzz_process_packet_with_main_LDFLAGS = $(ADDITIONAL_LIBS) $(LIBS)
+# force usage of CXX for linker
+fuzz_process_packet_with_main_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_process_packet_with_main_LDFLAGS) $(LDFLAGS) -o $@
+
fuzz_ndpi_reader_SOURCES = fuzz_ndpi_reader.c
fuzz_ndpi_reader_CFLAGS = -I../example/
fuzz_ndpi_reader_LDADD = ../example/libndpiReader.a ../src/lib/libndpi.a
diff --git a/fuzz/fuzz_process_packet.c b/fuzz/fuzz_process_packet.c
index 5af15afba..9efd80799 100644
--- a/fuzz/fuzz_process_packet.c
+++ b/fuzz/fuzz_process_packet.c
@@ -15,6 +15,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
ndpi_set_protocol_detection_bitmask2(ndpi_info_mod, &all);
src = ndpi_malloc(SIZEOF_ID_STRUCT);
dst = ndpi_malloc(SIZEOF_ID_STRUCT);
+ ndpi_finalize_initialization(ndpi_info_mod);
}
struct ndpi_flow_struct *ndpi_flow = ndpi_flow_malloc(SIZEOF_FLOW_STRUCT);
@@ -26,3 +27,64 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return 0;
}
+
+#ifdef BUILD_MAIN
+int main(int argc, char ** argv)
+{
+ FILE * data_file;
+ long data_file_size;
+ uint8_t * data_buffer;
+ int test_retval;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s: [data-file]\n",
+ (argc > 0 ? argv[0] : "fuzz_process_packet_with_main"));
+ return 1;
+ }
+
+ data_file = fopen(argv[1], "r");
+ if (data_file == NULL) {
+ perror("fopen failed");
+ return 1;
+ }
+
+ if (fseek(data_file, 0, SEEK_END) != 0) {
+ perror("fseek(SEEK_END) failed");
+ fclose(data_file);
+ return 1;
+ }
+
+ data_file_size = ftell(data_file);
+ if (data_file_size < 0) {
+ perror("ftell failed");
+ fclose(data_file);
+ return 1;
+ }
+
+ if (fseek(data_file, 0, SEEK_SET) != 0) {
+ perror("fseek(0, SEEK_SET) failed");
+ fclose(data_file);
+ return 1;
+ }
+
+ data_buffer = malloc(data_file_size);
+ if (data_buffer == NULL) {
+ perror("malloc failed");
+ fclose(data_file);
+ return 1;
+ }
+
+ if (fread(data_buffer, sizeof(*data_buffer), data_file_size, data_file) != (size_t)data_file_size) {
+ perror("fread failed");
+ fclose(data_file);
+ free(data_buffer);
+ return 1;
+ }
+
+ test_retval = LLVMFuzzerTestOneInput(data_buffer, data_file_size);
+ fclose(data_file);
+ free(data_buffer);
+
+ return test_retval;
+}
+#endif
diff --git a/src/include/ndpi_main.h b/src/include/ndpi_main.h
index 3e8825819..35efaa0b9 100644
--- a/src/include/ndpi_main.h
+++ b/src/include/ndpi_main.h
@@ -144,7 +144,7 @@ extern "C" {
#define ndpi_match_strprefix(payload, payload_len, str) \
ndpi_match_prefix((payload), (payload_len), (str), (sizeof(str)-1))
- int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi_str,
+ int ndpi_handle_ipv6_extension_headers(u_int16_t l3len,
const u_int8_t ** l4ptr, u_int16_t * l4len,
u_int8_t * nxt_hdr);
void ndpi_set_risk(struct ndpi_detection_module_struct *ndpi_str,
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index cd24e52df..f2b6aa334 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -4107,18 +4107,19 @@ void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *n
/* handle extension headers in IPv6 packets
* arguments:
+ * l3len: the packet length excluding the IPv6 header
* l4ptr: pointer to the byte following the initial IPv6 header
- * l4len: the length of the IPv6 packet excluding the IPv6 header
+ * l4len: the length of the IPv6 packet parsed from the IPv6 header
* nxt_hdr: next header value from the IPv6 header
* result:
- * l4ptr: pointer to the start of the actual packet payload
- * l4len: length of the actual payload
- * nxt_hdr: protocol of the actual payload
+ * l4ptr: pointer to the start of the actual layer 4 header
+ * l4len: length of the actual layer 4 header
+ * nxt_hdr: first byte of the layer 4 packet
* returns 0 upon success and 1 upon failure
*/
-int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi_str, const u_int8_t **l4ptr,
+int ndpi_handle_ipv6_extension_headers(u_int16_t l3len, const u_int8_t **l4ptr,
u_int16_t *l4len, u_int8_t *nxt_hdr) {
- while((*nxt_hdr == 0 || *nxt_hdr == 43 || *nxt_hdr == 44 || *nxt_hdr == 60 || *nxt_hdr == 135 || *nxt_hdr == 59)) {
+ while(l3len > 1 && (*nxt_hdr == 0 || *nxt_hdr == 43 || *nxt_hdr == 44 || *nxt_hdr == 60 || *nxt_hdr == 135 || *nxt_hdr == 59)) {
u_int16_t ehdr_len, frag_offset;
// no next header
@@ -4132,6 +4133,11 @@ int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi
return(1);
}
+ if (l3len < 5) {
+ return 1;
+ }
+ l3len -= 5;
+
*nxt_hdr = (*l4ptr)[0];
frag_offset = ntohs(*(u_int16_t *)((*l4ptr) + 2)) >> 3;
// Handle ipv6 fragments as the ipv4 ones: keep the first fragment, drop the others
@@ -4152,6 +4158,11 @@ int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi
ehdr_len *= 8;
ehdr_len += 8;
+ if (ehdr_len > l3len) {
+ return 1;
+ }
+ l3len -= ehdr_len;
+
if(*l4len < ehdr_len) {
return(1);
}
@@ -4249,7 +4260,7 @@ static u_int8_t ndpi_detection_get_l4_internal(struct ndpi_detection_module_stru
l4protocol = iph_v6->ip6_hdr.ip6_un1_nxt;
// we need to handle IPv6 extension headers if present
- if(ndpi_handle_ipv6_extension_headers(ndpi_str, &l4ptr, &l4len, &l4protocol) != 0) {
+ if(ndpi_handle_ipv6_extension_headers(l3_len - sizeof(struct ndpi_ipv6hdr), &l4ptr, &l4len, &l4protocol) != 0) {
return(1);
}
@@ -7009,6 +7020,7 @@ int ndpi_match_hostname_protocol(struct ndpi_detection_module_struct *ndpi_struc
else
what = name, what_len = name_len;
+ memset(&ret_match, 0, sizeof(ret_match));
subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, what, what_len,
&ret_match, master_protocol);
@@ -7518,7 +7530,7 @@ int ndpi_check_dga_name(struct ndpi_detection_module_struct *ndpi_str,
if(isdigit(name[0])) {
struct in_addr ip_addr;
-
+
ip_addr.s_addr = inet_addr(name);
if(strcmp(inet_ntoa(ip_addr), name) == 0)
return(0); /* Ignore numeric IPs */
diff --git a/src/lib/protocols/bittorrent.c b/src/lib/protocols/bittorrent.c
index f49c7f31a..f78706195 100644
--- a/src/lib/protocols/bittorrent.c
+++ b/src/lib/protocols/bittorrent.c
@@ -477,8 +477,11 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st
|| (bt_proto = ndpi_strnstr((const char *)packet->payload, "BitTorrent protocol", packet->payload_packet_len))
) {
bittorrent_found:
- if(bt_proto && (packet->payload_packet_len > 47))
- memcpy(flow->protos.bittorrent.hash, &bt_proto[27], 20);
+ if(bt_proto != NULL && ((u_int8_t *)&bt_proto[27] - packet->payload +
+ sizeof(flow->protos.bittorrent.hash)) < packet->payload_packet_len)
+ {
+ memcpy(flow->protos.bittorrent.hash, &bt_proto[27], sizeof(flow->protos.bittorrent.hash));
+ }
NDPI_LOG_INFO(ndpi_struct, "found BT: plain\n");
ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 0,
diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c
index e291bc908..bb5b38eed 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -466,9 +466,7 @@ int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
}
if(flow->http.user_agent == NULL) {
- int len = ua_ptr_len + 1;
-
- flow->http.user_agent = ndpi_malloc(len);
+ flow->http.user_agent = ndpi_malloc(ua_ptr_len + 1);
if(flow->http.user_agent) {
memcpy(flow->http.user_agent, (char*)ua_ptr, ua_ptr_len);
flow->http.user_agent[ua_ptr_len] = '\0';
diff --git a/src/lib/protocols/irc.c b/src/lib/protocols/irc.c
index bb1b65929..92a1f57da 100644
--- a/src/lib/protocols/irc.c
+++ b/src/lib/protocols/irc.c
@@ -635,14 +635,20 @@ void ndpi_search_irc_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc
NDPI_LOG_DBG2(ndpi_struct, "xdcc should match.");
}
j += 2;
- if (memcmp(&packet->line[i].ptr[j], "DCC ", 4) == 0) {
+ if (j + 4 < packet->line[i].len &&
+ memcmp(&packet->line[i].ptr[j], "DCC ", 4) == 0) {
j += 4;
NDPI_LOG_DBG2(ndpi_struct, "found DCC.");
- if (memcmp(&packet->line[i].ptr[j], "SEND ", 5) == 0
- || (memcmp(&packet->line[i].ptr[j], "CHAT", 4) == 0)
- || (memcmp(&packet->line[i].ptr[j], "chat", 4) == 0)
- || (j+7 < packet->line[i].len && memcmp(&packet->line[i].ptr[j], "sslchat", 7) == 0)
- || (memcmp(&packet->line[i].ptr[j], "TSEND", 5) == 0)) {
+ if ((j + 5 < packet->line[i].len &&
+ memcmp(&packet->line[i].ptr[j], "SEND ", 5) == 0) ||
+ (j + 4 < packet->line[i].len &&
+ memcmp(&packet->line[i].ptr[j], "CHAT", 4) == 0) ||
+ (j + 4 < packet->line[i].len &&
+ memcmp(&packet->line[i].ptr[j], "chat", 4) == 0) ||
+ (j + 7 < packet->line[i].len &&
+ memcmp(&packet->line[i].ptr[j], "sslchat", 7) == 0) ||
+ (j + 5 < packet->line[i].len &&
+ memcmp(&packet->line[i].ptr[j], "TSEND", 5) == 0)) {
NDPI_LOG_DBG2(ndpi_struct, "found CHAT,chat,sslchat,TSEND.");
j += 4;
diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c
index fe1aba684..1f242ac46 100644
--- a/src/lib/protocols/kerberos.c
+++ b/src/lib/protocols/kerberos.c
@@ -213,15 +213,21 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]);
#endif
- if(name_offset < packet->payload_packet_len) {
+ if(name_offset < packet->payload_packet_len - 1) {
u_int cname_len = 0;
name_offset += 1;
- if(packet->payload[name_offset+1] < ' ') /* Isn't printable ? */
+ if(name_offset < packet->payload_packet_len - 1 &&
+ isprint(packet->payload[name_offset+1]) == 0) /* Isn't printable ? */
+ {
name_offset++;
+ }
- if(packet->payload[name_offset+1] == 0x1b)
+ if(name_offset < packet->payload_packet_len - 1 &&
+ packet->payload[name_offset+1] == 0x1b)
+ {
name_offset += 2;
+ }
cname_len = packet->payload[name_offset];
@@ -230,11 +236,16 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
char cname_str[48];
u_int8_t num_cname = 0;
+ cname_str[0] = '\0'; // required, because cname_len
+
while(++num_cname <= 2) {
if(cname_len > sizeof(cname_str)-1)
- cname_len = sizeof(cname_str)-1;
+ cname_len = sizeof(cname_str)-1;
- strncpy(cname_str, (char*)&packet->payload[name_offset+1], cname_len);
+ if (name_offset + cname_len + 1 >= packet->payload_packet_len)
+ cname_len = 0;
+ else
+ strncpy(cname_str, (char*)&packet->payload[name_offset+1], cname_len);
cname_str[cname_len] = '\0';
for(i=0; i<cname_len; i++) cname_str[i] = tolower(cname_str[i]);
@@ -243,16 +254,18 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
#endif
if(((strcmp(cname_str, "host") == 0) || (strcmp(cname_str, "ldap") == 0)) && (packet->payload[name_offset+1+cname_len] == 0x1b)) {
- name_offset += cname_len + 2;
- cname_len = packet->payload[name_offset];
- } else
- break;
+ name_offset += cname_len + 2;
+ if (name_offset < packet->payload_packet_len)
+ cname_len = packet->payload[name_offset];
+ } else{
+ break;
+ }
}
realm_offset = cname_len + name_offset + 3;
/* if cname does not end with a $ then it's a username */
- if(cname_len
+ if(cname_len > 0 && name_offset + cname_len + 1 < packet->payload_packet_len
&& (cname_len < sizeof(cname_str))
&& (cname_str[cname_len-1] == '$')) {
cname_str[cname_len-1] = '\0';
@@ -305,7 +318,7 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t name_offset, padding_offset = body_offset + 4;
name_offset = padding_offset;
- for(i=0; i<14; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
+ for(i=0; i<14 && name_offset < packet->payload_packet_len; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */
#ifdef KERBEROS_DEBUG
printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]);
diff --git a/src/lib/protocols/ntp.c b/src/lib/protocols/ntp.c
index db9416121..1b56dc8a2 100644
--- a/src/lib/protocols/ntp.c
+++ b/src/lib/protocols/ntp.c
@@ -49,7 +49,7 @@ void ndpi_search_ntp_udp(struct ndpi_detection_module_struct *ndpi_struct, struc
// 38 in binary representation is 00111000
flow->protos.ntp.version = (packet->payload[0] & 0x38) >> 3;
- if (flow->protos.ntp.version == 2) {
+ if (packet->payload_packet_len > 3 && flow->protos.ntp.version == 2) {
flow->protos.ntp.request_code = packet->payload[3];
}
diff --git a/src/lib/protocols/ppstream.c b/src/lib/protocols/ppstream.c
index 44eb812dc..91f66bee4 100644
--- a/src/lib/protocols/ppstream.c
+++ b/src/lib/protocols/ppstream.c
@@ -51,7 +51,7 @@ void ndpi_search_ppstream(struct ndpi_detection_module_struct
/* check PPS over UDP */
if(packet->udp != NULL) {
/*** on port 17788 ***/
- if(packet->payload_packet_len > 12 && ((ntohs(packet->udp->source) == PPS_PORT) || (ntohs(packet->udp->dest) == PPS_PORT))) {
+ if(packet->payload_packet_len > 14 && ((ntohs(packet->udp->source) == PPS_PORT) || (ntohs(packet->udp->dest) == PPS_PORT))) {
if(((packet->payload_packet_len - 4 == get_l16(packet->payload, 0))
|| (packet->payload_packet_len == get_l16(packet->payload, 0))
|| (packet->payload_packet_len >= 6 && packet->payload_packet_len - 6 == get_l16(packet->payload, 0)))) {
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 799092af2..1a849b2cb 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -499,7 +499,7 @@ static void processCertificateElements(struct ndpi_detection_module_struct *ndpi
/* The check "len > sizeof(dNSName) - 1" will be always false. If we add it,
the compiler is smart enough to detect it and throws a warning */
if((len == 0 /* Looks something went wrong */)
- || ((i+len) > packet->payload_packet_len))
+ || ((i+len) > packet->payload_packet_len))
break;
strncpy(dNSName, (const char*)&packet->payload[i], len);
@@ -641,7 +641,8 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
packet->payload[3], packet->payload[4], packet->payload[5]);
#endif
- if((packet->payload_packet_len != (length + 4 + (is_dtls ? 8 : 0))) || (packet->payload[1] != 0x0)) {
+ if((packet->payload_packet_len != (length + 4 + (is_dtls ? 8 : 0))) || (packet->payload[1] != 0x0) ||
+ certificates_offset >= packet->payload_packet_len) {
ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET);
return(-1); /* Invalid length */
}
@@ -1024,18 +1025,20 @@ static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
break;
}
/* TODO: handle (certificate) fragments */
- handshake_len = (block[14] << 16) + (block[15] << 8) + block[16];
- if((handshake_len + 12) != block_len) {
-#ifdef DEBUG_TLS
- printf("[TLS] DTLS invalid handshake_len %d, %d)\n",
- handshake_len, block_len);
-#endif
- no_dtls = 1;
- break;
+ if (block_len > 16) {
+ handshake_len = (block[14] << 16) + (block[15] << 8) + block[16];
+ if((handshake_len + 12) != block_len) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid handshake_len %d, %d)\n",
+ handshake_len, block_len);
+#endif
+ no_dtls = 1;
+ break;
+ }
+ packet->payload = &block[13];
+ packet->payload_packet_len = block_len;
+ processTLSBlock(ndpi_struct, flow);
}
- packet->payload = &block[13];
- packet->payload_packet_len = block_len;
- processTLSBlock(ndpi_struct, flow);
} else {
/* Change-cipher-spec: any subsequent block might be encrypted */
#ifdef DEBUG_TLS
@@ -1219,7 +1222,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
char ja3_str[JA3_STR_LEN];
ndpi_MD5_CTX ctx;
u_char md5_hash[16];
- int i;
+ u_int32_t i;
u_int16_t total_len;
u_int8_t handshake_type;
char buffer[64] = { '\0' };
@@ -1243,7 +1246,9 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
if(total_len > 4) {
u_int16_t base_offset = (!is_dtls) ? 38 : 46;
u_int16_t version_offset = (!is_dtls) ? 4 : 12;
- u_int16_t offset = (!is_dtls) ? 38 : 46, extension_len, j;
+ u_int16_t offset = (!is_dtls) ? 38 : 46;
+ u_int16_t j;
+ u_int32_t tot_extension_len;
u_int8_t session_id_len = 0;
if((base_offset >= total_len) ||
@@ -1259,7 +1264,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
tls_version = ntohs(*((u_int16_t*)&packet->payload[version_offset]));
if(handshake_type == 0x02 /* Server Hello */) {
- int i, rc;
+ u_int32_t i;
+ int rc;
ja3.server.num_cipher = 0;
ja3.server.num_tls_extension = 0;
@@ -1299,22 +1305,26 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
offset += 2 + 1;
if((offset + 1) < packet->payload_packet_len) /* +1 because we are goint to read 2 bytes */
- extension_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
+ tot_extension_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
else
- extension_len = 0;
+ tot_extension_len = 0;
#ifdef DEBUG_TLS
printf("TLS [server][extension_len: %u]\n", extension_len);
#endif
offset += 2;
- for(i=0; i<extension_len; ) {
- u_int16_t extension_id, extension_len;
+ for(i=0; i<tot_extension_len; ) {
+ u_int16_t extension_id;
+ u_int32_t extension_len;
if((offset+4) > packet->payload_packet_len) break;
extension_id = ntohs(*((u_int16_t*)&packet->payload[offset]));
extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+2]));
+ if (offset+4+extension_len > packet->payload_packet_len) {
+ break;
+ }
if(ja3.server.num_tls_extension < MAX_NUM_JA3)
ja3.server.tls_extension[ja3.server.num_tls_extension++] = extension_id;
@@ -1335,7 +1345,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
flow->protos.tls_quic_stun.tls_quic.ssl_version = ja3.server.tls_supported_version = tls_version;
}
- } else if(extension_id == 16 /* application_layer_protocol_negotiation (ALPN) */) {
+ } else if(extension_id == 16 /* application_layer_protocol_negotiation (ALPN) */ &&
+ offset + 6 < packet->payload_packet_len) {
u_int16_t s_offset = offset+4;
u_int16_t tot_alpn_len = ntohs(*((u_int16_t*)&packet->payload[s_offset]));
char alpn_str[256];
@@ -1347,6 +1358,9 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
s_offset += 2;
tot_alpn_len += s_offset;
+ if (tot_alpn_len > packet->payload_packet_len)
+ return 0;
+
while(s_offset < tot_alpn_len && s_offset < total_len) {
u_int8_t alpn_i, alpn_len = packet->payload[s_offset++];
@@ -1400,7 +1414,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
printf("Server TLS [EllipticCurveFormat: len=%u]\n", extension_len);
#endif
if((s_offset+extension_len-1) <= total_len) {
- for(i=0; i<extension_len-1; i++) {
+ for(i=0; i<extension_len-1 && s_offset+i<packet->payload_packet_len; i++) {
u_int8_t s_group = packet->payload[s_offset+i];
#ifdef DEBUG_TLS
@@ -1526,7 +1540,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i];
u_int16_t cipher_id = ntohs(*id);
- if(packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1] /* Skip Grease */) {
+ if(cipher_offset+i+1 < packet->payload_packet_len &&
+ packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1] /* Skip Grease */) {
/*
Skip GREASE [https://tools.ietf.org/id/draft-ietf-tls-grease-01.html]
https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967
@@ -1749,7 +1764,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#endif
if((s_offset+extension_len-2) <= total_len) {
- for(i=0; i<extension_len-2;) {
+ for(int i=0; i<extension_len-2 && s_offset + i + 1 < total_len; i += 2) {
u_int16_t s_group = ntohs(*((u_int16_t*)&packet->payload[s_offset+i]));
#ifdef DEBUG_TLS
@@ -1766,8 +1781,6 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#endif
}
}
-
- i += 2;
}
} else {
invalid_ja3 = 1;
@@ -1782,7 +1795,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
printf("Client TLS [EllipticCurveFormat: len=%u]\n", extension_len);
#endif
if((s_offset+extension_len-1) <= total_len) {
- for(i=0; i<extension_len-1; i++) {
+ for(int i=0; i<extension_len-1 && s_offset+i < total_len; i++) {
u_int8_t s_group = packet->payload[s_offset+i];
#ifdef DEBUG_TLS
@@ -1805,7 +1818,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#endif
}
} else if(extension_id == 13 /* signature algorithms */) {
- u_int16_t s_offset = offset+extension_offset, safari_signature_algorithms = 0, chrome_signature_algorithms = 0,
+ int s_offset = offset+extension_offset, safari_signature_algorithms = 0, chrome_signature_algorithms = 0,
duplicate_found = 0, last_signature = 0;
u_int16_t tot_signature_algorithms_len = ntohs(*((u_int16_t*)&packet->payload[s_offset]));
@@ -1823,13 +1836,13 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
&packet->payload[s_offset], 2 /* 16 bit */*flow->protos.tls_quic_stun.tls_quic.num_tls_signature_algorithms);
#endif
- for(i=0; i<tot_signature_algorithms_len; i++) {
+ for(i=0; i<tot_signature_algorithms_len && s_offset+i<total_len; i++) {
int rc = snprintf(&ja3.client.signature_algorithms[i*2], sizeof(ja3.client.signature_algorithms)-i*2, "%02X", packet->payload[s_offset+i]);
if(rc < 0) break;
}
- for(i=0; i<tot_signature_algorithms_len; i+=2) {
+ for(i=0; i<tot_signature_algorithms_len && s_offset + (int)i + 2 < packet->payload_packet_len; i+=2) {
u_int16_t signature_algo = (u_int16_t)ntohs(*((u_int16_t*)&packet->payload[s_offset+i]));
if(last_signature == signature_algo) {
@@ -1839,10 +1852,10 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
} else {
/* Check for other duplications */
u_int all_ok = 1;
- int j;
+ u_int32_t j;
for(j=0; j<tot_signature_algorithms_len; j+=2) {
- if(j != i) {
+ if(j != i && s_offset + (int)j + 2 < packet->payload_packet_len) {
u_int16_t j_signature_algo = (u_int16_t)ntohs(*((u_int16_t*)&packet->payload[s_offset+j]));
if((signature_algo == j_signature_algo)
@@ -1920,7 +1933,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
duplicate_found);
#endif
- if (i >= tot_signature_algorithms_len) {
+ if (i > 0 && i >= tot_signature_algorithms_len) {
ja3.client.signature_algorithms[i*2 - 1] = '\0';
} else {
ja3.client.signature_algorithms[i*2] = '\0';
@@ -1929,7 +1942,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef DEBUG_TLS
printf("Client TLS [SIGNATURE_ALGORITHMS: %s]\n", ja3.client.signature_algorithms);
#endif
- } else if(extension_id == 16 /* application_layer_protocol_negotiation */) {
+ } else if(extension_id == 16 /* application_layer_protocol_negotiation */ &&
+ offset+extension_offset < total_len) {
u_int16_t s_offset = offset+extension_offset;
u_int16_t tot_alpn_len = ntohs(*((u_int16_t*)&packet->payload[s_offset]));
char alpn_str[256];
@@ -1997,7 +2011,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
s_offset++;
// careful not to overflow and loop forever with u_int8_t
- for(j=0; j+1<version_len; j += 2) {
+ for(j=0; j+1<version_len && s_offset + j + 1 < packet->payload_packet_len; j += 2) {
u_int16_t tls_version = ntohs(*((u_int16_t*)&packet->payload[s_offset+j]));
u_int8_t unknown_tls_version;
@@ -2037,9 +2051,10 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
- https://tools.ietf.org/html/draft-ietf-tls-esni-06
- https://blog.cloudflare.com/encrypted-sni/
*/
- u_int16_t e_offset = offset+extension_offset;
- u_int16_t initial_offset = e_offset;
- u_int16_t e_sni_len, cipher_suite = ntohs(*((u_int16_t*)&packet->payload[e_offset]));
+ int e_offset = offset+extension_offset;
+ int e_sni_len;
+ int initial_offset = e_offset;
+ u_int16_t cipher_suite = ntohs(*((u_int16_t*)&packet->payload[e_offset]));
flow->protos.tls_quic_stun.tls_quic.encrypted_sni.cipher_suite = cipher_suite;
@@ -2047,7 +2062,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
/* Key Share Entry */
e_offset += 2; /* Group */
- e_offset += ntohs(*((u_int16_t*)&packet->payload[e_offset])) + 2; /* Lenght */
+ if (e_offset + 2 < packet->payload_packet_len) {
+ e_offset += ntohs(*((u_int16_t*)&packet->payload[e_offset])) + 2; /* Lenght */
if((e_offset+4) < packet->payload_packet_len) {
/* Record Digest */
@@ -2057,7 +2073,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
e_sni_len = ntohs(*((u_int16_t*)&packet->payload[e_offset]));
e_offset += 2;
- if((e_offset+e_sni_len-extension_len-initial_offset) >= 0 &&
+ if((e_offset+e_sni_len-(int)extension_len-initial_offset) >= 0 &&
e_offset+e_sni_len < packet->payload_packet_len) {
#ifdef DEBUG_ENCRYPTED_SNI
printf("Client TLS [Encrypted Server Name len: %u]\n", e_sni_len);
@@ -2083,6 +2099,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
}
}
}
+ }
} else if(extension_id == 65445 || /* QUIC transport parameters (drafts version) */
extension_id == 57) { /* QUIC transport parameters (final version) */
u_int16_t s_offset = offset+extension_offset;
diff --git a/tests/do.sh.in b/tests/do.sh.in
index 36b83b128..d04b483b6 100755
--- a/tests/do.sh.in
+++ b/tests/do.sh.in
@@ -3,6 +3,9 @@
cd "$(dirname "${0}")"
FUZZY_TESTING_ENABLED=@BUILD_FUZZTARGETS@
+if [ "$NDPI_DISABLE_FUZZY" = "1" ]; then
+ FUZZY_TESTING_ENABLED=0
+fi
#Remember: valgrind and *SAN are incompatible!
VALGRIND=""
diff --git a/tests/pcap/fuzz-2021-10-13.pcap b/tests/pcap/fuzz-2021-10-13.pcap
new file mode 100644
index 000000000..751775397
--- /dev/null
+++ b/tests/pcap/fuzz-2021-10-13.pcap
Binary files differ
diff --git a/tests/result/fuzz-2021-10-13.pcap.out b/tests/result/fuzz-2021-10-13.pcap.out
new file mode 100644
index 000000000..e0d6e4c90
--- /dev/null
+++ b/tests/result/fuzz-2021-10-13.pcap.out
@@ -0,0 +1,12 @@
+Guessed flow protos: 1
+
+DPI Packets (TCP): 1 (1.00 pkts/flow)
+
+TLS 1 197 1
+
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 3400:3a30:3035:2f75:706c:6f32:643f:6c3d 1
+
+
+ 1 TCP [3400:3a30:3035:2f75:706c:6f32:643f:6c3d]:44288 -> [302e::3d00::8001]:0 [proto: 91/TLS][Encrypted][cat: Web/5][1 pkts/197 bytes -> 0 pkts/0 bytes][Goodput ratio: 75/0][< 1 sec][Risk: ** Known protocol on non standard port **** Obsolete TLS version (older than 1.2) **** TLS suspicious extension **][Risk Score: 160][TLS (0030)][JA3C: 7fd749763364ca3fe45ec98917f981f6][PLAIN TEXT (005/uplo2)][Plen Bins: 0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]