forked from cisagov/Malcolm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathguess.zeek
123 lines (99 loc) · 4.54 KB
/
guess.zeek
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
module Best_Guess;
# given an input map file with the following format:
# proto dport sport name category
# (see https://docs.zeek.org/en/master/frameworks/input.html#reading-data-into-tables
# for details on how the table is loaded),
# load up the table on zeek_init and for each connection_state_remove
# make a "best guess" of protocols based on proto+dport+sport.
# Best guesses are written to bestguess according to Best_Guess::Info
# Table key is transport protocol + destination port + source port
# Zeek will segfault if there is an unset value ('-') in the key,
# so use unknown_transport and 0 for protocol and ports, respectively,
# if they are not defined in the lookup.
type Best_Guess_Key: record {
proto: transport_proto &optional;
dport: count &optional;
sport: count &optional;
};
# Other table values include name, category.
type Best_Guess_Value: record {
name: string &optional;
category: string &optional;
};
export {
redef enum Log::ID += { BEST_GUESS_LOG };
#############################################################################
# This is the format of bestguess.log
type Info: record {
# Timestamp for when the event happened.
ts: time &log;
# Unique ID for the connection.
uid: string &log;
# The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
# transport protocol
proto: transport_proto &log &optional;
# protocol guess values for log
name: string &log &optional;
category: string &log &optional;
# originating structure containing guess info
guess_info: Best_Guess_Value &optional;
};
# Event that can be handled to access the record as it is sent on to the logging framework.
global log_best_guess: event(rec: Best_Guess::Info);
}
# lookup table of Best_Guess_Key -> Best_Guess_Value to be loaded in zeek_init
global proto_guesses: table[transport_proto, count, count] of Best_Guess_Value = table();
# filespec containing best guess mappings
global guest_map_filespec : string = @DIR + "/guess_ics_map.txt";
#############################################################################
event zeek_init() &priority=5 {
# populate the lookup table from guest_map_filespec and then clean up the intermediate source
Input::add_table([$source=guest_map_filespec, $name="guess_ics_map",
$idx=Best_Guess_Key, $val=Best_Guess_Value,
$destination=proto_guesses, $want_record=T]);
Input::remove("guess_ics_map");
# initialize bestguess.log
Log::create_stream(Best_Guess::BEST_GUESS_LOG, [$columns=Best_Guess::Info, $ev=log_best_guess, $path="bestguess"]);
}
#############################################################################
event connection_state_remove(c: connection) {
local p = get_port_transport_proto(c$id$resp_p);
local dp = port_to_count(c$id$resp_p);
local sp = port_to_count(c$id$orig_p);
local guess = Best_Guess_Value($name="");
local category: string = "";
# 1. only check connections for which we don't already know "service"
# 2. skip ICMP, since dp and sp don't mean the same thing for ICMP
if (((!c?$service) || (|c$service| == 0)) && (p != icmp)) {
# Look up permutations of transport protocol + destination port + source port
# from more-specific to less-specific.
if ([p, dp, sp] in proto_guesses)
guess = proto_guesses[p, dp, sp];
else if ([p, dp, 0] in proto_guesses)
guess = proto_guesses[p, dp, 0];
else if ([p, 0, sp] in proto_guesses)
guess = proto_guesses[p, 0, sp];
else if ([unknown_transport, dp, sp] in proto_guesses)
guess = proto_guesses[unknown_transport, dp, sp];
else if ([unknown_transport, dp, 0] in proto_guesses)
guess = proto_guesses[unknown_transport, dp, 0];
else if ([unknown_transport, 0, sp] in proto_guesses)
guess = proto_guesses[unknown_transport, 0, sp];
# if a best guess was made based on protocol and ports, log it
if ((guess?$name) && (guess$name != "")) {
# as category may be undefined, check before accessing
if (guess?$category)
category = guess$category;
# log entry into bestguess.log
local info = Best_Guess::Info($ts=network_time(),
$uid=c$uid,
$id=c$id,
$proto=p,
$name=guess$name,
$category=category,
$guess_info=guess);
Log::write(Best_Guess::BEST_GUESS_LOG, info);
} # found guess
} # if (p != icmp)
} # connection_state_remove