aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/protocols/rtp.c96
-rw-r--r--tests/result/zoom2.pcap.out16
2 files changed, 92 insertions, 20 deletions
diff --git a/src/lib/protocols/rtp.c b/src/lib/protocols/rtp.c
index d0ca60a98..db7a90936 100644
--- a/src/lib/protocols/rtp.c
+++ b/src/lib/protocols/rtp.c
@@ -41,6 +41,7 @@ static u_int8_t isValidMSRTPType(u_int8_t payloadType) {
case 13: /* Comfort Noise */
case 96: /* Dynamic RTP */
case 97: /* Redundant Audio Data Payload */
+ case 98: /* DynamicRTP-Type-98 (Zoom) */
case 101: /* DTMF */
case 103: /* SILK Narrowband */
case 104: /* SILK Wideband */
@@ -79,41 +80,112 @@ int is_valid_rtp_payload_type(uint8_t type)
/* *************************************************************** */
+/*
+ https://github.com/Princeton-Cabernet/zoom-analysis
+ https://citizenlab.ca/2020/04/move-fast-roll-your-own-crypto-a-quick-look-at-the-confidentiality-of-zoom-meetings/
+ https://github.com/marty90/rtc_pcap_cleaners
+ */
+
+PACK_ON struct zoom_sfu_encapsulation {
+ u_int8_t sfu_type; /* 3/4 = Zoom_0, 5 = RTCP/RTP */
+ u_int16_t sequence_num;
+ u_int32_t unknown;
+ u_int8_t direction; /* 0 = -> Zoom, 4 = <- Zoom */
+} PACK_OFF;
+
+PACK_ON struct zoom_media_encapsulation {
+ u_int8_t enc_type; /* 15 = Audio, 16 = Video, 34 = RTCP */
+ u_int32_t unknown_1, unknown_2;
+ u_int16_t sequence_num;
+ u_int32_t timestamp;
+} PACK_OFF;
+
+#define ZOOM_PORT 8801
+
+static u_int8_t isZoom(u_int16_t sport, u_int16_t dport,
+ const u_int8_t *payload, const u_int16_t payloadLen,
+ u_int8_t *is_rtp, u_int8_t *zoom_stream_type,
+ u_int16_t *payload_offset) {
+ u_int16_t header_offset = sizeof(struct zoom_sfu_encapsulation) + sizeof(struct zoom_media_encapsulation);
+
+ if(payloadLen < header_offset)
+ return(0);
+
+ if((sport == ZOOM_PORT) || (dport == ZOOM_PORT)) {
+ struct zoom_sfu_encapsulation *enc = (struct zoom_sfu_encapsulation*)payload;
+
+ /* traceEvent(TRACE_NORMAL, "==> %u <-> %u [type: %u]", sport, dport, enc->sfu_type); */
+
+ if((enc->sfu_type >= 3) && (enc->sfu_type <= 5)) {
+ struct zoom_media_encapsulation *enc = (struct zoom_media_encapsulation*)(&payload[sizeof(struct zoom_sfu_encapsulation)]);
+
+ *is_rtp = ((enc->enc_type == 15) || (enc->enc_type == 16)) ? 1 : 0, *zoom_stream_type = enc->enc_type;
+
+ *payload_offset = (enc->enc_type == 16) ? 32 /* video streams have a long zoom_media_encapsulation header */
+ : ((enc->enc_type == 15) ? 27 : header_offset);
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+/* *************************************************************** */
+
static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
- const u_int8_t * payload, const u_int16_t payload_len) {
+ u_int8_t * payload, u_int16_t payload_len) {
u_int8_t payloadType, payload_type;
- u_int16_t d_port = ntohs(ndpi_struct->packet.udp->dest);
-
+ u_int16_t s_port = ntohs(ndpi_struct->packet.udp->source), d_port = ntohs(ndpi_struct->packet.udp->dest), payload_offset;
+ u_int8_t is_rtp, zoom_stream_type, is_zoom = 0;
+
NDPI_LOG_DBG(ndpi_struct, "search RTP\n");
if((payload_len < 2)
|| (d_port == 5355 /* LLMNR_PORT */)
- || (d_port == 5353 /* MDNS_PORT */)
+ || (d_port == 5353 /* MDNS_PORT */)
|| flow->stun.num_binding_requests
) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}
+ if(isZoom(s_port, d_port, payload, payload_len,
+ &is_rtp, &zoom_stream_type, &payload_offset)) {
+ if(payload_offset < payload_len) {
+ payload_len -= payload_offset;
+ payload = &payload[payload_offset];
+ is_zoom = 1;
+ }
+ }
+
payload_type = payload[1] & 0x7F;
-
+
/* Check whether this is an RTP flow */
if((payload_len >= 12)
- && (((payload[0] & 0xFF) == 0x80) || ((payload[0] & 0xFF) == 0xA0)) /* RTP magic byte[1] */
+ && (((payload[0] & 0xFF) == 0x80)
+ || ((payload[0] & 0xFF) == 0xA0)
+ || ((payload[0] & 0xFF) == 0x90)
+ ) /* RTP magic byte [1] */
&& ((payload_type < 72) || (payload_type > 76))
&& (is_valid_rtp_payload_type(payload_type))
- ) {
+ ) {
if(flow->l4.udp.line_pkts[0] >= 2 && flow->l4.udp.line_pkts[1] >= 2) {
/* It seems that it is a LINE stuff; let its dissector to evaluate */
return;
} else {
NDPI_LOG_INFO(ndpi_struct, "Found RTP\n");
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_RTP, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
+ ndpi_set_detected_protocol(ndpi_struct, flow,
+ is_zoom ? NDPI_PROTOCOL_ZOOM : NDPI_PROTOCOL_UNKNOWN,
+ NDPI_PROTOCOL_RTP,
+ NDPI_CONFIDENCE_DPI);
return;
}
} else if((payload_len >= 12)
- && (((payload[0] & 0xFF) == 0x80) || ((payload[0] & 0xFF) == 0xA0)) /* RTP magic byte[1] */
+ && (((payload[0] & 0xFF) == 0x80)
+ || ((payload[0] & 0xFF) == 0xA0)
+ || ((payload[0] & 0xFF) == 0x90)
+ ) /* RTP magic byte[1] */
&& (payloadType = isValidMSRTPType(payload[1] & 0xFF))) {
if(payloadType == 1 /* RTP */) {
NDPI_LOG_INFO(ndpi_struct, "Found Skype for Business (former MS Lync)\n");
@@ -133,15 +205,15 @@ static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, st
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
u_int16_t source = ntohs(packet->udp->source);
u_int16_t dest = ntohs(packet->udp->dest);
-
+
// printf("==> %s()\n", __FUNCTION__);
-
+
/* printf("*** %s(pkt=%d)\n", __FUNCTION__, flow->packet_counter); */
if((source != 30303) && (dest != 30303 /* Avoid to mix it with Ethereum that looks alike */)
&& (dest > 1023)
)
- ndpi_rtp_search(ndpi_struct, flow, packet->payload, packet->payload_packet_len);
+ ndpi_rtp_search(ndpi_struct, flow, (u_int8_t*)packet->payload, packet->payload_packet_len);
else
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
}
diff --git a/tests/result/zoom2.pcap.out b/tests/result/zoom2.pcap.out
index 51e541e85..2bbc3522b 100644
--- a/tests/result/zoom2.pcap.out
+++ b/tests/result/zoom2.pcap.out
@@ -1,17 +1,17 @@
-Guessed flow protos: 3
+Guessed flow protos: 2
DPI Packets (TCP): 8 (8.00 pkts/flow)
-DPI Packets (UDP): 75 (25.00 pkts/flow)
+DPI Packets (UDP): 62 (20.67 pkts/flow)
DPI Packets (other): 1 (1.00 pkts/flow)
-Confidence DPI (partial cache): 3 (flows)
-Confidence DPI : 2 (flows)
-Num dissector calls: 884 (176.80 diss/flow)
+Confidence DPI (partial cache): 2 (flows)
+Confidence DPI : 3 (flows)
+Num dissector calls: 806 (161.20 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/9/0 (insert/search/found)
-LRU cache zoom: 1/3/3 (insert/search/found)
+LRU cache zoom: 1/2/2 (insert/search/found)
LRU cache stun: 0/0/0 (insert/search/found)
LRU cache tls_cert: 0/0/0 (insert/search/found)
-LRU cache mining: 0/3/0 (insert/search/found)
+LRU cache mining: 0/2/0 (insert/search/found)
LRU cache msteams: 0/0/0 (insert/search/found)
Automa host: 1/1 (search/found)
Automa domain: 1/0 (search/found)
@@ -31,7 +31,7 @@ JA3 Host Stats:
1 UDP 192.168.1.178:60653 <-> 144.195.73.154:8801 [proto: 189/Zoom][IP: 189/Zoom][Encrypted][Confidence: DPI (partial cache)][cat: Video/26][3824 pkts/4162390 bytes <-> 4907 pkts/4203451 bytes][Goodput ratio: 96/95][40.59 sec][bytes ratio: -0.005 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 6/6 101/100 10/10][Pkt Len c2s/s2c min/avg/max/stddev: 94/60 1088/857 1339/1339 242/271][PLAIN TEXT (replace)][Plen Bins: 0,2,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,74,3,1,0,1,9,1,0,0,0,0,0,0,0,0,0]
- 2 UDP 192.168.1.178:58117 <-> 144.195.73.154:8801 [proto: 189/Zoom][IP: 189/Zoom][Encrypted][Confidence: DPI (partial cache)][cat: Video/26][1283 pkts/302584 bytes <-> 947 pkts/159626 bytes][Goodput ratio: 82/75][39.98 sec][bytes ratio: 0.309 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 28/36 141/131 26/34][Pkt Len c2s/s2c min/avg/max/stddev: 106/60 236/169 376/369 87/64][PLAIN TEXT (replace)][Plen Bins: 0,1,64,18,7,0,0,4,3,1,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.1.178:58117 <-> 144.195.73.154:8801 [proto: 87.189/RTP.Zoom][IP: 189/Zoom][ClearText][Confidence: DPI][cat: Video/26][1283 pkts/302584 bytes <-> 947 pkts/159626 bytes][Goodput ratio: 82/75][39.98 sec][bytes ratio: 0.309 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 28/36 141/131 26/34][Pkt Len c2s/s2c min/avg/max/stddev: 106/60 236/169 376/369 87/64][PLAIN TEXT (replace)][Plen Bins: 0,1,64,18,7,0,0,4,3,1,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]
3 TCP 192.168.1.178:50076 <-> 144.195.73.154:443 [proto: 91.189/TLS.Zoom][IP: 189/Zoom][Encrypted][Confidence: DPI][cat: Video/26][491 pkts/108525 bytes <-> 411 pkts/58625 bytes][Goodput ratio: 70/54][44.41 sec][Hostname/SNI: zoomsjccv154mmr.sjc.zoom.us][TLS Supported Versions: TLSv1.3;TLSv1.2;TLSv1.1;TLSv1][bytes ratio: 0.299 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 75/109 1466/1467 185/193][Pkt Len c2s/s2c min/avg/max/stddev: 54/60 221/143 1506/1506 285/210][Risk: ** TLS (probably) Not Carrying HTTPS **][Risk Score: 10][Risk Info: No ALPN][TLSv1.2][JA3C: 832952db10f1453442636675bed2702b][ServerNames: *.sjc.zoom.us][JA3S: 8aca82d60194883e764ab2743e60c380][Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1][Subject: C=US, ST=California, L=San Jose, O=Zoom Video Communications, Inc., CN=*.sjc.zoom.us][Certificate SHA-1: 43:42:0A:34:FD:F6:7A:FC:E9:C1:95:D8:E0:79:7E:17:B9:65:B0:A7][Firefox][Validity: 2021-04-13 00:00:00 - 2022-04-20 23:59:59][Cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384][Plen Bins: 0,15,17,13,5,3,8,2,1,0,1,0,1,1,3,1,2,4,2,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,10,0,0]
4 UDP 192.168.1.178:57953 <-> 144.195.73.154:8801 [proto: 189/Zoom][IP: 189/Zoom][Encrypted][Confidence: DPI (partial cache)][cat: Video/26][43 pkts/5229 bytes <-> 44 pkts/4520 bytes][Goodput ratio: 65/59][39.68 sec][bytes ratio: 0.073 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 941/849 3580/3749 1440/1522][Pkt Len c2s/s2c min/avg/max/stddev: 69/60 122/103 185/133 41/28][PLAIN TEXT (replace)][Plen Bins: 35,2,43,13,6,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]
5 ICMP 192.168.1.178:0 -> 144.195.73.154:0 [proto: 81/ICMP][IP: 189/Zoom][ClearText][Confidence: DPI][cat: Network/14][27 pkts/1890 bytes -> 0 pkts/0 bytes][Goodput ratio: 40/0][0.15 sec][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 6/0 20/0 6/0][Pkt Len c2s/s2c min/avg/max/stddev: 70/0 70/0 70/0 0/0][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No server to client traffic][Plen Bins: 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,0,0]