auth_bruteforcing.bro error

I am using below code while running this i am getting below error from below area

if(!auth_success) {
SumStats::observe(“http.auth_errors.attacker”,
[$host=to_addr(c$http$cluster_client_ip)],
[]);
if ( c?$conn )

error

field value missing [AuthBruteforcing::c$http$cluster_client_ip]

code

@load base/frameworks/notice
@load base/frameworks/sumstats
@load base/protocols/http

module AuthBruteforcing;

export {
redef enum Notice::Type += {

Indicates that a host performing HTTP requests leading to

excessive HTTP auth errors was detected.

HTTP_AuthBruteforcing_Attacker,

Indicates that a host was seen to respond excessive HTTP

auth errors. This is tracked by IP address as opposed to

hostname.

HTTP_AuthBruteforcing_Victim,
};

Let’s tag the http item

redef enum HTTP::Tags += {

HTTP status code 401, describing a HTTP auth error

HTTP_AUTH_ERROR,

HTTP describing a successful HTTP auth

HTTP_AUTH_SUCCESS,
};

redef enum Log::ID += { LOG };

type Info: record {
ts: time &log;
uid: string &log;
id: conn_id &log &optional;
cluster_client_ip: string &log &optional;
status_code: count &log &optional;
host: string &log &optional;
uri: string &log &optional;
username: string &log &optional;
auth_success: bool &log &optional;
};

global log_auth: event(rec: Info);

Defines the threshold that determines if a auth bruteforcing attack

is ongoing based on the number of requests that appear to be

attacks.

const auth_errors_threshold: double = 50.0 &redef;

Interval at which to watch for the

:bro:id:AuthBruteforcing::auth_errors_requests_threshold variable to be crossed.

At the end of each interval the counter is reset.

const auth_errors_interval = 5min &redef;

Interval at which to watch for the

:bro:id:AuthBruteforcing::excessive_auth_errors_threshold variable to be

crossed. At the end of each interval the counter is reset.

const excessive_auth_errors_interval = 1min &redef;

const internal_space: subnet = 10.0.0.0/8 &redef;
const public_space: subnet = 63.245.208.0/20 &redef;

const ignore_host_resp: set[addr] = { } &redef;
const ignore_host_orig: set[addr] = { } &redef;
}

event bro_init() &priority=3
{

Create auth_bruteforcing.log

Log::create_stream(AuthBruteforcing::LOG, [$columns=Info, $ev=log_auth]);

HTTP auth errors for requests FROM the same host

local r1: SumStats::Reducer = [$stream=“http.auth_errors.attacker”, $apply=set(SumStats::SUM)];
SumStats::create([$name=“auth-http-errors-attackers”,
$epoch=auth_errors_interval,
$reducers=set(r1),
$threshold_val(key: SumStats::Key, result: SumStats::Result) = {
return result[“http.auth_errors.attacker”]$sum;
},
$threshold=auth_errors_threshold,
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) = {
NOTICE([$note=HTTP_AuthBruteforcing_Attacker,
$msg=fmt(“HTTP auth bruteforcing from attacker %s”, key$host),
$sub=fmt("%.0f auth failed in %s", result[“http.auth_errors.attacker”]$sum, auth_errors_interval),
$src=key$host,
$n=to_count(fmt("%.0f", result[“http.auth_errors.attacker”]$sum))
]);
}]);

HTTP errors for requests TO the same host

local r2: SumStats::Reducer = [$stream=“http.auth_errors.victim”, $apply=set(SumStats::SUM)];
SumStats::create([$name=“auth-http-errors-victims”,
$epoch=auth_errors_interval,
$reducers=set(r2),
$threshold_val(key: SumStats::Key, result: SumStats::Result) = {
return result[“http.auth_errors.victim”]$sum;
},
$threshold=auth_errors_threshold,
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) = {
NOTICE([$note=HTTP_AuthBruteforcing_Victim,
$msg=fmt(“HTTP auth bruteforcing to victim %s”, key$host),
$sub=fmt("%.0f auth failed in %s", result[“http.auth_errors.victim”]$sum, auth_errors_interval),
$src=key$host,
$n=to_count(fmt("%.0f", result[“http.auth_errors.victim”]$sum))
]);
}]);
}

Make sure we have all the http info before looking for auth errors

event http_message_done(c: connection, is_orig: bool, stat: http_message_stat)
{

only conns we want

local ports_ext: set[port] = { 80/tcp };
local ports_int: set[port] = { 80/tcp, 81/tcp, 443/tcp };

if (c$id$resp_h in ignore_host_resp)
return;
if (c$id$orig_h in ignore_host_orig)
return;

if (((c$id$resp_h in internal_space) && (c$id$resp_p in ports_int)) || ((c$id$resp_h in public_space) && (c$id$resp_p in ports_ext))) {

if (c$http?$username && c$http?$status_code) {
local auth_success : bool = T;
if (c$http$status_code == 401) {
auth_success = F;
add c$http$tags[HTTP_AUTH_ERROR];
}
else if (c$http$status_code < 400) {
auth_success = T;
add c$http$tags[HTTP_AUTH_SUCCESS];
}
if(!auth_success) {
SumStats::observe(“http.auth_errors.attacker”,
[$host=to_addr(c$http$cluster_client_ip)],
[]);
if ( c?$conn )
SumStats::observe(“http.auth_errors.victim”,
[$host=c$conn$id$resp_h],
[]);
}
}
}
}

https://github.com/michalpurzynski/bro-gramming/blob/ae37c0d6bfc62e25a797426d6791cf340b045d17/auth_bruteforcing.bro

cluster_client_ip is the user defined field, http record doesn’t have any field name “cluster_client_ip”.

I think what you want is c$http$id$orig_h , if that’s what the purpose of cluster_client_ip is.
Also your host is “string” type, you can change it to “addr” type:

Might wanna try something like:

type Info: record {

host: addr &log &optional;

};

SumStats::observe(“http.auth_errors.attacker”,
[$host=c$http$id$orig_h],
[]);

Also, not sure how this part is working(As c doesn’t have “conn” field as well.):

if ( c?$conn )
SumStats::observe(“http.auth_errors.victim”,
[$host=c$conn$id$resp_h],
[]);

i cleared using below code

if( c$http?$cluster_client_ip )

thanks

if( c$http?$cluster_client_ip )
Though, I wonder if this condition is ever going to result in true…