From 6f046df0dcb07dae74be127af555ad96e8576acf Mon Sep 17 00:00:00 2001 From: Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> Date: Thu, 30 Nov 2023 09:09:40 +0100 Subject: [PATCH] STUN: fix detection of DTLS (#2187) Fix a memory leak ``` ==97697==ERROR: LeakSanitizer: detected memory leaks Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x55a6967cfa7e in malloc (/home/ivan/svnrepos/nDPI/fuzz/fuzz_ndpi_reader+0x701a7e) (BuildId: c7124999fa1ccc54346fa7bd536d8eab88c3ea01) #1 0x55a696972ab5 in ndpi_malloc /home/ivan/svnrepos/nDPI/src/lib/ndpi_memory.c:60:25 #2 0x55a696972da0 in ndpi_strdup /home/ivan/svnrepos/nDPI/src/lib/ndpi_memory.c:113:13 #3 0x55a696b7658d in processClientServerHello /home/ivan/svnrepos/nDPI/src/lib/protocols/tls.c:2394:46 #4 0x55a696b86e81 in processTLSBlock /home/ivan/svnrepos/nDPI/src/lib/protocols/tls.c:897:5 #5 0x55a696b80649 in ndpi_search_tls_udp /home/ivan/svnrepos/nDPI/src/lib/protocols/tls.c:1262:11 #6 0x55a696b67a57 in ndpi_search_tls_wrapper /home/ivan/svnrepos/nDPI/src/lib/protocols/tls.c:2751:5 #7 0x55a696b67758 in switch_to_tls /home/ivan/svnrepos/nDPI/src/lib/protocols/tls.c:1408:3 #8 0x55a696c47810 in stun_search_again /home/ivan/svnrepos/nDPI/src/lib/protocols/stun.c:422:4 #9 0x55a6968a22af in ndpi_process_extra_packet /home/ivan/svnrepos/nDPI/src/lib/ndpi_main.c:7247:9 #10 0x55a6968acd6f in ndpi_internal_detection_process_packet /home/ivan/svnrepos/nDPI/src/lib/ndpi_main.c:7746:5 #11 0x55a6968aba3f in ndpi_detection_process_packet /home/ivan/svnrepos/nDPI/src/lib/ndpi_main.c:8013:22 #12 0x55a69683d30e in packet_processing /home/ivan/svnrepos/nDPI/fuzz/../example/reader_util.c:1723:31 #13 0x55a69683d30e in ndpi_workflow_process_packet /home/ivan/svnrepos/nDPI/fuzz/../example/reader_util.c:2440:10 #14 0x55a69680f08f in LLVMFuzzerTestOneInput /home/ivan/svnrepos/nDPI/fuzz/fuzz_ndpi_reader.c:135:7 [...] SUMMARY: AddressSanitizer: 16 byte(s) leaked in 1 allocation(s). ``` Found by oss-fuzzer See: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=64564 --- fuzz/fuzz_ndpi_reader.c | 5 +++++ src/lib/protocols/stun.c | 28 ++++++++++++++++++++++++ tests/cfgs/default/pcap/stun.pcap | Bin 34424 -> 35344 bytes tests/cfgs/default/result/stun.pcap.out | 27 ++++++++++++++--------- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/fuzz/fuzz_ndpi_reader.c b/fuzz/fuzz_ndpi_reader.c index fd7d185e15b..1a6cd7569e7 100644 --- a/fuzz/fuzz_ndpi_reader.c +++ b/fuzz/fuzz_ndpi_reader.c @@ -37,6 +37,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { int r; char errbuf[PCAP_ERRBUF_SIZE]; NDPI_PROTOCOL_BITMASK all; + NDPI_PROTOCOL_BITMASK debug_bitmask; u_int i; FILE *fd; @@ -60,6 +61,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { NDPI_BITMASK_SET_ALL(all); ndpi_set_protocol_detection_bitmask2(workflow->ndpi_struct, &all); + NDPI_BITMASK_SET_ALL(debug_bitmask); + ndpi_set_log_level(workflow->ndpi_struct, 4); + ndpi_set_debug_bitmask(workflow->ndpi_struct, debug_bitmask); + ndpi_load_protocols_file(workflow->ndpi_struct, "protos.txt"); ndpi_load_categories_file(workflow->ndpi_struct, "categories.txt", NULL); ndpi_load_risk_domain_file(workflow->ndpi_struct, "risky_domains.txt"); diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index 76a75b45957..62e904b6960 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -353,6 +353,8 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t app_proto = NDPI_PROTOCOL_UNKNOWN; u_int32_t unused; int first_dtls_pkt = 0; + u_int16_t old_proto_stack[2] = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN}; + ndpi_protocol_category_t old_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED; NDPI_LOG_DBG2(ndpi_struct, "Packet counter %d protos %d/%d\n", flow->packet_counter, flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]); @@ -396,6 +398,10 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, * the easiest (!?) solution is to remove everything, and let the TLS dissector to set both master (i.e. DTLS) and subprotocol (if any) */ + /* In same rare cases, with malformed/fuzzed traffic, `is_dtls()` might return false + positives. In that case, the TLS dissector doesn't set the master protocol, so we + need to rollback to the current state */ + if(packet->tcp) { /* TODO: TLS code assumes that DTLS is only over UDP */ NDPI_LOG_DBG(ndpi_struct, "Ignoring DTLS over TCP\n"); @@ -407,6 +413,11 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, /* First DTLS packet of the flow */ first_dtls_pkt = 1; + /* We might need to rollback this change... */ + old_proto_stack[0] = flow->detected_protocol_stack[0]; + old_proto_stack[1] = flow->detected_protocol_stack[1]; + old_category = flow->category; + /* TODO: right way? It is a bit scary... do we need to reset something else too? */ reset_detected_protocol(ndpi_struct, flow); change_category(ndpi_struct, flow, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED); @@ -423,6 +434,23 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, NDPI_LOG_DBG(ndpi_struct, "(%d/%d)\n", flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]); + + /* If this is not a real DTLS packet, we need to restore the old state */ + if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN && + first_dtls_pkt) { + NDPI_LOG_DBG(ndpi_struct, "Switch to TLS failed. Rollback to old classification\n"); + + ndpi_set_detected_protocol(ndpi_struct, flow, + old_proto_stack[1], old_proto_stack[0], + NDPI_CONFIDENCE_DPI); + change_category(ndpi_struct, flow, old_category); + + flow->stun.maybe_dtls = 0; + flow->max_extra_packets_to_check -= 10; + + NDPI_LOG_DBG(ndpi_struct, "(%d/%d)\n", + flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]); + } } } } diff --git a/tests/cfgs/default/pcap/stun.pcap b/tests/cfgs/default/pcap/stun.pcap index c7e645eea168eb9afd1df6e54f90eb61bbf5dc68..7d7c3044e35f4b52798dbf6eeeb1e1d510b44e0f 100644 GIT binary patch delta 885 zcmey-!!%(E(*!L>%Zb`&Cr%OB_@kk;5MU~pw%*fH72fx$uWX5xVr+AG^0MCI?hrj*FAW)(k+fsMh_)xgBX(!|(J*V)M2P}kYg%n`(L(RFclaxt(pH@B!avoNqSGB7c4 zGk0~?HFk4y(={`6GuJhAbT-m;baXLwF)=eVaI^qg&cL7w#3~FddG!qc8?+cWrX_!^ zs1E;hg@J=XWSzdTrYBSBCMTOV4qr|`1I)XO=AE41Jy%--@pI=mq6J|{{8)9+<$YvjR zAqD}q^3K8yFDmK+Fh=OpsSWUhV;6Slo7Tit1zm`5+95RfxYqaa+$2!(Z>fU?`YV z2#Q#cx0Mq2U1RWAna0S-po0;)3Sf&EYK+h7g2I13!{7UR87EG;a<2NwlZP#*E{YWN zg2KNh{?#IgBhbU&XqhN5{Ncf0kDAhMPIdu@zaDD%PeTfSMurVQKT;U}px|c^XJGh0 Mc|o>#Fb(1W02_q;*Z=?k delta 22 ecmbO*h3Q8R(*!L>i;3E2Czmh^Y?fgxXaxXbum}bK diff --git a/tests/cfgs/default/result/stun.pcap.out b/tests/cfgs/default/result/stun.pcap.out index 4c421c21e6d..f4078a04e0a 100644 --- a/tests/cfgs/default/result/stun.pcap.out +++ b/tests/cfgs/default/result/stun.pcap.out @@ -1,15 +1,15 @@ -Guessed flow protos: 0 +Guessed flow protos: 1 DPI Packets (TCP): 9 (4.50 pkts/flow) -DPI Packets (UDP): 12 (3.00 pkts/flow) +DPI Packets (UDP): 16 (3.20 pkts/flow) DPI Packets (other): 1 (1.00 pkts/flow) -Confidence DPI : 7 (flows) -Num dissector calls: 22 (3.14 diss/flow) +Confidence DPI : 8 (flows) +Num dissector calls: 28 (3.50 diss/flow) LRU cache ookla: 0/0/0 (insert/search/found) LRU cache bittorrent: 0/0/0 (insert/search/found) LRU cache zoom: 0/0/0 (insert/search/found) -LRU cache stun: 8/28/0 (insert/search/found) -LRU cache tls_cert: 0/0/0 (insert/search/found) +LRU cache stun: 8/32/0 (insert/search/found) +LRU cache tls_cert: 0/1/0 (insert/search/found) LRU cache mining: 0/0/0 (insert/search/found) LRU cache msteams: 0/0/0 (insert/search/found) LRU cache stun_zoom: 0/0/0 (insert/search/found) @@ -17,24 +17,31 @@ Automa host: 0/0 (search/found) Automa domain: 0/0 (search/found) Automa tls cert: 0/0 (search/found) Automa risk mask: 1/0 (search/found) -Automa common alpns: 0/0 (search/found) -Patricia risk mask: 8/0 (search/found) +Automa common alpns: 2/2 (search/found) +Patricia risk mask: 10/0 (search/found) Patricia risk mask IPv6: 2/0 (search/found) Patricia risk: 1/0 (search/found) Patricia risk IPv6: 1/0 (search/found) -Patricia protocols: 8/4 (search/found) +Patricia protocols: 9/5 (search/found) Patricia protocols IPv6: 2/0 (search/found) +DTLS 4 766 1 Skype_TeamsCall 15 2124 1 STUN 62 7620 2 ICMP 1 122 1 GoogleHangoutDuo 41 7228 2 FacebookVoip 75 10554 1 +JA3 Host Stats: + IP Address # JA3C + 1 192.168.43.169 1 + + 1 UDP 192.168.12.169:38123 <-> 31.13.86.54:40003 [proto: 78.268/STUN.FacebookVoip][IP: 119/Facebook][ClearText][Confidence: DPI][DPI packets: 2][cat: VoIP/10][40 pkts/6134 bytes <-> 35 pkts/4420 bytes][Goodput ratio: 73/67][10.09 sec][Hostname/SNI: turner.facebook][bytes ratio: 0.162 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 260/331 6004/5997 1040/1126][Pkt Len c2s/s2c min/avg/max/stddev: 70/68 153/126 190/174 31/39][Risk: ** Known Proto on Non Std Port **][Risk Score: 50][PLAIN TEXT (unauthorized)][Plen Bins: 8,14,9,28,40,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] 2 UDP 192.168.12.169:49153 <-> 142.250.82.99:3478 [proto: 78.201/STUN.GoogleHangoutDuo][IP: 126/Google][ClearText][Confidence: DPI][DPI packets: 1][cat: VoIP/10][18 pkts/2856 bytes <-> 15 pkts/3436 bytes][Goodput ratio: 74/82][2.12 sec][bytes ratio: -0.092 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 8/0 88/153 699/625 177/222][Pkt Len c2s/s2c min/avg/max/stddev: 107/76 159/229 588/1240 107/297][PLAIN TEXT (BwlkYDtFJ)][Plen Bins: 0,6,57,21,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0] 3 UDP [3516:bf0b:fc53:75e7:70af:f67f:8e49:f603]:56880 <-> [2a38:e156:8167:a333:face:b00c::24d9]:3478 [proto: 78/STUN][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 5][cat: Network/14][21 pkts/1722 bytes <-> 21 pkts/2226 bytes][Goodput ratio: 24/41][191.49 sec][bytes ratio: -0.128 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 2/2 9451/9451 10358/10358 2441/2441][Pkt Len c2s/s2c min/avg/max/stddev: 82/106 82/106 82/106 0/0][PLAIN TEXT (WOBTrOXR)][Plen Bins: 50,50,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,0,0,0] 4 TCP 87.47.100.17:3478 <-> 54.1.57.155:37257 [proto: 78/STUN][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 6][cat: Network/14][9 pkts/1494 bytes <-> 11 pkts/2178 bytes][Goodput ratio: 60/67][0.95 sec][Hostname/SNI: apps-host.com][bytes ratio: -0.186 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 104/96 267/252 102/93][Pkt Len c2s/s2c min/avg/max/stddev: 74/94 166/198 234/354 41/65][PLAIN TEXT (Unauthorized)][Plen Bins: 10,0,15,21,42,5,0,0,0,5,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] 5 TCP 10.77.110.51:41588 <-> 10.206.50.239:42000 [VLAN: 1611][proto: 78.38/STUN.Skype_TeamsCall][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 3][cat: VoIP/10][7 pkts/1006 bytes <-> 8 pkts/1118 bytes][Goodput ratio: 58/57][1.05 sec][bytes ratio: -0.053 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 189/134 369/399 144/153][Pkt Len c2s/s2c min/avg/max/stddev: 70/64 144/140 164/172 31/43][Plen Bins: 0,0,25,75,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,0] 6 UDP 192.168.12.169:43016 <-> 74.125.247.128:3478 [proto: 78.201/STUN.GoogleHangoutDuo][IP: 126/Google][ClearText][Confidence: DPI][DPI packets: 4][cat: VoIP/10][4 pkts/528 bytes <-> 4 pkts/408 bytes][Goodput ratio: 68/59][1.25 sec][Hostname/SNI: turn.l.google.com][bytes ratio: 0.128 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 9/23 342/409 974/1177 447/543][Pkt Len c2s/s2c min/avg/max/stddev: 62/74 132/102 198/122 61/19][PLAIN TEXT (BSnLfRxS6)][Plen Bins: 12,37,25,0,25,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] - 7 ICMP 192.168.12.169:0 -> 74.125.247.128:0 [proto: 81/ICMP][IP: 126/Google][ClearText][Confidence: DPI][DPI packets: 1][cat: Network/14][1 pkts/122 bytes -> 0 pkts/0 bytes][Goodput ratio: 65/0][< 1 sec][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No server to client traffic][PLAIN TEXT (62NfUD5)][Plen Bins: 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,0,0] + 7 UDP 192.168.43.169:48854 <-> 134.224.90.111:8801 [proto: 30/DTLS][IP: 189/Zoom][Encrypted][Confidence: DPI][DPI packets: 4][3 pkts/660 bytes <-> 1 pkts/106 bytes][Goodput ratio: 81/60][0.12 sec][(Advertised) ALPNs: webrtc;c-webrtc][Risk: ** Known Proto on Non Std Port **** Missing SNI TLS Extn **][Risk Score: 100][DTLSv1.2][JA3C: 3e12a43c7535bb32beac3928f8fe905d][Firefox][PLAIN TEXT (DCBD09778680)][Plen Bins: 0,0,25,0,25,50,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] + 8 ICMP 192.168.12.169:0 -> 74.125.247.128:0 [proto: 81/ICMP][IP: 126/Google][ClearText][Confidence: DPI][DPI packets: 1][cat: Network/14][1 pkts/122 bytes -> 0 pkts/0 bytes][Goodput ratio: 65/0][< 1 sec][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No server to client traffic][PLAIN TEXT (62NfUD5)][Plen Bins: 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,0,0]