-
Notifications
You must be signed in to change notification settings - Fork 3
/
detect-http-basic-auth-server-bruteforced.bro
74 lines (60 loc) · 3.18 KB
/
detect-http-basic-auth-server-bruteforced.bro
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
##! HTTP basic-auth brute-forced server detector
##! detect servers under potential brute force attack / misconfiguration
##! tracking for servers (by IP, not HOST) throwing a high number of 401's
##! Improvements & derivatives
##! - Presently watches for attempts with a user
##! Break that into two seperate heuristics- track attempts by user, distinct passwords
##! could identify misconfigured services sending same user/password over & over again
##! - Implement check for "HTTP::default_capture_password=T" and if so also check for "&& c$http?$password"
##! - Track heuristics by client / host, client/ ip address, client / subnet
##! - Dynamicaly detect if "HTTP::default_capture_password=T"
##! - Right now tracking for BOTH local and remote connections; will catch inbound & outbound attackers
##! can enable remote only with is_local_addr
@load base/protocols/http
@load base/frameworks/sumstats
@load base/utils/time
module HTTP;
export {
redef enum Notice::Type += {
## Indicates a host bruteforcing HTTP Basic Auth logins by watching for too many
## rejected usernames or failed passwords.
HTTP_Basic_Auth_Server_Bruteforced
};
## How many rejected usernames or passwords are required before being
## considered to be bruteforcing.
const basic_auth_bruteforced_server_threshold: double = 20 &redef;
## The time period in which the threshold needs to be crossed before
## being reset.
const basic_auth_bruteforced_server_measurement_interval = 15mins &redef;
}
event bro_init()
{
local r1: SumStats::Reducer = [$stream="http-basic-auth.server_401", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(basic_auth_bruteforced_server_threshold+2)];
SumStats::create([$name="http-basic-auth-detect-server-bruteforced",
$epoch=basic_auth_bruteforced_server_measurement_interval,
$reducers=set(r1),
$threshold_val(key: SumStats::Key, result: SumStats::Result) =
{
return result["http-basic-auth.server_401"]$num+0.0;
},
$threshold=basic_auth_bruteforced_server_threshold,
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
{
local r = result["http-basic-auth.server_401"];
local dur = duration_to_mins_secs(r$end-r$begin);
local plural = r$unique>1 ? "s" : "";
local message = fmt("%s had %d failed basic http auth logins from %d clients%s in %s", key$host, r$num, r$unique, plural, dur);
NOTICE([$note=HTTP::HTTP_Basic_Auth_Server_Bruteforced,
$src=key$host,
$msg=message,
$identifier=cat(key$host)]);
}]);
}
event http_reply(c: connection, version: string, code: count, reason: string)
{
if (c$http?$status_code && c$http$status_code == 401 && c$http?$username) # && c$http?$password
{
# SumStats::observe("http-basic-auth.server_401", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]);
SumStats::observe("http-basic-auth.server_401", [$host=c$id$resp_h], [$str=cat(c$id$orig_h)]);
}
}