diff options
-rw-r--r-- | example/reader_util.c | 10 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 3 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 7 | ||||
-rw-r--r-- | src/lib/protocols/kerberos.c | 203 | ||||
-rw-r--r-- | tests/result/kerberos.pcap.out | 20 |
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)] |