aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2019-11-17 22:35:10 +0100
committerLuca Deri <deri@ntop.org>2019-11-17 22:35:10 +0100
commit65a629304c7930bd566b592c84d3478443a9e659 (patch)
tree0b81f4d4d5222af30fc87690ce41e1a6d3422acf /src
parent51cfdfb0d80a7bbcc11bc3b95d1696d8dae900c2 (diff)
Kerberos dissection improvements
Diffstat (limited to 'src')
-rw-r--r--src/include/ndpi_typedefs.h3
-rw-r--r--src/lib/ndpi_utils.c7
-rw-r--r--src/lib/protocols/kerberos.c203
3 files changed, 157 insertions, 56 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index dc529e22b..3325e9cd9 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1203,7 +1203,8 @@ struct ndpi_flow_struct {
} ntp;
struct {
- char cname[24], realm[24];
+
+ char hostname[24], domain[24], username[24];
} kerberos;
struct {
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index ed07d6ba6..067c9456d 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -960,9 +960,10 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
break;
case NDPI_PROTOCOL_KERBEROS:
- ndpi_serialize_start_of_block(serializer, "kerberos");
- ndpi_serialize_string_string(serializer, "cname", flow->protos.kerberos.cname);
- ndpi_serialize_string_string(serializer, "realm", flow->protos.kerberos.realm);
+ ndpi_serialize_start_of_block(serializer, "kerberos");
+ ndpi_serialize_string_string(serializer, "hostname", flow->protos.kerberos.hostname);
+ ndpi_serialize_string_string(serializer, "domain", flow->protos.kerberos.domain);
+ ndpi_serialize_string_string(serializer, "username", flow->protos.kerberos.username);
ndpi_serialize_end_of_block(serializer);
break;
diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c
index b7fcfb61d..333ee628c 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) {
@@ -36,6 +36,7 @@ static void ndpi_int_kerberos_add_connection(struct ndpi_detection_module_struct
NDPI_LOG_DBG(ndpi_struct, "trace KERBEROS\n");
}
+/* ************************************************* */
void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
@@ -44,73 +45,171 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
NDPI_LOG_DBG(ndpi_struct, "search KERBEROS\n");
/* I have observed 0a,0c,0d,0e at packet->payload[19/21], maybe there are other possibilities */
- if(packet->payload_packet_len >= 4 && ntohl(get_u_int32_t(packet->payload, 0)) == packet->payload_packet_len - 4) {
- if(packet->payload_packet_len > 19 &&
- packet->payload[14] == 0x05 &&
- (packet->payload[19] == 0x0a ||
- packet->payload[19] == 0x0c || packet->payload[19] == 0x0d || packet->payload[19] == 0x0e)) {
- if(packet->payload[19] == 0x0a) /* AS-REQ */ {
- u_int pad_data_len = packet->payload[23];
- u_int body_offset = pad_data_len + 23;
-
- if(body_offset < packet->payload_packet_len) {
- u_int name_offset = body_offset + 30;
-
- if(name_offset < packet->payload_packet_len) {
- u_int 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];
-
- 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]);
-
+ 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;
+
+ if(kerberos_len < 1514) {
+ /*
+ 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(packet->payload_packet_len > 128) {
+ u_int16_t koffset;
+
+ if(packet->payload[14] == 0x05) /* PVNO */
+ koffset = 19;
+ else
+ koffset = 21;
+
+ if((packet->payload[koffset] == 0x0a || packet->payload[koffset] == 0x0c || packet->payload[koffset] == 0x0d || packet->payload[koffset] == 0x0e)) {
#ifdef KERBEROS_DEBUG
- printf("[Kerberos Cname][len: %u][%s]\n", cname_len, cname_str);
+ printf("[Kerberos] Packet found\n");
#endif
- snprintf(flow->protos.kerberos.cname, sizeof(flow->protos.kerberos.cname), "%s", cname_str);
+ if(packet->payload[koffset] == 0x0a) /* AS-REQ */ {
+ u_int16_t koffsetp, pad_data_len, body_offset;
- realm_len = packet->payload[realm_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;
+
+ if(name_offset < packet->payload_packet_len) {
+ u_int 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];
+
+ 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]);
+
+#ifdef KERBEROS_DEBUG
+ printf("[Kerberos Cname][len: %u][%s]\n", cname_len, cname_str);
+#endif
+
+ /* if cname does not end with a $ then it's a username */
+ if(cname_str[cname_len-1] == '$') {
+ cname_str[cname_len-1] = '\0';
+ snprintf(flow->protos.kerberos.hostname, sizeof(flow->protos.kerberos.hostname), "%s", cname_str);
+ } else
+ snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str);
- if((realm_offset+realm_len) < packet->payload_packet_len) {
- char realm_str[24];
+ realm_len = packet->payload[realm_offset];
- if(realm_len >= sizeof(realm_str))
- realm_len = sizeof(realm_str);
+ if((realm_offset+realm_len) < packet->payload_packet_len) {
+ char realm_str[24];
- strncpy(realm_str, (char*)&packet->payload[realm_offset+1], realm_len);
- realm_str[realm_len] = '\0';
- for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]);
+ if(realm_len >= sizeof(realm_str))
+ realm_len = sizeof(realm_str);
+ strncpy(realm_str, (char*)&packet->payload[realm_offset+1], 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("[Kerberos Realm][len: %u][%s]\n", realm_len, realm_str);
#endif
- snprintf(flow->protos.kerberos.realm, sizeof(flow->protos.kerberos.realm), "%s", realm_str);
+ 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;
- ndpi_int_kerberos_add_connection(ndpi_struct, flow);
- return;
+ koffsetp = koffset + 3;
+ pad_data_len = ntohs(*((u_int16_t*)&packet->payload[koffsetp]));
+ body_offset = pad_data_len + koffsetp + 4;
- }
+ if(body_offset < packet->payload_packet_len) {
+ u_int name_offset = body_offset + 14;
+
+ if(name_offset < packet->payload_packet_len) {
+ u_int realm_len = packet->payload[name_offset];
- if(packet->payload_packet_len > 21 &&
- packet->payload[16] == 0x05 &&
- (packet->payload[21] == 0x0a ||
- packet->payload[21] == 0x0c || packet->payload[21] == 0x0d || packet->payload[21] == 0x0e)) {
- ndpi_int_kerberos_add_connection(ndpi_struct, flow);
- return;
+ if((realm_len+name_offset) < packet->payload_packet_len) {
+ u_int i;
+ char realm_str[24];
+ if(realm_len > sizeof(realm_str)-1)
+ realm_len = sizeof(realm_str)-1;
+
+ strncpy(realm_str, (char*)&packet->payload[name_offset+1], 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);
+#endif
+ snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str);
+ }
+ }
+ }
+
+ /* We set the protocol in the response */
+ return;
+ } else if(packet->payload[koffset] == 0x0d) /* TGS-RES */ {
+ u_int16_t koffsetp, pad_data_len, cname_offset;
+
+ koffsetp = koffset + 4;
+ pad_data_len = packet->payload[koffsetp];
+ /* Skip realm already filled in request */
+ cname_offset = pad_data_len + koffsetp + 15;
+
+ if(cname_offset < packet->payload_packet_len) {
+ u_int8_t cname_len = packet->payload[cname_offset];
+
+ if((cname_offset+cname_offset) < packet->payload_packet_len) {
+ char cname_str[24];
+ 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);
+#endif
+
+ if(cname_str[cname_len-1] == '$') {
+ cname_str[cname_len-1] = '\0';
+ snprintf(flow->protos.kerberos.hostname, sizeof(flow->protos.kerberos.hostname), "%s", cname_str);
+ } else
+ snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str);
+
+ ndpi_int_kerberos_add_connection(ndpi_struct, flow);
+ }
+ }
+ }
+
+ return;
+ }
+
+ if(packet->payload_packet_len > 21 &&
+ packet->payload[16] == 0x05 &&
+ (packet->payload[21] == 0x0a ||
+ packet->payload[21] == 0x0c || packet->payload[21] == 0x0d || packet->payload[21] == 0x0e)) {
+ ndpi_int_kerberos_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
+ }
+ } else {
+ if(flow->protos.kerberos.domain[0] != '\0')
+ return;
}
}