mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
191 lines
5 KiB
Text
191 lines
5 KiB
Text
# $Id: trw.bro 2911 2006-05-06 17:58:43Z vern $
|
|
|
|
@load notice
|
|
@load port-name
|
|
@load hot
|
|
|
|
module TRW;
|
|
|
|
export {
|
|
redef enum Notice += {
|
|
TRWAddressScan, # source flagged as scanner by TRW algorithm
|
|
TRWScanSummary, # summary of scanning activities reported by TRW
|
|
};
|
|
|
|
# Activate TRW if T.
|
|
global use_TRW_algorithm = F &redef;
|
|
|
|
# Tell TRW not to flag a friendly remote.
|
|
global do_not_flag_friendly_remotes = T &redef;
|
|
|
|
# Set of services for outbound connections that are possibly triggered
|
|
# by incoming connections.
|
|
const triggered_outbound_services = { ident, finger, 20/tcp, } &redef;
|
|
|
|
# The following correspond to P_D and P_F in the TRW paper, i.e., the
|
|
# desired detection and false positive probabilities.
|
|
global target_detection_prob = 0.99 &redef;
|
|
global target_false_positive_prob = 0.01 &redef;
|
|
|
|
# Given a legitimate remote, the probability that its connection
|
|
# attempt will succeed.
|
|
global theta_zero = 0.8 &redef;
|
|
|
|
# Given a scanner, the probability that its connection attempt
|
|
# will succeed.
|
|
global theta_one = 0.2 &redef;
|
|
|
|
|
|
# These variables the user usually won't alter, except they
|
|
# might want to adjust the expiration times, which is why
|
|
# they're exported here.
|
|
global scan_sources: set[addr] &write_expire = 1 hr;
|
|
global benign_sources: set[addr] &write_expire = 1 hr;
|
|
|
|
global failed_locals: set[addr, addr] &write_expire = 30 mins;
|
|
global successful_locals: set[addr, addr] &write_expire = 30 mins;
|
|
|
|
global lambda: table[addr] of double
|
|
&default = 1.0 &write_expire = 30 mins;
|
|
global num_scanned_locals:
|
|
table[addr] of count &default = 0 &write_expire = 30 mins;
|
|
|
|
# Function called to perform TRW analysis.
|
|
global check_TRW_scan: function(c: connection, state: string,
|
|
reverse: bool): bool;
|
|
}
|
|
|
|
# Set of remote hosts that have been successfully accessed by local hosts.
|
|
global friendly_remotes: set[addr] &read_expire = 30 mins;
|
|
|
|
# Set of local honeypot hosts - for internal use at LBL.
|
|
global honeypot: set[addr];
|
|
|
|
# Approximate solutions for upper and lower thresholds.
|
|
global eta_zero: double; # initialized when Bro starts
|
|
global eta_one: double;
|
|
|
|
event bro_init()
|
|
{
|
|
eta_zero =
|
|
(1 - target_detection_prob) / (1 - target_false_positive_prob);
|
|
eta_one = target_detection_prob / target_false_positive_prob;
|
|
}
|
|
|
|
|
|
event TRW_scan_summary(orig: addr)
|
|
{
|
|
NOTICE([$note=TRWScanSummary, $src=orig,
|
|
$msg=fmt("%s scanned a total of %d hosts",
|
|
orig, num_scanned_locals[orig])]);
|
|
}
|
|
|
|
function check_TRW_scan(c: connection, state: string, reverse: bool): bool
|
|
{
|
|
local id = c$id;
|
|
|
|
local service = "ftp-data" in c$service ? 20/tcp
|
|
: (reverse ? id$orig_p : id$resp_p);
|
|
local orig = reverse ? id$resp_h : id$orig_h;
|
|
local resp = reverse ? id$orig_h : id$resp_h;
|
|
local outbound = is_local_addr(orig);
|
|
|
|
# Mark a remote as friendly if it is successfully accessed by
|
|
# a local with protocols other than triggered_outbound_services.
|
|
# XXX There is an ambiguity to determine who initiated a
|
|
# connection when the status is "OTH".
|
|
if ( outbound )
|
|
{
|
|
if ( resp !in scan_sources &&
|
|
service !in triggered_outbound_services &&
|
|
orig !in honeypot && state != "OTH" )
|
|
add friendly_remotes[resp];
|
|
|
|
return F;
|
|
}
|
|
|
|
if ( orig in scan_sources )
|
|
return T;
|
|
|
|
if ( orig in benign_sources )
|
|
return F;
|
|
|
|
if ( do_not_flag_friendly_remotes && orig in friendly_remotes )
|
|
return F;
|
|
|
|
# Start TRW evaluation.
|
|
local flag = +0;
|
|
local resp_byte = reverse ? c$orig$size : c$resp$size;
|
|
local established = T;
|
|
|
|
if ( state == "S0" || state == "REJ" || state == "OTH" ||
|
|
(state == "RSTOS0" && resp_byte <= 0) )
|
|
established = F;
|
|
|
|
if ( ! established || resp in honeypot )
|
|
{
|
|
if ( [orig, resp] !in failed_locals )
|
|
{
|
|
flag = 1;
|
|
add failed_locals[orig, resp];
|
|
}
|
|
}
|
|
|
|
else if ( [orig, resp] !in successful_locals )
|
|
{
|
|
flag = -1;
|
|
add successful_locals[orig, resp];
|
|
}
|
|
|
|
if ( flag == 0 )
|
|
return F;
|
|
|
|
local ratio = 1.0;
|
|
|
|
# Update the corresponding likelihood ratio of orig.
|
|
if ( theta_zero <= 0 || theta_zero >= 1 || theta_one <= 0 ||
|
|
theta_one >= 1 || theta_one >= theta_zero )
|
|
{
|
|
# Error: theta_zero should be between 0 and 1.
|
|
alarm "bad theta_zero/theta_one in check_TRW_scan";
|
|
use_TRW_algorithm = F;
|
|
return F;
|
|
}
|
|
|
|
if ( flag == 1 )
|
|
ratio = (1 - theta_one) / (1 - theta_zero);
|
|
|
|
if ( flag == -1 )
|
|
ratio = theta_one / theta_zero;
|
|
|
|
++num_scanned_locals[orig];
|
|
|
|
lambda[orig] = lambda[orig] * ratio;
|
|
local updated_lambda = lambda[orig];
|
|
|
|
if ( target_detection_prob <= 0 ||
|
|
target_detection_prob >= 1 ||
|
|
target_false_positive_prob <= 0 ||
|
|
target_false_positive_prob >= 1 )
|
|
{
|
|
# Error: target probabilities should be between 0 and 1
|
|
alarm "bad target probabilities in check_TRW_scan";
|
|
use_TRW_algorithm = F;
|
|
return F;
|
|
}
|
|
|
|
if ( updated_lambda > eta_one )
|
|
{
|
|
add scan_sources[orig];
|
|
NOTICE([$note=TRWAddressScan, $src=orig,
|
|
$msg=fmt("%s scanned a total of %d hosts",
|
|
orig, num_scanned_locals[orig])]);
|
|
schedule 1 day { TRW_scan_summary(orig) };
|
|
return T;
|
|
}
|
|
|
|
if ( updated_lambda < eta_zero )
|
|
add benign_sources[orig];
|
|
|
|
return F;
|
|
}
|