aboutsummaryrefslogtreecommitdiff
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
parent51cfdfb0d80a7bbcc11bc3b95d1696d8dae900c2 (diff)
Kerberos dissection improvements
5 files changed, 173 insertions, 70 deletions
diff --git a/example/reader_util.c b/example/reader_util.c
index e7fe521a9..6c7dcdb46 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -978,10 +978,12 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
}
/* KERBEROS */
else if(is_ndpi_proto(flow, NDPI_PROTOCOL_KERBEROS)) {
- if(flow->ndpi_flow->protos.kerberos.cname[0] != '\0') {
- snprintf(flow->info, sizeof(flow->info), "%s (%s)",
- flow->ndpi_flow->protos.kerberos.cname,
- flow->ndpi_flow->protos.kerberos.realm);
+ 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)",
+ flow->ndpi_flow->protos.kerberos.hostname,
+ flow->ndpi_flow->protos.kerberos.username,
+ flow->ndpi_flow->protos.kerberos.domain);
}
}
/* HTTP */
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;
}
}
diff --git a/tests/result/kerberos.pcap.out b/tests/result/kerberos.pcap.out
index f56a94611..15b922058 100644
--- a/tests/result/kerberos.pcap.out
+++ b/tests/result/kerberos.pcap.out
@@ -3,28 +3,28 @@ SMBv23 6 1914 3
Kerberos 48 19194 24
LDAP 14 4152 7
- 1 TCP 172.16.8.201:49171 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1486 bytes <-> 1 pkts/1506 bytes][PLAIN TEXT (HAPPYCRAFT.ORG)]
- 2 TCP 172.16.8.201:49160 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1485 bytes <-> 1 pkts/1498 bytes][PLAIN TEXT (HAPPYCRAFT.ORG)]
- 3 TCP 172.16.8.201:49176 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1485 bytes <-> 1 pkts/1498 bytes][PLAIN TEXT (HAPPYCRAFT.ORG)]
+ 1 TCP 172.16.8.201:49171 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1486 bytes <-> 1 pkts/1506 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (HAPPYCRAFT.ORG)]
+ 2 TCP 172.16.8.201:49160 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1485 bytes <-> 1 pkts/1498 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (HAPPYCRAFT.ORG)]
+ 3 TCP 172.16.8.201:49176 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1485 bytes <-> 1 pkts/1498 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (HAPPYCRAFT.ORG)]
4 TCP 172.16.8.201:49173 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/1118 bytes <-> 1 pkts/190 bytes][PLAIN TEXT (HAPPYCRAFT.ORG)]
5 TCP 172.16.8.201:49194 <-> 172.16.8.8:445 [proto: 41/SMBv23][cat: System/18][1 pkts/410 bytes <-> 1 pkts/314 bytes]
6 TCP 172.16.8.201:49193 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/384 bytes <-> 1 pkts/264 bytes]
7 TCP 172.16.8.201:49191 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/368 bytes <-> 1 pkts/264 bytes]
- 8 TCP 172.16.8.201:49157 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/293 bytes <-> 1 pkts/332 bytes][johnson-pc$ (happycraft.org)][PLAIN TEXT (johnson)]
- 9 TCP 172.16.8.201:49166 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/293 bytes <-> 1 pkts/332 bytes][johnson-pc$ (happycraft.org)][PLAIN TEXT (johnson)]
- 10 TCP 172.16.8.201:49181 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/293 bytes <-> 1 pkts/332 bytes][johnson-pc$ (happycraft.org)][PLAIN TEXT (JOHNSON)]
+ 8 TCP 172.16.8.201:49157 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/293 bytes <-> 1 pkts/332 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (johnson)]
+ 9 TCP 172.16.8.201:49166 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/293 bytes <-> 1 pkts/332 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (johnson)]
+ 10 TCP 172.16.8.201:49181 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/293 bytes <-> 1 pkts/332 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (JOHNSON)]
11 TCP 172.16.8.201:49156 <-> 172.16.8.8:445 [proto: 41/SMBv23][cat: System/18][1 pkts/281 bytes <-> 1 pkts/314 bytes]
12 TCP 172.16.8.201:49174 <-> 172.16.8.8:445 [proto: 41/SMBv23][cat: System/18][1 pkts/281 bytes <-> 1 pkts/314 bytes]
- 13 TCP 172.16.8.201:49188 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/369 bytes <-> 1 pkts/216 bytes][PLAIN TEXT (theresa.johnson)]
+ 13 TCP 172.16.8.201:49188 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/369 bytes <-> 1 pkts/216 bytes][theresa.johnson (happycraft)][PLAIN TEXT (theresa.johnson)]
14 TCP 172.16.8.201:49161 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/320 bytes <-> 1 pkts/264 bytes]
15 TCP 172.16.8.201:49179 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/320 bytes <-> 1 pkts/264 bytes]
16 TCP 172.16.8.201:49180 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/320 bytes <-> 1 pkts/264 bytes]
17 TCP 172.16.8.201:49187 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/289 bytes <-> 1 pkts/294 bytes][theresa.johnson (happycraft)][PLAIN TEXT (theresa.johnson)]
18 TCP 172.16.8.201:49169 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/296 bytes <-> 1 pkts/264 bytes][PLAIN TEXT (PSTUsM)]
19 TCP 172.16.8.201:49172 <-> 172.16.8.8:389 [proto: 112/LDAP][cat: System/18][1 pkts/296 bytes <-> 1 pkts/264 bytes]
- 20 TCP 172.16.8.201:49158 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/373 bytes <-> 1 pkts/166 bytes][PLAIN TEXT (johnson)]
- 21 TCP 172.16.8.201:49167 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/373 bytes <-> 1 pkts/166 bytes][PLAIN TEXT (johnson)]
- 22 TCP 172.16.8.201:49182 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/373 bytes <-> 1 pkts/166 bytes][PLAIN TEXT (JOHNSON)]
+ 20 TCP 172.16.8.201:49158 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/373 bytes <-> 1 pkts/166 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (johnson)]
+ 21 TCP 172.16.8.201:49167 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/373 bytes <-> 1 pkts/166 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (johnson)]
+ 22 TCP 172.16.8.201:49182 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/373 bytes <-> 1 pkts/166 bytes][johnson-pc (happycraft.org)][PLAIN TEXT (JOHNSON)]
23 TCP 172.16.8.201:49190 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/271 bytes <-> 1 pkts/244 bytes][PLAIN TEXT (happycraft.org)]
24 TCP 172.16.8.201:49192 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/255 bytes <-> 1 pkts/233 bytes][PLAIN TEXT (20370913024805Z)]
25 TCP 172.16.8.201:49195 <-> 172.16.8.8:88 [proto: 111/Kerberos][cat: Network/14][1 pkts/255 bytes <-> 1 pkts/233 bytes][PLAIN TEXT (20370913024805Z)]