diff options
-rw-r--r-- | example/ndpiReader.c | 3 | ||||
-rw-r--r-- | example/reader_util.c | 32 | ||||
-rw-r--r-- | example/reader_util.h | 2 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 4 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 96 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 6 | ||||
-rw-r--r-- | wireshark/ndpi.lua | 367 |
7 files changed, 414 insertions, 96 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index b98bb3374..22f7f3215 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -2056,6 +2056,9 @@ static void printFlow(u_int32_t id, struct ndpi_flow_info *flow, u_int16_t threa fprintf(out, "[Risk Info: %s]", flow->risk_str); } + if(flow->tcp_fingerprint) + fprintf(out, "[TCP Fingerprint: %s]", flow->tcp_fingerprint); + if(flow->ssh_tls.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(buf_ver, sizeof(buf_ver), flow->ssh_tls.ssl_version, &known_tls)); diff --git a/example/reader_util.c b/example/reader_util.c index 28596eb4f..8f9dae101 100644 --- a/example/reader_util.c +++ b/example/reader_util.c @@ -609,8 +609,9 @@ void ndpi_flow_info_free_data(struct ndpi_flow_info *flow) { ndpi_free_bin(&flow->payload_len_bin); #endif - if(flow->risk_str) ndpi_free(flow->risk_str); - if(flow->flow_payload) ndpi_free(flow->flow_payload); + if(flow->tcp_fingerprint) ndpi_free(flow->tcp_fingerprint); + if(flow->risk_str) ndpi_free(flow->risk_str); + if(flow->flow_payload) ndpi_free(flow->flow_payload); } /* ***************************************************** */ @@ -623,7 +624,7 @@ void ndpi_workflow_free(struct ndpi_workflow * workflow) { if(addr_dump_path != NULL) ndpi_cache_address_dump(workflow->ndpi_struct, addr_dump_path, 0); - + ndpi_exit_detection_module(workflow->ndpi_struct); ndpi_free(workflow->ndpi_flows_root); ndpi_free(workflow); @@ -1131,7 +1132,7 @@ static void dump_flow_fingerprint(struct ndpi_workflow * workflow, if(flow->server_hostname) ndpi_serialize_string_string(&serializer, "server_hostname", flow->server_hostname); - + buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len); fprintf(fingerprint_fp, "%s\n", buffer); } @@ -1408,24 +1409,24 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl /* For consistency across platforms replace :0: with :: */ ndpi_patchIPv6Address(flow->info); } - + if(flow->ndpi_flow->protos.dns.geolocation_iata_code[0] != '\0') strcpy(flow->dns.geolocation_iata_code, flow->ndpi_flow->protos.dns.geolocation_iata_code); if(0) { u_int8_t i; - + for(i=0; i<flow->ndpi_flow->protos.dns.num_rsp_addr; i++) { char buf[64]; - + if(flow->ndpi_flow->protos.dns.is_rsp_addr_ipv6[i] == 0) { inet_ntop(AF_INET, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv4, buf, sizeof(buf)); } else { - inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf)); + inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf)); } printf("(%s) %s [ttl: %u]\n", flow->host_server_name, buf, flow->ndpi_flow->protos.dns.rsp_addr_ttl[i]); - } + } } } /* MDNS */ @@ -1520,7 +1521,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl if(flow->ndpi_flow->protos.tls_quic.ja4_client_raw) flow->ssh_tls.ja4_client_raw = strdup(flow->ndpi_flow->protos.tls_quic.ja4_client_raw); - + ndpi_snprintf(flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server), "%s", flow->ndpi_flow->protos.tls_quic.ja3_server); flow->ssh_tls.server_unsafe_cipher = flow->ndpi_flow->protos.tls_quic.server_unsafe_cipher; @@ -1585,6 +1586,9 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl flow->multimedia_flow_type = flow->ndpi_flow->flow_multimedia_type; + if(flow->ndpi_flow->tcp.fingerprint) + flow->tcp_fingerprint = ndpi_strdup(flow->ndpi_flow->tcp.fingerprint); + /* HTTP metadata are "global" not in `flow->ndpi_flow->protos` union; for example, we can have HTTP/BitTorrent and in that case we want to export also HTTP attributes */ if(is_ndpi_proto(flow, NDPI_PROTOCOL_HTTP) @@ -1608,16 +1612,16 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl { ndpi_ip_addr_t ip_addr; struct ndpi_address_cache_item *c; - + memset(&ip_addr, 0, sizeof(ip_addr)); - + if(flow->ip_version == 4) ip_addr.ipv4 = flow->dst_ip; else memcpy(&ip_addr.ipv6, &flow->dst_ip6, sizeof(struct ndpi_in6_addr)); c = ndpi_cache_address_find(workflow->ndpi_struct, ip_addr); - + if(c) { flow->server_hostname = ndpi_strdup(c->hostname); } @@ -2205,7 +2209,7 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, /* At the first packet flush expired cached addresses */ ndpi_cache_address_flush_expired(workflow->ndpi_struct, header->ts.tv_sec); } - + /* Increment raw packet counter */ workflow->stats.raw_packet_count++; diff --git a/example/reader_util.h b/example/reader_util.h index 9eb49accd..4b9d90beb 100644 --- a/example/reader_util.h +++ b/example/reader_util.h @@ -324,7 +324,7 @@ typedef struct ndpi_flow_info { ndpi_multimedia_flow_type multimedia_flow_type; void *src_id, *dst_id; - + char *tcp_fingerprint; struct ndpi_entropy *entropy; struct ndpi_entropy *last_entropy; diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 82eaabcc3..2074181bf 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1312,6 +1312,10 @@ struct ndpi_flow_struct { ndpi_risk risk, risk_shadow; /* Issues found with this flow [bitmask of ndpi_risk] */ struct ndpi_risk_information risk_infos[MAX_NUM_RISK_INFOS]; /* String that contains information about the risks found */ u_int8_t num_risk_infos; + + struct { + char *fingerprint; + } tcp; /* This structure below will not not stay inside the protos diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index bcd3520fb..3265ef80f 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -60,6 +60,8 @@ #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 #endif #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ @@ -4400,7 +4402,7 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str->address_cache) ndpi_term_address_cache(ndpi_str->address_cache); - + ndpi_free(ndpi_str); } @@ -4794,7 +4796,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, def = NULL; else def = &ndpi_str->proto_defaults[subprotocol_id]; - + if(def == NULL) { ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS]; char *equal = strchr(proto, '='); @@ -6724,6 +6726,9 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { ndpi_free(flow->risk_infos[i].info); } + if(flow->tcp.fingerprint) + ndpi_free(flow->tcp.fingerprint); + if(flow->http.url) ndpi_free(flow->http.url); @@ -6904,14 +6909,86 @@ static int ndpi_init_packet(struct ndpi_detection_module_struct *ndpi_str, /* TCP / UDP detection */ if(l4protocol == IPPROTO_TCP) { + u_int16_t header_len; + if(l4_packet_len < 20 /* min size of tcp */) return(1); /* tcp */ packet->tcp = (struct ndpi_tcphdr *) l4ptr; - if(l4_packet_len >= packet->tcp->doff * 4) { - packet->payload_packet_len = l4_packet_len - packet->tcp->doff * 4; - packet->payload = ((u_int8_t *) packet->tcp) + (packet->tcp->doff * 4); + header_len = packet->tcp->doff * 4; + + if(l4_packet_len >= header_len) { + if(flow->tcp.fingerprint == NULL) { + u_int8_t *t = (u_int8_t*)packet->tcp; + u_int16_t flags = ntohs(*((u_int16_t*)&t[12])); + + if((flags & (TH_SYN | TH_ECE | TH_CWR)) == TH_SYN) { + u_int8_t *options = (u_int8_t*)(&t[sizeof(struct ndpi_tcphdr)]); + char fingerprint[128], options_fp[128]; + u_int8_t i, fp_idx = 0, options_fp_idx = 0; + u_int8_t options_len = header_len - sizeof(struct ndpi_tcphdr); + u_int16_t tcp_win = ntohs(packet->tcp->window); + u_int8_t ip_ttl; + u_int8_t sha_hash[NDPI_SHA256_BLOCK_SIZE]; + + if(packet->iph) + ip_ttl = packet->iph->ttl; + else + ip_ttl = packet->iphv6->ip6_hdr.ip6_un1_hlim; + + if(ip_ttl <= 32) ip_ttl = 32; + else if(ip_ttl <= 64) ip_ttl = 64; + else if(ip_ttl <= 128) ip_ttl = 128; + else if(ip_ttl <= 192) ip_ttl = 192; + else ip_ttl = 255; + + fp_idx = snprintf(fingerprint, sizeof(fingerprint), "%u_%u_", ip_ttl, tcp_win); + + for(i=0; i<options_len; ) { + u_int8_t kind = options[i]; + int rc; + + rc = snprintf(&options_fp[options_fp_idx], sizeof(options_fp)-options_fp_idx, "%02x", kind); + options_fp_idx += rc; + + if(kind == 0) /* EOF */ + break; + else if(kind == 1) /* NOP */ + i++; + else { + u_int8_t len = options[i+1]; + + if(len == 0) + break; + else if(kind == 8) { + /* Timestamp: ignore it */ + } else { + int j = i+2; + u_int8_t opt_len = len - 2; + + while(opt_len > 0) { + rc = snprintf(&options_fp[options_fp_idx], sizeof(options_fp)-options_fp_idx, "%02x", options[j]); + options_fp_idx += rc; + j++, opt_len--; + } + } + + i += len; + } + } /* for */ + + ndpi_sha256((const u_char*)options_fp, options_fp_idx, sha_hash); + snprintf(&fingerprint[fp_idx], sizeof(fingerprint)-fp_idx, "%02x%02x%02x%02x%02x%02x", + sha_hash[0], sha_hash[1], sha_hash[2], + sha_hash[3], sha_hash[4], sha_hash[5]); + + flow->tcp.fingerprint = ndpi_strdup(fingerprint); + } + } + + packet->payload_packet_len = l4_packet_len - header_len; + packet->payload = ((u_int8_t *) packet->tcp) + header_len; } else { /* tcp header not complete */ return(1); @@ -7546,7 +7623,7 @@ static void ndpi_reconcile_msteams_udp(struct ndpi_detection_module_struct *ndpi struct ndpi_flow_struct *flow, u_int16_t master) { /* This function can NOT access &ndpi_str->packet since it is called also from ndpi_detection_giveup(), via ndpi_reconcile_protocols() */ - + if(flow->l4_proto == IPPROTO_UDP) { u_int16_t sport = ntohs(flow->c_port); u_int16_t dport = ntohs(flow->s_port); @@ -7694,7 +7771,7 @@ static void ndpi_reconcile_protocols(struct ndpi_detection_module_struct *ndpi_s NDPI_CONFIDENCE_DPI_PARTIAL); } break; - + case NDPI_PROTOCOL_SKYPE_TEAMS: case NDPI_PROTOCOL_SKYPE_TEAMS_CALL: if(flow->l4_proto == IPPROTO_UDP && ndpi_str->msteams_cache) { @@ -9066,8 +9143,7 @@ struct header_line { struct ndpi_int_one_line_struct *line; }; -static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_str) -{ +static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_str) { struct ndpi_packet_struct *packet = &ndpi_str->packet; struct ndpi_int_one_line_struct *line; size_t length; @@ -11366,7 +11442,7 @@ static const struct cfg_param { { "tls", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_subclassification_enabled), NULL }, { "quic", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(quic_subclassification_enabled), NULL }, - + { "smtp", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(smtp_opportunistic_tls_enabled), NULL }, { "imap", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(imap_opportunistic_tls_enabled), NULL }, diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 9b7cc387e..26efd20a2 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -1651,7 +1651,11 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct, ndpi_serialize_string_uint32(serializer, "ip", ip_version); - ndpi_serialize_string_string(serializer, "proto", ndpi_get_ip_proto_name(l4_protocol, l4_proto_name, sizeof(l4_proto_name))); + if(flow->tcp.fingerprint) + ndpi_serialize_string_string(serializer, "tcp_fingerprint", flow->tcp.fingerprint); + + ndpi_serialize_string_string(serializer, "proto", + ndpi_get_ip_proto_name(l4_protocol, l4_proto_name, sizeof(l4_proto_name))); return(ndpi_dpi2json(ndpi_struct, flow, l7_protocol, serializer)); } diff --git a/wireshark/ndpi.lua b/wireshark/ndpi.lua index 3db686206..c1758c03d 100644 --- a/wireshark/ndpi.lua +++ b/wireshark/ndpi.lua @@ -32,10 +32,13 @@ end -- ############################################## -local ndpi_proto = Proto("ndpi", "nDPI Protocol Interpreter") +local ndpi_proto = Proto("ndpi", "nDPI Protocol Interpreter") +local tcp_fprint = Proto("ndpi.tcp_fingerprint", "TCP Fingerprint") + ndpi_proto.fields = {} local ndpi_fds = ndpi_proto.fields +local tcp_fprint_fds = tcp_fprint.fields ndpi_fds.magic = ProtoField.new("nDPI Magic", "ndpi.magic", ftypes.UINT32, nil, base.HEX) ndpi_fds.network_protocol = ProtoField.new("nDPI Network Protocol", "ndpi.protocol.network", ftypes.UINT8, nil, base.DEC) ndpi_fds.application_protocol = ProtoField.new("nDPI Application Protocol", "ndpi.protocol.application", ftypes.UINT16, nil, base.DEC) @@ -153,9 +156,10 @@ local ntop_proto = Proto("ntop", "ntop Extensions") ntop_proto.fields = {} local ntop_fds = ntop_proto.fields -ntop_fds.client_nw_rtt = ProtoField.new("TCP client network RTT (msec)", "ntop.latency.client_rtt", ftypes.FLOAT, nil, base.NONE) -ntop_fds.server_nw_rtt = ProtoField.new("TCP server network RTT (msec)", "ntop.latency.server_rtt", ftypes.FLOAT, nil, base.NONE) -ntop_fds.appl_latency_rtt = ProtoField.new("Application Latency RTT (msec)", "ntop.latency.appl_rtt", ftypes.FLOAT, nil, base.NONE) +ntop_fds.client_nw_rtt = ProtoField.new("TCP client network RTT (msec)", "ntop.latency.client_rtt", ftypes.FLOAT, nil, base.NONE) +ntop_fds.server_nw_rtt = ProtoField.new("TCP server network RTT (msec)", "ntop.latency.server_rtt", ftypes.FLOAT, nil, base.NONE) +ntop_fds.appl_latency_rtt = ProtoField.new("Application Latency RTT (msec)", "ntop.latency.appl_rtt", ftypes.FLOAT, nil, base.NONE) +ntop_fds.tcp_fingerprint = ProtoField.new("TCP Fingerprint", "ntop.tcp_fingerprint", ftypes.STRING, nil, base.NONE) local f_eth_source = Field.new("eth.src") local f_eth_trailer = Field.new("eth.trailer") @@ -171,8 +175,6 @@ local f_dns_response = Field.new("dns.flags.response") local f_udp_len = Field.new("udp.length") local f_tcp_header_len = Field.new("tcp.hdr_len") local f_tcp_win = Field.new("tcp.window_size_value") -local f_tcp_mss = Field.new("tcp.options.mss_val") -local f_tcp_wscale = Field.new("tcp.options.wscale.shift") local f_tcp_stream = Field.new("tcp.stream") local f_tcp_options = Field.new("tcp.options") local f_ip_len = Field.new("ip.len") @@ -368,11 +370,211 @@ local ja4_db = { } -- ############################################## +-- ############################################## + +-- From http://pastebin.com/gsFrNjbt linked from http://www.computercraft.info/forums2/index.php?/topic/8169-sha-256-in-pure-lua/ + +-- +-- Adaptation of the Secure Hashing Algorithm (SHA-244/256) +-- Found Here: http://lua-users.org/wiki/SecureHashAlgorithm +-- +-- Using an adapted version of the bit library +-- Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua +-- + +local MOD = 2^32 +local MODM = MOD-1 + +local function memoize(f) + local mt = {} + local t = setmetatable({}, mt) + function mt:__index(k) + local v = f(k) + t[k] = v + return v + end + return t +end + +local function make_bitop_uncached(t, m) + local function bitop(a, b) + local res,p = 0,1 + while a ~= 0 and b ~= 0 do + local am, bm = a % m, b % m + res = res + t[am][bm] * p + a = (a - am) / m + b = (b - bm) / m + p = p*m + end + res = res + (a + b) * p + return res + end + return bitop +end + +local function make_bitop(t) + local op1 = make_bitop_uncached(t,2^1) + local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end) + return make_bitop_uncached(op2, 2 ^ (t.n or 1)) +end + +local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4}) + +local function bxor(a, b, c, ...) + local z = nil + if b then + a = a % MOD + b = b % MOD + z = bxor1(a, b) + if c then z = bxor(z, c, ...) end + return z + elseif a then return a % MOD + else return 0 end +end + +local function band(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = ((a + b) - bxor1(a,b)) / 2 + if c then z = bit32_band(z, c, ...) end + return z + elseif a then return a % MOD + else return MODM end +end + +local function bnot(x) return (-1 - x) % MOD end + +local function rshift1(a, disp) + if disp < 0 then return lshift(a,-disp) end + return math.floor(a % 2 ^ 32 / 2 ^ disp) +end + +local function rshift(x, disp) + if disp > 31 or disp < -31 then return 0 end + return rshift1(x % MOD, disp) +end + +local function lshift(a, disp) + if disp < 0 then return rshift(a,-disp) end + return (a * 2 ^ disp) % 2 ^ 32 +end + +local function rrotate(x, disp) + x = x % MOD + disp = disp % 32 + local low = band(x, 2 ^ disp - 1) + return rshift(x, disp) + lshift(low, 32 - disp) +end + +local k = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +} + +local function str2hexa(s) + return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end)) +end + +local function num2s(l, n) + local s = "" + for i = 1, n do + local rem = l % 256 + s = string.char(rem) .. s + l = (l - rem) / 256 + end + return s +end + +local function s232num(s, i) + local n = 0 + for i = i, i + 3 do n = n*256 + string.byte(s, i) end + return n +end + +local function preproc(msg, len) + local extra = 64 - ((len + 9) % 64) + len = num2s(8 * len, 8) + msg = msg .. "\128" .. string.rep("\0", extra) .. len + assert(#msg % 64 == 0) + return msg +end + +local function initH256(H) + H[1] = 0x6a09e667 + H[2] = 0xbb67ae85 + H[3] = 0x3c6ef372 + H[4] = 0xa54ff53a + H[5] = 0x510e527f + H[6] = 0x9b05688c + H[7] = 0x1f83d9ab + H[8] = 0x5be0cd19 + return H +end + +local function digestblock(msg, i, H) + local w = {} + for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end + for j = 17, 64 do + local v = w[j - 15] + local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3)) + v = w[j - 2] + w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10)) + end + + local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] + for i = 1, 64 do + local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22)) + local maj = bxor(band(a, b), band(a, c), band(b, c)) + local t2 = s0 + maj + local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25)) + local ch = bxor (band(e, f), band(bnot(e), g)) + local t1 = h + s1 + ch + k[i] + w[i] + h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2 + end + + H[1] = band(H[1] + a) + H[2] = band(H[2] + b) + H[3] = band(H[3] + c) + H[4] = band(H[4] + d) + H[5] = band(H[5] + e) + H[6] = band(H[6] + f) + H[7] = band(H[7] + g) + H[8] = band(H[8] + h) +end + +-- Made this global +function sha256(msg) + msg = preproc(msg, #msg) + local H = initH256({}) + for i = 1, #msg, 64 do digestblock(msg, i, H) end + return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) .. + num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4)) +end + +-- ############################################## +-- ############################################## function string.contains(String,Start) if type(String) ~= 'string' or type(Start) ~= 'string' then return false end + return(string.find(String,Start,1) ~= nil) end @@ -1088,81 +1290,103 @@ end function tcp_fingerprint(tvb, pinfo, tree, ip_version) local tcp_flags = getval(f_tcp_flags()) - if(tcp_flags == "0x0002") then -- SYN - local tcp_win = getval(f_tcp_win()) - local tcp_mss = getval(f_tcp_mss()) - local tcp_wss = getval(f_tcp_wscale()) + if(tcp_flags == "0x0002") then -- SYN local tcp_options = f_tcp_options() - local d_tcp_options = tcp_options.display - local fingerprint = "" - local d_tcp_options_len = d_tcp_options:len() - local tcp_opt_debug = false - i = 1 - while(i < d_tcp_options_len) do - if(tcp_opt_debug) then tprint("[offset "..i .. "/".. d_tcp_options:len().."]") end + if(tcp_options ~= nil) then + local tcp_win = getval(f_tcp_win()) + local fingerprint = "" + local d_tcp_options = tcp_options.display + local d_tcp_options_len = d_tcp_options:len() + local tcp_opt_debug = false + + if(tcp_win == "nil") then tcp_win = 0 end - local kind = d_tcp_options:sub(i,i+1) - - if(tcp_opt_debug) then tprint("[Kind: " .. kind .."] *** ") end - - i = i + 2 -- Skip kind + i = 1 + while(i < d_tcp_options_len) do + if(tcp_opt_debug) then tprint("[offset "..i .. "/".. d_tcp_options:len().."]") end + + local kind = d_tcp_options:sub(i,i+1) + + if(tcp_opt_debug) then tprint("[Kind: " .. kind .."] *** ") end + + i = i + 2 -- Skip kind + + fingerprint = fingerprint .. kind + + if(kind == "00") then + -- EOL + if(tcp_opt_debug) then tprint("[" .. kind .."][EOL]") end + elseif(kind == "01") then + -- NOP + if(tcp_opt_debug) then tprint("[" .. kind .."][NOP]") end + else + local len = d_tcp_options:sub(i, i+1) - fingerprint = fingerprint .. kind - - if(kind == "00") then - -- EOL - if(tcp_opt_debug) then tprint("[" .. kind .."][EOL]") end - elseif(kind == "01") then - -- NOP - if(tcp_opt_debug) then tprint("[" .. kind .."][NOP]") end - else - local len = d_tcp_options:sub(i, i+1) + if(tcp_opt_debug) then tprint("[Len: " .. len .."] *** ") end - if(tcp_opt_debug) then tprint("[Len: " .. len .."] *** ") end + len = tonumber(len, 16) + i = i + 2 -- Skip len - len = tonumber(len, 16) - i = i + 2 -- Skip len + if((len ~= nil) and (len > 0)) then + local value_len = 2 * (len-2) + local value + + if(tcp_opt_debug) then tprint("[ValueLen: " .. value_len .."] *** ") end - if(len > 0) then - local value_len = 2 * (len-2) - local value - - if(tcp_opt_debug) then tprint("[ValueLen: " .. value_len .."] *** ") end - - value = d_tcp_options:sub(i, i+value_len) - if(tcp_opt_debug) then tprint("[" .. kind .."][len: ".. len .."][value: ".. value.."]") end + -- Skip timestamps + if((kind ~= "08") and (value_len > 0)) then + value = d_tcp_options:sub(i, i+value_len) + value = value:sub(1, value_len) -- make sure the lenght is correct + if(tcp_opt_debug) then tprint("[" .. kind .."][len: ".. len .."][value: ".. value.."]") end - -- Skip timestamps - if(kind ~= "08") then - fingerprint = fingerprint .. value + fingerprint = fingerprint .. value + end + + i = i + value_len end - - i = i + value_len end + end -- while + + local ip_ttl + local src_ip + + if(ip_version == 6) then + ip_ttl = getval(f_ipv6_hlim()) + src_ip = f_src_ipv6() + else + ip_ttl = getval(f_ip_ttl()) + src_ip = f_src_ip() end + + src_ip = getval(src_ip) + + -- Normalize TTL + ip_ttl = tonumber(ip_ttl) + if(ip_ttl <= 32) then ip_ttl = 32 + elseif(ip_ttl <= 64) then ip_ttl = 64 + elseif(ip_ttl <= 128) then ip_ttl = 128 + elseif(ip_ttl <= 192) then ip_ttl = 192 + else ip_ttl = 255 end + + fingerprint = string.lower(fingerprint) + local f_print + + if(true) then + -- Use SHA256 + f_print = string.lower(ip_ttl .."_".. tcp_win .."_".. string.sub(sha256(fingerprint), 1, 12)) + else + f_print = string.upper(ip_ttl .."_".. tcp_win .."_".. fingerprint) + end + + if(tcp_opt_debug) then tprint("Fingerprint: " .. f_print) end + + local tcp_f_entry = tree:add(ntop_proto, tvb()) + tcp_f_entry:add(ntop_fds.tcp_fingerprint, f_print) + + tcp_host_fingerprints[src_ip] = f_print + tcp_fingerprint_hosts[f_print] = src_ip end - - -- tprint("Fingerprint: "..fingerprint) - - local ip_ttl - local src_ip - - if(ip_version == 6) then - ip_ttl = getval(f_ipv6_hlim()) - src_ip = f_src_ipv6() - else - ip_ttl = getval(f_ip_ttl()) - src_ip = f_src_ip() - end - - src_ip = getval(src_ip) - - -- local f_print = string.upper(ip_ttl .."_".. tcp_win .."_".. tcp_mss .."_".. tcp_wss.."_".. fingerprint) - local f_print = string.upper(tcp_win .."_".. tcp_mss .."_".. tcp_wss.."_".. fingerprint) - tcp_host_fingerprints[src_ip] = f_print - - tcp_fingerprint_hosts[f_print] = src_ip end end @@ -2305,13 +2529,16 @@ end local function tcp_dialog_menu() local win = TextWindow.new("TCP Packets Analysis"); local label = "" + local i + i = 0 label = label .. "TCP Host Fingerprints\n" for k,v in pairsByValues(tcp_host_fingerprints, rev) do label = label .. string.format("%-32s", shortenString(k,32)).."\t"..v.."\n" if(i == 10) then break else i = i + 1 end end - + + i = 0 label = label .. "\nTCP Fingerprint Hosts\n" for k,v in pairsByValues(tcp_fingerprint_hosts, rev) do label = label .. string.format("%-64s", shortenString(k,64)).."\t"..v.."\n" |