aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/reader_util.c39
-rw-r--r--src/include/ndpi_typedefs.h5
-rw-r--r--src/lib/ndpi_main.c3
-rw-r--r--src/lib/protocols/kerberos.c278
4 files changed, 252 insertions, 73 deletions
diff --git a/example/reader_util.c b/example/reader_util.c
index 2352369ee..cf3c82475 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -981,11 +981,14 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
else if(is_ndpi_proto(flow, NDPI_PROTOCOL_KERBEROS)) {
if((flow->ndpi_flow->protos.kerberos.hostname[0] != '\0')
|| (flow->ndpi_flow->protos.kerberos.username[0] != '\0')) {
- snprintf(flow->info, sizeof(flow->info), "%s%s (%s)",
+ snprintf(flow->info, sizeof(flow->info), "%s%s%s%s",
+ flow->ndpi_flow->protos.kerberos.domain /* = realm */,
+ flow->ndpi_flow->protos.kerberos.domain[0] != '\0' ? "\\" : "",
flow->ndpi_flow->protos.kerberos.hostname,
- flow->ndpi_flow->protos.kerberos.username,
+ flow->ndpi_flow->protos.kerberos.username);
+ } else if(flow->ndpi_flow->protos.kerberos.domain[0] != '\0')
+ snprintf(flow->info, sizeof(flow->info), "%s",
flow->ndpi_flow->protos.kerberos.domain);
- }
}
/* HTTP */
else if((flow->detected_protocol.master_protocol == NDPI_PROTOCOL_HTTP)
@@ -1171,21 +1174,21 @@ static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow,
if((flow->entropy.src2dst_pkt_count+flow->entropy.dst2src_pkt_count) <= max_num_packets_per_flow) {
if(flow->bidirectional)
flow->entropy.score = ndpi_classify(flow->entropy.src2dst_pkt_len, flow->entropy.src2dst_pkt_time,
- flow->entropy.dst2src_pkt_len, flow->entropy.dst2src_pkt_time,
- flow->entropy.src2dst_start, flow->entropy.dst2src_start,
- max_num_packets_per_flow, flow->src_port, flow->dst_port,
- flow->src2dst_packets, flow->dst2src_packets,
- flow->entropy.src2dst_opackets, flow->entropy.dst2src_opackets,
- flow->entropy.src2dst_l4_bytes, flow->entropy.dst2src_l4_bytes, 1,
- flow->entropy.src2dst_byte_count, flow->entropy.dst2src_byte_count);
- else
- flow->entropy.score = ndpi_classify(flow->entropy.src2dst_pkt_len, flow->entropy.src2dst_pkt_time,
- NULL, NULL, flow->entropy.src2dst_start, flow->entropy.src2dst_start,
- max_num_packets_per_flow, flow->src_port, flow->dst_port,
- flow->src2dst_packets, 0,
- flow->entropy.src2dst_opackets, 0,
- flow->entropy.src2dst_l4_bytes, 0, 1,
- flow->entropy.src2dst_byte_count, NULL);
+ flow->entropy.dst2src_pkt_len, flow->entropy.dst2src_pkt_time,
+ flow->entropy.src2dst_start, flow->entropy.dst2src_start,
+ max_num_packets_per_flow, flow->src_port, flow->dst_port,
+ flow->src2dst_packets, flow->dst2src_packets,
+ flow->entropy.src2dst_opackets, flow->entropy.dst2src_opackets,
+ flow->entropy.src2dst_l4_bytes, flow->entropy.dst2src_l4_bytes, 1,
+ flow->entropy.src2dst_byte_count, flow->entropy.dst2src_byte_count);
+ else
+ flow->entropy.score = ndpi_classify(flow->entropy.src2dst_pkt_len, flow->entropy.src2dst_pkt_time,
+ NULL, NULL, flow->entropy.src2dst_start, flow->entropy.src2dst_start,
+ max_num_packets_per_flow, flow->src_port, flow->dst_port,
+ flow->src2dst_packets, 0,
+ flow->entropy.src2dst_opackets, 0,
+ flow->entropy.src2dst_l4_bytes, 0, 1,
+ flow->entropy.src2dst_byte_count, NULL);
}
}
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 82a450462..b8c3b40bb 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1203,8 +1203,9 @@ struct ndpi_flow_struct {
} ntp;
struct {
-
- char hostname[24], domain[24], username[24];
+ char *pktbuf;
+ u_int16_t pktbuf_maxlen, pktbuf_currlen;
+ char hostname[48], domain[48], username[48];
} kerberos;
struct {
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 40bf9ae20..a2a7e593d 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -6374,7 +6374,8 @@ void ndpi_free_flow(struct ndpi_flow_struct *flow) {
if(flow->http.url) ndpi_free(flow->http.url);
if(flow->http.content_type) ndpi_free(flow->http.content_type);
if(flow->http.user_agent) ndpi_free(flow->http.user_agent);
-
+ if(flow->protos.kerberos.pktbuf) ndpi_free(flow->protos.kerberos.pktbuf);
+
if(flow->l4_proto == IPPROTO_TCP) {
if(flow->l4.tcp.tls_srv_cert_fingerprint_ctx)
ndpi_free(flow->l4.tcp.tls_srv_cert_fingerprint_ctx);
diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c
index 533995604..ae33d525a 100644
--- a/src/lib/protocols/kerberos.c
+++ b/src/lib/protocols/kerberos.c
@@ -28,7 +28,7 @@
#include "ndpi_api.h"
-/* #define KERBEROS_DEBUG 1 */
+//#define KERBEROS_DEBUG 1
static void ndpi_int_kerberos_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
@@ -41,62 +41,195 @@ static void ndpi_int_kerberos_add_connection(struct ndpi_detection_module_struct
void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
+#ifdef KERBEROS_DEBUG
+ u_int16_t sport = packet->tcp ? ntohs(packet->tcp->source) : ntohs(packet->udp->source);
+ u_int16_t dport = packet->tcp ? ntohs(packet->tcp->dest) : ntohs(packet->udp->dest);
+#endif
NDPI_LOG_DBG(ndpi_struct, "search KERBEROS\n");
+#ifdef KERBEROS_DEBUG
+ printf("\n[Kerberos] Process packet [len: %u]\n", packet->payload_packet_len);
+#endif
+
+ if(flow->protos.kerberos.pktbuf != NULL) {
+ u_int missing = flow->protos.kerberos.pktbuf_maxlen - flow->protos.kerberos.pktbuf_currlen;
+
+ if(packet->payload_packet_len <= missing) {
+ memcpy(&flow->protos.kerberos.pktbuf[flow->protos.kerberos.pktbuf_currlen], packet->payload, packet->payload_packet_len);
+ flow->protos.kerberos.pktbuf_currlen += packet->payload_packet_len;
+
+ if(flow->protos.kerberos.pktbuf_currlen == flow->protos.kerberos.pktbuf_maxlen) {
+ packet->payload = (u_int8_t *)flow->protos.kerberos.pktbuf;
+ packet->payload_packet_len = flow->protos.kerberos.pktbuf_currlen;
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] Packet is now full: processing\n");
+#endif
+ } else {
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] Missing %u bytes: skipping\n",
+ flow->protos.kerberos.pktbuf_maxlen - flow->protos.kerberos.pktbuf_currlen);
+#endif
+
+ return;
+ }
+ }
+ }
+
/* I have observed 0a,0c,0d,0e at packet->payload[19/21], maybe there are other possibilities */
if(packet->payload_packet_len >= 4) {
- u_int32_t kerberos_len = ntohl(get_u_int32_t(packet->payload, 0));
- u_int32_t expected_len = packet->payload_packet_len - 4;
+ u_int32_t kerberos_len, expected_len;
+ u_int16_t base_offset = 0;
+
+ if(packet->tcp) {
+ kerberos_len = ntohl(get_u_int32_t(packet->payload, 0)),
+ expected_len = packet->payload_packet_len - 4;
+ base_offset = 4;
+ } else
+ base_offset = 0, kerberos_len = expected_len = packet->payload_packet_len;
- if(kerberos_len < 1514) {
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] [Kerberos len: %u][expected_len: %u]\n", kerberos_len, expected_len);
+#endif
+
+ if(kerberos_len < 12000) {
/*
Kerberos packets might be too long for a TCP packet
so it could be split across two packets. Instead of
rebuilding the stream we use a heuristic approach
*/
- if(kerberos_len >= expected_len) {
+ if(kerberos_len > expected_len) {
+ if(packet->tcp) {
+ flow->protos.kerberos.pktbuf = (char*)ndpi_malloc(kerberos_len+4);
+ if(flow->protos.kerberos.pktbuf != NULL) {
+ flow->protos.kerberos.pktbuf_maxlen = kerberos_len+4;
+ memcpy(flow->protos.kerberos.pktbuf, packet->payload, packet->payload_packet_len);
+ flow->protos.kerberos.pktbuf_currlen = packet->payload_packet_len;
+ }
+ }
+
+ return;
+ } else if(kerberos_len == expected_len) {
if(packet->payload_packet_len > 128) {
- u_int16_t koffset;
+ u_int16_t koffset, i;
- if(packet->payload[14] == 0x05) /* PVNO */
- koffset = 19;
- else
- koffset = 21;
+ for(i=8; i<16; i++)
+ if((packet->payload[base_offset+i] == 0x03)
+ && (packet->payload[base_offset+i+1] == 0x02)
+ && (packet->payload[base_offset+i+2] == 0x01)
+ && (packet->payload[base_offset+i+3] != 0x05)
+ )
+ break;
+
+ koffset = base_offset + i + 3;
- if((packet->payload[koffset] == 0x0a || packet->payload[koffset] == 0x0c || packet->payload[koffset] == 0x0d || packet->payload[koffset] == 0x0e)) {
#ifdef KERBEROS_DEBUG
- printf("[Kerberos] Packet found\n");
+ printf("[Kerberos] [msg-type: 0x%02X/%u][koffset: %u]\n",
+ packet->payload[koffset], packet->payload[koffset], koffset);
+#endif
+
+ if(((packet->payload[koffset] == 0x0A)
+ || (packet->payload[koffset] == 0x0C)
+ || (packet->payload[koffset] == 0x0D)
+ || (packet->payload[koffset] == 0x0E))) {
+ u_int16_t koffsetp, body_offset, pad_len;
+ u_int8_t msg_type = packet->payload[koffset];
+
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] Packet found 0x%02X/%u\n", msg_type, msg_type);
+#endif
+ if(msg_type != 0x0d) /* TGS-REP */ {
+ /* Process only on requests */
+ if(packet->payload[koffset+1] == 0xA3) {
+ if(packet->payload[koffset+3] == 0x30)
+ pad_len = packet->payload[koffset+4];
+ else {
+ /* Long pad */
+ pad_len = packet->payload[koffset+2];
+ for(i=3; i<10; i++) if(packet->payload[koffset+i] == pad_len) break;
+
+ pad_len = (packet->payload[koffset+i+1] << 8) + packet->payload[koffset+i+2];
+ koffset += i-2;
+ }
+ } else
+ pad_len = 0;
+
+#ifdef KERBEROS_DEBUG
+ printf("pad_len=0x%02X/%u\n", pad_len, pad_len);
+#endif
+
+ if(pad_len > 0) {
+ koffsetp = koffset + 2;
+ for(i=0; i<4; i++) if(packet->payload[koffsetp] != 0x30) koffsetp++; /* ASN.1 */
+#ifdef KERBEROS_DEBUG
+ printf("koffsetp=%u [%02X %02X] [byte 0 must be 0x30]\n", koffsetp, packet->payload[koffsetp], packet->payload[koffsetp+1]);
+#endif
+ } else
+ koffsetp = koffset;
+
+ body_offset = koffsetp + 1 + pad_len;
+
+ for(i=0; i<10; i++) if(packet->payload[body_offset] != 0x05) body_offset++; /* ASN.1 */
+#ifdef KERBEROS_DEBUG
+ printf("body_offset=%u [%02X %02X] [byte 0 must be 0x05]\n", body_offset, packet->payload[body_offset], packet->payload[body_offset+1]);
+#endif
+ }
+
+ if(msg_type == 0x0A) /* AS-REQ */ {
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] Processing AS-REQ\n");
#endif
- if(packet->payload[koffset] == 0x0a) /* AS-REQ */ {
- u_int16_t koffsetp, pad_data_len, body_offset;
-
- koffsetp = koffset + 4;
- pad_data_len = packet->payload[koffsetp];
- body_offset = pad_data_len + koffsetp;
if(body_offset < packet->payload_packet_len) {
- u_int name_offset = body_offset + 30;
+ u_int16_t name_offset;
+
+ name_offset = body_offset + 13;
+ for(i=0; i<10; 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]);
+#endif
if(name_offset < packet->payload_packet_len) {
- u_int cname_len = packet->payload[name_offset];
+ u_int cname_len;
+
+ name_offset += 1;
+ if(packet->payload[name_offset+1] < ' ') /* Isn't printable ? */
+ name_offset++;
+
+ if(packet->payload[name_offset+1] == 0x1b)
+ name_offset += 2;
+
+ cname_len = packet->payload[name_offset];
if((cname_len+name_offset) < packet->payload_packet_len) {
- u_int realm_len, realm_offset = cname_len + name_offset + 4, i;
- char cname_str[24];
+ u_int realm_len, realm_offset, i;
+ char cname_str[48];
+ u_int8_t num_cname = 0;
- if(cname_len > sizeof(cname_str)-1)
- cname_len = sizeof(cname_str)-1;
+ while(++num_cname <= 2) {
+ if(cname_len > sizeof(cname_str)-1)
+ cname_len = sizeof(cname_str)-1;
- 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]);
+ 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]);
#ifdef KERBEROS_DEBUG
- printf("[Kerberos Cname][len: %u][%s]\n", cname_len, cname_str);
+ printf("[AS-REQ][s/dport: %u/%u][Kerberos Cname][len: %u][%s]\n",
+ sport, dport, cname_len, cname_str);
#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;
+ }
+
+ realm_offset = cname_len + name_offset + 3;
+
/* if cname does not end with a $ then it's a username */
if(cname_len && cname_str[cname_len-1] == '$') {
cname_str[cname_len-1] = '\0';
@@ -104,62 +237,97 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
} else
snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str);
+ for(i=0; i<10; i++) if(packet->payload[realm_offset] != 0x1b) name_offset++; /* ASN.1 */
+#ifdef KERBEROS_DEBUG
+ printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset, packet->payload[realm_offset], packet->payload[realm_offset+1]);
+#endif
+ realm_offset += 1;
+ //if(num_cname == 2) realm_offset++;
realm_len = packet->payload[realm_offset];
if((realm_offset+realm_len) < packet->payload_packet_len) {
- char realm_str[24];
+ char realm_str[48];
if(realm_len > sizeof(realm_str)-1)
realm_len = sizeof(realm_str);
- strncpy(realm_str, (char*)&packet->payload[realm_offset+1], realm_len);
+ realm_offset += 1;
+
+ strncpy(realm_str, (char*)&packet->payload[realm_offset], realm_len);
realm_str[realm_len] = '\0';
for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]);
#ifdef KERBEROS_DEBUG
- printf("[Kerberos Realm][len: %u][%s]\n", realm_len, realm_str);
+ printf("[AS-REQ][Kerberos Realm][len: %u][%s]\n", realm_len, realm_str);
#endif
snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str);
}
}
}
- }
- } else if(packet->payload[koffset] == 0x0c) /* TGS-REQ */ {
- u_int16_t koffsetp, pad_data_len, body_offset;
-
- koffsetp = koffset + 3;
- pad_data_len = ntohs(*((u_int16_t*)&packet->payload[koffsetp]));
- body_offset = pad_data_len + koffsetp + 4;
+ }
+ } else if(msg_type == 0x0c) /* TGS-REQ */ {
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] Processing TGS-REQ\n");
+#endif
if(body_offset < packet->payload_packet_len) {
- u_int name_offset = body_offset + 14;
+ u_int name_offset, padding_offset = body_offset + 4;
+
+ name_offset = padding_offset;
+ for(i=0; i<10; 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]);
+#endif
if(name_offset < packet->payload_packet_len) {
- u_int realm_len = packet->payload[name_offset];
+ u_int realm_len;
+
+ name_offset++;
+ realm_len = packet->payload[name_offset];
if((realm_len+name_offset) < packet->payload_packet_len) {
u_int i;
- char realm_str[24];
+ char realm_str[48];
if(realm_len > sizeof(realm_str)-1)
realm_len = sizeof(realm_str)-1;
- strncpy(realm_str, (char*)&packet->payload[name_offset+1], realm_len);
+ name_offset += 1;
+
+ strncpy(realm_str, (char*)&packet->payload[name_offset], realm_len);
realm_str[realm_len] = '\0';
for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]);
#ifdef KERBEROS_DEBUG
- printf("[Kerberos Realm][len: %u][%s]\n", realm_len, realm_str);
+ printf("[TGS-REQ][s/dport: %u/%u][Kerberos Realm][len: %u][%s]\n", sport, dport, realm_len, realm_str);
#endif
snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str);
+
+ /* If necessary we can decode sname */
+
+ if(flow->protos.kerberos.pktbuf) ndpi_free(flow->protos.kerberos.pktbuf);
+ flow->protos.kerberos.pktbuf = NULL;
}
}
}
+ if(packet->udp)
+ ndpi_int_kerberos_add_connection(ndpi_struct, flow);
+
/* We set the protocol in the response */
+ if(flow->protos.kerberos.pktbuf != NULL) {
+ free(flow->protos.kerberos.pktbuf);
+ flow->protos.kerberos.pktbuf = NULL;
+ }
+
return;
- } else if(packet->payload[koffset] == 0x0d) /* TGS-RES */ {
+ } else if(msg_type == 0x0d) /* TGS-REP */ {
u_int16_t koffsetp, pad_data_len, cname_offset;
+
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos] Processing TGS-REP\n");
+#endif
koffsetp = koffset + 4;
pad_data_len = packet->payload[koffsetp];
@@ -170,20 +338,21 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
u_int8_t cname_len = packet->payload[cname_offset];
if((cname_offset+cname_offset) < packet->payload_packet_len) {
- char cname_str[24];
+ char cname_str[48];
u_int i;
-
+
if(cname_len > sizeof(cname_str)-1)
cname_len = sizeof(cname_str)-1;
-
+
strncpy(cname_str, (char*)&packet->payload[cname_offset+1], cname_len);
cname_str[cname_len] = '\0';
for(i=0; i<cname_len; i++) cname_str[i] = tolower(cname_str[i]);
-
+
#ifdef KERBEROS_DEBUG
- printf("[Kerberos Cname][len: %u][%s]\n", cname_len, cname_str);
+ printf("[TGS-REP][s/dport: %u/%u][Kerberos Cname][len: %u][%s]\n",
+ sport, dport, cname_len, cname_str);
#endif
-
+
if(cname_len && cname_str[cname_len-1] == '$') {
cname_str[cname_len-1] = '\0';
snprintf(flow->protos.kerberos.hostname, sizeof(flow->protos.kerberos.hostname), "%s", cname_str);
@@ -194,7 +363,7 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
}
}
}
-
+
return;
}
@@ -208,6 +377,11 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
}
}
} else {
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos][s/dport: %u/%u] Skipping packet: too long [kerberos_len: %u]\n",
+ sport, dport, kerberos_len);
+#endif
+
if(flow->protos.kerberos.domain[0] != '\0')
return;
}
@@ -222,7 +396,7 @@ void init_kerberos_dissector(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_set_bitmask_protocol_detection("Kerberos", ndpi_struct, detection_bitmask, *id,
NDPI_PROTOCOL_KERBEROS,
ndpi_search_kerberos,
- NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
+ NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
SAVE_DETECTION_BITMASK_AS_UNKNOWN,
ADD_TO_DETECTION_BITMASK);