Files
DetectionLab/Vagrant/resources/malcolm/zeek/config/login.zeek
2021-08-06 10:35:01 +02:00

254 lines
8.7 KiB
Plaintext

module Login;
# log telnet, rlogin, and rsh events to login.log
export {
redef enum Log::ID += {
## The logging stream identifier
Log_LOGIN
};
type Info : record {
## Time the event occurred
ts : time &log;
## Unique ID for the connection
uid : string &log;
## The connection's 4-tuple of endpoint addresses/port
id : conn_id &log;
## proto (telnet, rlogin, or rsh)
proto : string &log &optional;
## login_success event was seen (successful login)
success : bool &log &default = F;
## login_confused event was seen (successful login)
confused : bool &log &default = F;
## username given for login attempt
user : string &log &optional;
## client_user given for login attempt (empty for telnet, set for rlogin)
client_user : string &log &optional;
## password given for login attempt
password : string &log &optional;
## whether or not a line has been written to login.log
logged : bool &default = F;
};
## Event that can be handled to access the :zeek:type:`Login::Info`
## record as it is sent on to the logging framework.
global log_login : event(rec : Info);
}
# Add the state tracking information variable to the connection record
redef record connection += {
login : Info &optional;
};
###############################################
# constants borrowed from the old Bro 1.5 login.bro required to make some of the telnet/rlogin/rsh events work correctly
# see https://github.com/zeek/zeek/blob/release/1.5/policy/login.bro#L178
# https://github.com/reservoirlabs/brorefguide/blob/master/analysis.texi#L3850
redef skip_authentication = { "WELCOME TO THE BERKELEY PUBLIC LIBRARY", };
redef direct_login_prompts = { "TERMINAL?", };
redef login_prompts = {
"Login:",
"login:",
"Name:",
"Username:",
"User:",
"Member Name",
"User Access Verification",
"Cisco Systems Console",
direct_login_prompts
};
redef login_non_failure_msgs = {
"Failures",
"failures", # probably is "<n> failures since last login"
"failure since last successful login",
"failures since last successful login",
};
redef login_non_failure_msgs = {
"Failures",
"failures", # probably is "<n> failures since last login"
"failure since last successful login",
"failures since last successful login",
} &redef;
redef login_failure_msgs = {
"invalid",
"Invalid",
"incorrect",
"Incorrect",
"failure",
"Failure",
# "Unable to authenticate",
# "unable to authenticate",
"User authorization failure",
"Login failed",
"INVALID",
"Sorry.",
"Sorry,",
};
const router_prompts: set[string] &redef;
redef login_success_msgs = {
"Last login",
"Last successful login",
"Last successful login",
"checking for disk quotas",
"unsuccessful login attempts",
"failure since last successful login",
"failures since last successful login",
router_prompts,
};
redef login_timeouts = {
"timeout",
"timed out",
"Timeout",
"Timed out",
"Error reading command input", # VMS
};
# end borrowed constants from Bro 1.5 login.bro
###############################################
# telnet, rlogin, rsh
const telnet_port = 23/tcp;
const telnet_ports = { telnet_port };
const rlogin_port = 513/tcp;
const rlogin_ports = { rlogin_port };
const rsh_port = 514/tcp;
const rsh_ports = { rsh_port };
redef likely_server_ports += { telnet_ports, rlogin_ports, rsh_ports };
# set_login_session - if has not yet been registered in the connection, instantiate
# the Info record and assign in c$login
function set_login_session(c : connection) {
if ( ! c?$login ) {
local s : Info = [$ts = network_time(), $uid = c$uid, $id = c$id];
switch c$id$resp_p {
case telnet_port:
s$proto = "telnet";
add c$service["telnet"];
break;
case rlogin_port:
s$proto = "rlogin";
add c$service["rlogin"];
break;
case rsh_port:
s$proto = "rsh";
add c$service["rsh"];
break;
}
c$login = s;
}
}
# login_message - log to login.log
function login_message(s : Info) {
# strip some values that can happen in a "confused" state that aren't really valid values
if (( s?$user ) && (( s$user == "" ) || ( s$user == "<none>" ) || ( s$user == "<timeout>" )))
delete s$user;
if (( s?$client_user ) && (( s$client_user == "" ) || ( s$client_user == "<none>" ) || ( s$client_user == "<timeout>" )))
delete s$client_user;
if (( s?$password ) && (( s$password == "" ) || ( s$password == "<none>" ) || ( s$password == "<timeout>" )))
delete s$password;
if (( s?$proto ) && ( s$proto == "" ))
delete s$proto;
s$ts = network_time();
Log::write(Login::Log_LOGIN, s);
s$logged = T;
}
# create log stream for login.log and register telnet, rlogin, and rsh analyzers
event zeek_init() &priority = 5 {
Log::create_stream(Login::Log_LOGIN, [$columns = Info, $ev = log_login, $path = "login"]);
Analyzer::register_for_ports(Analyzer::ANALYZER_TELNET, telnet_ports);
Analyzer::register_for_ports(Analyzer::ANALYZER_RLOGIN, rlogin_ports);
Analyzer::register_for_ports(Analyzer::ANALYZER_RSH, rsh_ports);
}
# login_confused - Generated when tracking of Telnet/Rlogin authentication failed
# https://docs.zeek.org/en/current/scripts/base/bif/plugins/Zeek_Login.events.bif.zeek.html#id-login_confused
event login_confused(c : connection, msg : string, line : string) &priority = 5 {
# print "login_confused", msg, line;
set_login_session(c);
c$login$confused = T;
}
# login_failure - Generated when tracking of Telnet/Rlogin authentication failed
# https://docs.zeek.org/en/current/scripts/base/bif/plugins/Zeek_Login.events.bif.zeek.html#id-login_failure
event login_failure(c : connection, user : string, client_user : string, password : string, line : string) &priority = 5 {
# print "login_failure", user, client_user, password, line;
set_login_session(c);
if ((!c$login?$user) || (c$login$user == ""))
c$login$user = user;
if ((!c$login?$client_user) || (c$login$client_user == ""))
c$login$client_user = client_user;
if ((!c$login?$password) || (c$login$password == ""))
c$login$password = password;
login_message(c$login);
}
# login_success - Generated for successful Telnet/Rlogin logins
# https://docs.zeek.org/en/current/scripts/base/bif/plugins/Zeek_Login.events.bif.zeek.html#id-login_success
event login_success(c : connection, user : string, client_user : string, password : string, line : string) &priority = 5 {
# print "login_success", user, client_user, password, line;
set_login_session(c);
c$login$success = T;
c$login$user = user;
c$login$client_user = client_user;
# it appears for a successful login with rsh where client_user was checked, what we're getting in
# the "password" field is actually not the password, but the first line of data
if ((c$login$proto != "rsh") || (c$login$client_user == ""))
c$login$password = password;
login_message(c$login);
}
event connection_state_remove(c : connection) &priority = -5 {
if (c?$login) {
if ( c$login$logged == F) {
login_message(c$login);
}
delete c$login;
}
}
# for testing:
# for file in /host/telnet/*; do cd /tmp; mkdir -p /host/logs/"$(basename "$file")"; /bin/rm -f /host/logs/"$(basename "$file")"/*; cd /host/logs/"$(basename "$file")"; zeek -r "$file" local > debug_output.txt; cd /tmp; done
# event activating_encryption(c: connection) { print "activating_encryption"; }
# event authentication_accepted(name: string, c: connection) { print "authentication_accepted", name; }
# event authentication_rejected(name: string, c: connection) { print "authentication_rejected", name; }
# event authentication_skipped(c: connection) { print "authentication_skipped"; }
# event bad_option(c: connection) { print "bad_option"; }
# event bad_option_termination(c: connection) { print "bad_option_termination"; }
# event inconsistent_option(c: connection) { print "inconsistent_option"; }
# event login_confused_text(c: connection, line: string) { print "login_confused_text", line; }
# event login_display(c: connection, display: string) { print "login_display", display; }
# event login_input_line(c: connection, line: string) { print "login_input_line", line; }
# event login_output_line(c: connection, line: string) { print "login_output_line", line; }
# event login_terminal(c: connection, terminal: string) { print "login_terminal", terminal; }
# event rsh_reply(c: connection, client_user: string, server_user: string, line: string) { print "rsh_reply", client_user, server_user, line; }
# event rsh_request(c: connection, client_user: string, server_user: string, line: string; new_session: bool) { print "rsh_request", client_user, server_user, line, new_session; }