Notice and Sumstats and how to whitelist IPs

Hello everyone,

I can’t seem to figure out how to break out of scripts that trigger notices based on a sumstats function. I have a few Exfiltration scripts and my network scanner triggers many alerts. I only encounter this problem when sumstats is involved.

@load base/frameworks/sumstats

@load base/frameworks/notice

module Exfiltration;

export {

redef enum Notice::Type += {

notice::icmp_data_exfil,

};

const frequent_icmp_senders: set[subnet] {192.168.0.1/32} &redef;

const icmp_interval = 2min &redef;

const icmp_per_query_interval = 120.0 &redef;

}

function check_icmp(c:connection)

{

if (c$id$orig_h in frequent_icmp_senders) return;

if (c$id$resp_h in frequent_icmp_senders) return;

SumStats::observe(“Messages”,

SumStats::Key($host=c$id$orig_h),

SumStats::Observation($num=1));

}

event bro_init()

{

local messages_reducer = SumStats::Reducer($stream=“Messages”,

$apply=set(SumStats::SUM));

SumStats::create([$name = “messages”,

$epoch = icmp_interval,

$reducers = set(messages_reducer),

$threshold = icmp_per_query_interval,

$threshold_val(key: SumStats::Key, result: SumStats::Result) =

{

return result[“Messages”]$sum;

},

$threshold_crossed(key: SumStats::Key, result: SumStats::Result) =

{

local dur = icmp_interval;

NOTICE([$note=notice::icmp_data_exfil,

$src=key$host,

$msg=fmt("%s sent %s/%s ICMP messages in %s", key$host, result[“Messages”]$sum, icmp_per_query_interval, dur),

$sub=fmt(“Severity: 7”),

$suppress_for=10mins,

$identifier=cat(key$host)]);

}

]);

}

How do I get it to stop counting and not send a notice if an IP is in a white list?

Thanks!

That looks right to me.
If the orig or resp hosts are in frequent_icmp_senders observe() will never be called
and the connections will be effectively ignored.

This issue wouldn't have anything to do with sumstats.. if there is a problem it would be with the
logic in how observe() is called initially. It could be as simple as a typo of the IP in the frequent senders set.

Hey Justin,

I thought the same thing, but I rechecked the IP over and over again and it is correct. I’ve also added the whitelist to the script in many different ways, but still had no luck. I’ve been able to get this to work easily on all scripts that don’t load the sumstats framework. I’ve rewritten the scripts multiple times, tested them out in try.bro.org and my tool and nothing has worked to stop the notices. I’ve tried to break and return in functions and events, but that didn’t work.

I’ve even contacted our vendor for my tool who originally added some of the scripts and their head engineer has not been able to solve it yet. It seems to just keep continuing to keep track of the intervals and sends the data to the notice, even if the IP matches what’s in the white list. I’m no major bro scripting expert, but my vendors engineer is a well-known bro scripter, and if they had no luck, my chances are slim.

It seems that it should be as easy as returning on any matching IP, but I guess not. I don’t know what I’m missing, and I’m running out of ideas.

If you have any questions, please let me know.

Thank you for looking at my post!

image001.png

Hard to tell what is wrong without seeing the scripts.

As you say it IS as easy as returning early from a function when an IP matches.

If you can share the complete script that is not working properly I can help you fix it :slight_smile:

No problem at all. Here is the complete script. If you need one, I’ll work getting you a pcap to run it against.

Thank you Justin!

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

module Exfiltration;

export {
redef enum Notice::Type += {
notice::icmp_data_exfil,
};

const frequent_icmp_senders: set[subnet] {192.168.0.1/32} &redef;
const icmp_interval = 2min &redef;
const icmp_per_query_interval = 120.0 &redef;
}

function check_icmp(c:connection)
{
if (c$id$orig_h in frequent_icmp_senders) return;
if (c$id$resp_h in frequent_icmp_senders) return;
if (c$id$orig_h !in Site::local_nets) return;
if (c$id$resp_h in Site::local_nets) return;

SumStats::observe(“Messages”,
SumStats::Key($host=c$id$orig_h),
SumStats::Observation($num=1));

}

event bro_init()
{
local messages_reducer = SumStats::Reducer($stream=“Messages”,
$apply=set(SumStats::SUM));

SumStats::create([$name = “messages”,
$epoch = icmp_interval,
$reducers = set(messages_reducer),
$threshold = icmp_per_query_interval,
$threshold_val(key: SumStats::Key, result: SumStats::Result) =
{
return result[“Messages”]$sum;
},
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
{
local dur = icmp_interval;
NOTICE([$note=notice::icmp_data_exfil,
$src=key$host,
$msg=fmt("%s sent %s/%s ICMP messages in %s", key$host, result[“Messages”]$sum, icmp_per_query_interval, dur),
$sub=fmt(“Severity: 7”),
$suppress_for=10mins,
$identifier=cat(key$host)]);
}
]);
}

Huh.. well nothing calls this check_icmp function you have there so that script does nothing at all.

This looks like a "The princess is in another castle" kind of thing.

Is something else calling

    SumStats::observe("Messages", ...

Normally the stream name you use would be named something like "http.sqli.attacker" or "ftp.failed_auth" or in your case "icmp.exfil.connection"

If you are just using "Messages", and using that same stream in more than one script, that
would explain why you are seeing a lot unexplained notices.

Hey Justin,

It looks like half the script is being removed every time I send it. Here is the other half.

event bro_init()

{

local messages_reducer = SumStats::Reducer($stream=“Messages”,

$apply=set(SumStats::SUM));

SumStats::create([$name = “messages”,

$epoch = icmp_interval,

$reducers = set(messages_reducer),

$threshold = icmp_per_query_interval,

$threshold_val(key: SumStats::Key, result: SumStats::Result) =

{

return result[“Messages”]$sum;

},

$threshold_crossed(key: SumStats::Key, result: SumStats::Result) =

{

print key;

local dur = icmp_interval;

NOTICE([$note=notice::icmp_data_exfil,

$src=key$host,

$msg=fmt("%s sent %s/%s ICMP messages in %s", key$host, result[“Messages”]$sum, icmp_per_query_interval, dur),

$sub=fmt(“Severity: 7”),

$suppress_for=10mins,

$identifier=cat(key$host)]);

}

]);

}

image001.png

No.. I got that part.

By itself, the script that you posted does not do anything.

That check_icmp function is never called and may as well not exist, that's why nothing you put in there is
changing the result.

You have another script that is also calling

    SumStats::observe("Messages",...)

which is what is causing all the confusion. You should not use "Messages" as the stream name, and you should absolutely not
use the same stream name in two different unrelated scripts.

I see. I forgot to add the ICMP event. I don’t know about the SumStats::observe(“Messages”). I’ll have to check on that.

Thank you very much for your help Justin!!

Dillon Murphy