This file is indexed.

/usr/share/bro/policy/misc/scan.bro is in bro-common 2.5-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
##! TCP Scan detection.

# ..Authors: Sheharbano Khattak
#            Seth Hall
#            All the authors of the old scan.bro

@load base/frameworks/notice
@load base/frameworks/sumstats

@load base/utils/time

module Scan;

export {
	redef enum Notice::Type += {
		## Address scans detect that a host appears to be scanning some
		## number of destinations on a single port. This notice is
		## generated when more than :bro:id:`Scan::addr_scan_threshold`
		## unique hosts are seen over the previous
		## :bro:id:`Scan::addr_scan_interval` time range.
		Address_Scan,

		## Port scans detect that an attacking host appears to be
		## scanning a single victim host on several ports.  This notice
		## is generated when an attacking host attempts to connect to
		## :bro:id:`Scan::port_scan_threshold`
		## unique ports on a single host over the previous
		## :bro:id:`Scan::port_scan_interval` time range.
		Port_Scan,
	};

	## Failed connection attempts are tracked over this time interval for
	## the address scan detection.  A higher interval will detect slower
	## scanners, but may also yield more false positives.
	const addr_scan_interval = 5min &redef;

	## Failed connection attempts are tracked over this time interval for
	## the port scan detection.  A higher interval will detect slower
	## scanners, but may also yield more false positives.
	const port_scan_interval = 5min &redef;

	## The threshold of the unique number of hosts a scanning host has to
	## have failed connections with on a single port.
	const addr_scan_threshold = 25.0 &redef;

	## The threshold of the number of unique ports a scanning host has to
	## have failed connections with on a single victim host.
	const port_scan_threshold = 15.0 &redef;

	global Scan::addr_scan_policy: hook(scanner: addr, victim: addr, scanned_port: port);
	global Scan::port_scan_policy: hook(scanner: addr, victim: addr, scanned_port: port);
}

event bro_init() &priority=5
	{
	local r1: SumStats::Reducer = [$stream="scan.addr.fail", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(addr_scan_threshold+2)];
	SumStats::create([$name="addr-scan",
	                  $epoch=addr_scan_interval,
	                  $reducers=set(r1),
	                  $threshold_val(key: SumStats::Key, result: SumStats::Result) =
	                  	{
	                  	return result["scan.addr.fail"]$unique+0.0;
	                  	},
	                  #$threshold_func=check_addr_scan_threshold,
	                  $threshold=addr_scan_threshold,
	                  $threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
	                  	{
	                  	local r = result["scan.addr.fail"];
	                  	local side = Site::is_local_addr(key$host) ? "local" : "remote";
	                  	local dur = duration_to_mins_secs(r$end-r$begin);
	                  	local message=fmt("%s scanned at least %d unique hosts on port %s in %s", key$host, r$unique, key$str, dur);
	                  	NOTICE([$note=Address_Scan,
	                  	        $src=key$host,
	                  	        $p=to_port(key$str),
	                  	        $sub=side,
	                  	        $msg=message,
	                  	        $identifier=cat(key$host)]);
	                  	}]);

	# Note: port scans are tracked similar to: table[src_ip, dst_ip] of set(port);
	local r2: SumStats::Reducer = [$stream="scan.port.fail", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(port_scan_threshold+2)];
	SumStats::create([$name="port-scan",
	                  $epoch=port_scan_interval,
	                  $reducers=set(r2),
	                  $threshold_val(key: SumStats::Key, result: SumStats::Result) =
	                  	{
	                  	return result["scan.port.fail"]$unique+0.0;
	                  	},
	                  $threshold=port_scan_threshold,
	                  $threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
	                  	{
	                  	local r = result["scan.port.fail"];
	                  	local side = Site::is_local_addr(key$host) ? "local" : "remote";
	                  	local dur = duration_to_mins_secs(r$end-r$begin);
	                  	local message = fmt("%s scanned at least %d unique ports of host %s in %s", key$host, r$unique, key$str, dur);
	                  	NOTICE([$note=Port_Scan,
	                  	        $src=key$host,
	                  	        $dst=to_addr(key$str),
	                  	        $sub=side,
	                  	        $msg=message,
	                  	        $identifier=cat(key$host)]);
	                  	}]);
	}

function add_sumstats(id: conn_id, reverse: bool)
	{
	local scanner      = id$orig_h;
	local victim       = id$resp_h;
	local scanned_port = id$resp_p;

	if ( reverse )
		{
		scanner      = id$resp_h;
		victim       = id$orig_h;
		scanned_port = id$orig_p;
		}

	if ( hook Scan::addr_scan_policy(scanner, victim, scanned_port) )
		SumStats::observe("scan.addr.fail", [$host=scanner, $str=cat(scanned_port)], [$str=cat(victim)]);

	if ( hook Scan::port_scan_policy(scanner, victim, scanned_port) )
		SumStats::observe("scan.port.fail", [$host=scanner, $str=cat(victim)], [$str=cat(scanned_port)]);
	}

function is_failed_conn(c: connection): bool
	{
	# Sr || ( (hR || ShR) && (data not sent in any direction) )
	if ( (c$orig$state == TCP_SYN_SENT && c$resp$state == TCP_RESET) ||
	     (((c$orig$state == TCP_RESET && c$resp$state == TCP_SYN_ACK_SENT) ||
	       (c$orig$state == TCP_RESET && c$resp$state == TCP_ESTABLISHED && "S" in c$history )
	      ) && /[Dd]/ !in c$history )
	   )
		return T;
	return F;
	}

function is_reverse_failed_conn(c: connection): bool
	{
	# reverse scan i.e. conn dest is the scanner
	# sR || ( (Hr || sHr) && (data not sent in any direction) )
	if ( (c$resp$state == TCP_SYN_SENT && c$orig$state == TCP_RESET) ||
	     (((c$resp$state == TCP_RESET && c$orig$state == TCP_SYN_ACK_SENT) ||
	       (c$resp$state == TCP_RESET && c$orig$state == TCP_ESTABLISHED && "s" in c$history )
	      ) && /[Dd]/ !in c$history )
	   )
		return T;
	return F;
	}

event connection_attempt(c: connection)
	{
	local is_reverse_scan = F;
	if ( "H" in c$history )
		is_reverse_scan = T;

	add_sumstats(c$id, is_reverse_scan);
	}

event connection_rejected(c: connection)
	{
	local is_reverse_scan = F;
	if ( "s" in c$history )
		is_reverse_scan = T;

	add_sumstats(c$id, is_reverse_scan);
	}

event connection_reset(c: connection)
	{
	if ( is_failed_conn(c) )
		add_sumstats(c$id, F);
	else if ( is_reverse_failed_conn(c) )
		add_sumstats(c$id, T);
	}

event connection_pending(c: connection)
	{
	if ( is_failed_conn(c) )
		add_sumstats(c$id, F);
	else if ( is_reverse_failed_conn(c) )
		add_sumstats(c$id, T);
	}