mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Merge remote-tracking branch 'origin/master' into fastpath
This commit is contained in:
commit
d14349a6f8
150 changed files with 4528 additions and 1114 deletions
|
@ -2,6 +2,7 @@ include(InstallPackageConfigFile)
|
|||
|
||||
install(DIRECTORY ./ DESTINATION ${BRO_SCRIPT_INSTALL_PATH} FILES_MATCHING
|
||||
PATTERN "site/local*" EXCLUDE
|
||||
PATTERN "test-all-policy.bro" EXCLUDE
|
||||
PATTERN "*.bro"
|
||||
PATTERN "*.sig"
|
||||
PATTERN "*.fp"
|
||||
|
|
|
@ -14,8 +14,8 @@ export {
|
|||
## Which port to listen on.
|
||||
const listen_port = 47757/tcp &redef;
|
||||
|
||||
## This defines if a listening socket should use encryption.
|
||||
const listen_encrypted = F &redef;
|
||||
## This defines if a listening socket should use SSL.
|
||||
const listen_ssl = F &redef;
|
||||
|
||||
## Default compression level. Compression level is 0-9, with 0 = no
|
||||
## compression.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
@load ./actions/page
|
||||
@load ./actions/add-geodata
|
||||
|
||||
# There shouldn't be any defaul toverhead from loading these since they
|
||||
# There shouldn't be any default overhead from loading these since they
|
||||
# *should* only do anything when notices have the ACTION_EMAIL action applied.
|
||||
@load ./extend-email/hostnames
|
||||
|
||||
|
@ -18,3 +18,6 @@
|
|||
@if ( Cluster::is_enabled() )
|
||||
@load ./cluster
|
||||
@endif
|
||||
|
||||
# Load here so that it can check whether clustering is enabled.
|
||||
@load ./actions/pp-alarms
|
||||
|
|
233
scripts/base/frameworks/notice/actions/pp-alarms.bro
Normal file
233
scripts/base/frameworks/notice/actions/pp-alarms.bro
Normal file
|
@ -0,0 +1,233 @@
|
|||
#! Notice extension that mails out a pretty-printed version of alarm.log
|
||||
#! in regular intervals, formatted for better human readability. If activated,
|
||||
#! that replaces the default summary mail having the raw log output.
|
||||
|
||||
@load base/frameworks/cluster
|
||||
@load ../main
|
||||
|
||||
module Notice;
|
||||
|
||||
export {
|
||||
## Activate pretty-printed alarm summaries.
|
||||
const pretty_print_alarms = T &redef;
|
||||
|
||||
## Address to send the pretty-printed reports to. Default if not set is
|
||||
## :bro:id:`Notice::mail_dest`.
|
||||
const mail_dest_pretty_printed = "" &redef;
|
||||
|
||||
## If an address from one of these networks is reported, we mark
|
||||
## the entry with an addition quote symbol (i.e., ">"). Many MUAs
|
||||
## then highlight such lines differently.
|
||||
global flag_nets: set[subnet] &redef;
|
||||
|
||||
## Function that renders a single alarm. Can be overidden.
|
||||
global pretty_print_alarm: function(out: file, n: Info) &redef;
|
||||
}
|
||||
|
||||
# We maintain an old-style file recording the pretty-printed alarms.
|
||||
const pp_alarms_name = "alarm-mail.txt";
|
||||
global pp_alarms: file;
|
||||
global pp_alarms_open: bool = F;
|
||||
|
||||
# Returns True if pretty-printed alarm summaries are activated.
|
||||
function want_pp() : bool
|
||||
{
|
||||
return (pretty_print_alarms && ! reading_traces()
|
||||
&& (mail_dest != "" || mail_dest_pretty_printed != ""));
|
||||
}
|
||||
|
||||
# Opens and intializes the output file.
|
||||
function pp_open()
|
||||
{
|
||||
if ( pp_alarms_open )
|
||||
return;
|
||||
|
||||
pp_alarms_open = T;
|
||||
pp_alarms = open(pp_alarms_name);
|
||||
|
||||
local dest = mail_dest_pretty_printed != "" ? mail_dest_pretty_printed
|
||||
: mail_dest;
|
||||
|
||||
local headers = email_headers("Alarm summary", dest);
|
||||
write_file(pp_alarms, headers + "\n");
|
||||
}
|
||||
|
||||
# Closes and mails out the current output file.
|
||||
function pp_send()
|
||||
{
|
||||
if ( ! pp_alarms_open )
|
||||
return;
|
||||
|
||||
write_file(pp_alarms, "\n\n--\n[Automatically generated]\n\n");
|
||||
close(pp_alarms);
|
||||
|
||||
system(fmt("/bin/cat %s | %s -t -oi && /bin/rm %s",
|
||||
pp_alarms_name, sendmail, pp_alarms_name));
|
||||
|
||||
pp_alarms_open = F;
|
||||
}
|
||||
|
||||
# Postprocessor function that triggers the email.
|
||||
function pp_postprocessor(info: Log::RotationInfo): bool
|
||||
{
|
||||
if ( want_pp() )
|
||||
pp_send();
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
if ( ! want_pp() )
|
||||
return;
|
||||
|
||||
# This replaces the standard non-pretty-printing filter.
|
||||
Log::add_filter(Notice::ALARM_LOG,
|
||||
[$name="alarm-mail", $writer=Log::WRITER_NONE,
|
||||
$interv=Log::default_rotation_interval,
|
||||
$postprocessor=pp_postprocessor]);
|
||||
}
|
||||
|
||||
event notice(n: Notice::Info) &priority=-5
|
||||
{
|
||||
if ( ! want_pp() )
|
||||
return;
|
||||
|
||||
if ( ACTION_LOG !in n$actions )
|
||||
return;
|
||||
|
||||
if ( ! pp_alarms_open )
|
||||
pp_open();
|
||||
|
||||
pretty_print_alarm(pp_alarms, n);
|
||||
}
|
||||
|
||||
function do_msg(out: file, n: Info, line1: string, line2: string, line3: string, host1: addr, name1: string, host2: addr, name2: string)
|
||||
{
|
||||
local country = "";
|
||||
@ifdef ( Notice::ACTION_ADD_GEODATA ) # Make tests happy, cyclic dependency.
|
||||
if ( n?$remote_location && n$remote_location?$country_code )
|
||||
country = fmt(" (remote location %s)", n$remote_location$country_code);
|
||||
@endif
|
||||
|
||||
line1 = cat(line1, country);
|
||||
|
||||
local resolved = "";
|
||||
|
||||
if ( host1 != 0.0.0.0 )
|
||||
resolved = fmt("%s # %s = %s", resolved, host1, name1);
|
||||
|
||||
if ( host2 != 0.0.0.0 )
|
||||
resolved = fmt("%s %s = %s", resolved, host2, name2);
|
||||
|
||||
print out, line1;
|
||||
print out, line2;
|
||||
if ( line3 != "" )
|
||||
print out, line3;
|
||||
if ( resolved != "" )
|
||||
print out, resolved;
|
||||
print out, "";
|
||||
}
|
||||
|
||||
# Default pretty-printer.
|
||||
function pretty_print_alarm(out: file, n: Info)
|
||||
{
|
||||
local pdescr = "";
|
||||
|
||||
@if ( Cluster::is_enabled() )
|
||||
pdescr = "local";
|
||||
|
||||
if ( n?$src_peer )
|
||||
pdescr = n$src_peer?$descr ? n$src_peer$descr : fmt("%s", n$src_peer$host);
|
||||
|
||||
pdescr = fmt("<%s> ", pdescr);
|
||||
@endif
|
||||
|
||||
local msg = fmt( "%s%s", pdescr, n$msg);
|
||||
|
||||
local who = "";
|
||||
local h1 = 0.0.0.0;
|
||||
local h2 = 0.0.0.0;
|
||||
|
||||
local orig_p = "";
|
||||
local resp_p = "";
|
||||
|
||||
if ( n?$id )
|
||||
{
|
||||
orig_p = fmt(":%s", n$id$orig_p);
|
||||
resp_p = fmt(":%s", n$id$resp_p);
|
||||
}
|
||||
|
||||
if ( n?$src && n?$dst )
|
||||
{
|
||||
h1 = n$src;
|
||||
h2 = n$dst;
|
||||
who = fmt("%s%s -> %s%s", h1, orig_p, h2, resp_p);
|
||||
|
||||
if ( n?$uid )
|
||||
who = fmt("%s (uid %s)", who, n$uid );
|
||||
}
|
||||
|
||||
else if ( n?$src )
|
||||
{
|
||||
local p = "";
|
||||
|
||||
if ( n?$p )
|
||||
p = fmt(":%s", n$p);
|
||||
|
||||
h1 = n$src;
|
||||
who = fmt("%s%s", h1, p);
|
||||
}
|
||||
|
||||
local flag = (h1 in flag_nets || h2 in flag_nets);
|
||||
|
||||
local line1 = fmt(">%s %D %s %s", (flag ? ">" : " "), network_time(), n$note, who);
|
||||
local line2 = fmt(" %s", msg);
|
||||
local line3 = n?$sub ? fmt(" %s", n$sub) : "";
|
||||
|
||||
if ( h1 == 0.0.0.0 )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, "", h2, "");
|
||||
return;
|
||||
}
|
||||
|
||||
when ( local h1name = lookup_addr(h1) )
|
||||
{
|
||||
if ( h2 == 0.0.0.0 )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, h1name, h2, "");
|
||||
return;
|
||||
}
|
||||
|
||||
when ( local h2name = lookup_addr(h2) )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, h1name, h2, h2name);
|
||||
return;
|
||||
}
|
||||
timeout 5secs
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, h1name, h2, "(dns timeout)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
timeout 5secs
|
||||
{
|
||||
if ( h2 == 0.0.0.0 )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, "(dns timeout)", h2, "");
|
||||
return;
|
||||
}
|
||||
|
||||
when ( local h2name_ = lookup_addr(h2) )
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, "(dns timeout)", h2, h2name_);
|
||||
return;
|
||||
}
|
||||
timeout 5secs
|
||||
{
|
||||
do_msg(out, n, line1, line2, line3, h1, "(dns timeout)", h2, "(dns timeout)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,25 +17,16 @@ event Notice::notice(n: Notice::Info) &priority=10
|
|||
{
|
||||
when ( local src_name = lookup_addr(n$src) )
|
||||
{
|
||||
output = cat(output, "orig_h/src: ", src_name, "\n");
|
||||
}
|
||||
timeout 5secs
|
||||
{
|
||||
output = cat(output, "orig_h/src: <timeout>\n");
|
||||
output = string_cat("orig_h/src hostname: ", src_name, "\n");
|
||||
n$email_body_sections[|n$email_body_sections|] = output;
|
||||
}
|
||||
}
|
||||
if ( n?$dst )
|
||||
{
|
||||
when ( local dst_name = lookup_addr(n$dst) )
|
||||
{
|
||||
output = cat(output, "resp_h/dst: ", dst_name, "\n");
|
||||
}
|
||||
timeout 5secs
|
||||
{
|
||||
output = cat(output, "resp_h/dst: <timeout>\n");
|
||||
output = string_cat("resp_h/dst hostname: ", dst_name, "\n");
|
||||
n$email_body_sections[|n$email_body_sections|] = output;
|
||||
}
|
||||
}
|
||||
|
||||
if ( output != "" )
|
||||
n$email_body_sections[|n$email_body_sections|] = output;
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ export {
|
|||
## from highest value (10) to lowest value (0).
|
||||
priority: count &log &default=5;
|
||||
## An action given to the notice if the predicate return true.
|
||||
result: Notice::Action &log &default=ACTION_NONE;
|
||||
action: Notice::Action &log &default=ACTION_NONE;
|
||||
## The pred (predicate) field is a function that returns a boolean T
|
||||
## or F value. If the predicate function return true, the action in
|
||||
## this record is applied to the notice that is given as an argument
|
||||
|
@ -169,25 +169,25 @@ export {
|
|||
[$pred(n: Notice::Info) = { return (n$note in Notice::ignored_types); },
|
||||
$halt=T, $priority = 9],
|
||||
[$pred(n: Notice::Info) = { return (n$note in Notice::not_suppressed_types); },
|
||||
$result = ACTION_NO_SUPPRESS,
|
||||
$action = ACTION_NO_SUPPRESS,
|
||||
$priority = 9],
|
||||
[$pred(n: Notice::Info) = { return (n$note in Notice::alarmed_types); },
|
||||
$result = ACTION_ALARM,
|
||||
$action = ACTION_ALARM,
|
||||
$priority = 8],
|
||||
[$pred(n: Notice::Info) = { return (n$note in Notice::emailed_types); },
|
||||
$result = ACTION_EMAIL,
|
||||
$action = ACTION_EMAIL,
|
||||
$priority = 8],
|
||||
[$pred(n: Notice::Info) = {
|
||||
if (n$note in Notice::type_suppression_intervals)
|
||||
if (n$note in Notice::type_suppression_intervals)
|
||||
{
|
||||
n$suppress_for=Notice::type_suppression_intervals[n$note];
|
||||
n$suppress_for=Notice::type_suppression_intervals[n$note];
|
||||
return T;
|
||||
}
|
||||
return F;
|
||||
return F;
|
||||
},
|
||||
$result = ACTION_NONE,
|
||||
$action = ACTION_NONE,
|
||||
$priority = 8],
|
||||
[$result = ACTION_LOG,
|
||||
[$action = ACTION_LOG,
|
||||
$priority = 0],
|
||||
} &redef;
|
||||
|
||||
|
@ -353,9 +353,26 @@ function email_notice_to(n: Notice::Info, dest: string, extend: bool)
|
|||
return;
|
||||
|
||||
local email_text = email_headers(fmt("%s", n$note), dest);
|
||||
|
||||
# First off, finish the headers and include the human readable messages
|
||||
# then leave a blank line after the message.
|
||||
email_text = string_cat(email_text, "\nMessage: ", n$msg);
|
||||
if ( n?$sub )
|
||||
email_text = string_cat(email_text, "\nSub-message: ", n$sub);
|
||||
|
||||
# The notice emails always start off with the human readable message.
|
||||
email_text = string_cat(email_text, "\n", n$msg, "\n");
|
||||
email_text = string_cat(email_text, "\n\n");
|
||||
|
||||
# Next, add information about the connection if it exists.
|
||||
if ( n?$id )
|
||||
{
|
||||
email_text = string_cat(email_text, "Connection: ",
|
||||
fmt("%s", n$id$orig_h), ":", fmt("%d", n$id$orig_p), " -> ",
|
||||
fmt("%s", n$id$resp_h), ":", fmt("%d", n$id$resp_p), "\n");
|
||||
if ( n?$uid )
|
||||
email_text = string_cat(email_text, "Connection uid: ", n$uid, "\n");
|
||||
}
|
||||
else if ( n?$src )
|
||||
email_text = string_cat(email_text, "Address: ", fmt("%s", n$src), "\n");
|
||||
|
||||
# Add the extended information if it's requested.
|
||||
if ( extend )
|
||||
|
@ -466,7 +483,7 @@ function apply_policy(n: Notice::Info)
|
|||
# If there's no predicate or the predicate returns F.
|
||||
if ( ! ordered_policy[i]?$pred || ordered_policy[i]$pred(n) )
|
||||
{
|
||||
add n$actions[ordered_policy[i]$result];
|
||||
add n$actions[ordered_policy[i]$action];
|
||||
add n$policy_items[int_to_count(i)];
|
||||
|
||||
# If the predicate matched and there was a suppression interval,
|
||||
|
|
|
@ -8,223 +8,212 @@ export {
|
|||
redef enum Log::ID += { LOG };
|
||||
|
||||
redef enum Notice::Type += {
|
||||
## Generic unusual but alarm-worthy activity.
|
||||
Weird_Activity,
|
||||
## Generic unusual but notice-worthy weird activity.
|
||||
Activity,
|
||||
};
|
||||
|
||||
type Info: record {
|
||||
## The time when the weird occurred.
|
||||
ts: time &log;
|
||||
## If a connection is associated with this weird, this will be the
|
||||
## connection's unique ID.
|
||||
uid: string &log &optional;
|
||||
## conn_id for the optional connection.
|
||||
id: conn_id &log &optional;
|
||||
msg: string &log;
|
||||
## The name of the weird that occurred.
|
||||
name: string &log;
|
||||
## Additional information accompanying the weird if any.
|
||||
addl: string &log &optional;
|
||||
## Indicate if this weird was also turned into a notice.
|
||||
notice: bool &log &default=F;
|
||||
## The peer that originated this weird. This is helpful in cluster
|
||||
## deployments if a particular cluster node is having trouble to help
|
||||
## identify which node is having trouble.
|
||||
peer: string &log &optional;
|
||||
};
|
||||
|
||||
type WeirdAction: enum {
|
||||
WEIRD_UNSPECIFIED, WEIRD_IGNORE, WEIRD_FILE,
|
||||
WEIRD_NOTICE_ALWAYS, WEIRD_NOTICE_PER_CONN,
|
||||
WEIRD_NOTICE_PER_ORIG, WEIRD_NOTICE_ONCE,
|
||||
type Action: enum {
|
||||
ACTION_UNSPECIFIED,
|
||||
ACTION_IGNORE,
|
||||
ACTION_LOG,
|
||||
ACTION_LOG_ONCE,
|
||||
ACTION_LOG_PER_CONN,
|
||||
ACTION_LOG_PER_ORIG,
|
||||
ACTION_NOTICE,
|
||||
ACTION_NOTICE_ONCE,
|
||||
ACTION_NOTICE_PER_CONN,
|
||||
ACTION_NOTICE_PER_ORIG,
|
||||
};
|
||||
|
||||
# Which of the above actions lead to logging. For internal use.
|
||||
const notice_actions = {
|
||||
WEIRD_NOTICE_ALWAYS, WEIRD_NOTICE_PER_CONN,
|
||||
WEIRD_NOTICE_PER_ORIG, WEIRD_NOTICE_ONCE,
|
||||
};
|
||||
const actions: table[string] of Action = {
|
||||
["unsolicited_SYN_response"] = ACTION_IGNORE,
|
||||
["above_hole_data_without_any_acks"] = ACTION_LOG,
|
||||
["active_connection_reuse"] = ACTION_LOG,
|
||||
["bad_HTTP_reply"] = ACTION_LOG,
|
||||
["bad_HTTP_version"] = ACTION_LOG,
|
||||
["bad_ICMP_checksum"] = ACTION_LOG_PER_ORIG,
|
||||
["bad_ident_port"] = ACTION_LOG,
|
||||
["bad_ident_reply"] = ACTION_LOG,
|
||||
["bad_ident_request"] = ACTION_LOG,
|
||||
["bad_rlogin_prolog"] = ACTION_LOG,
|
||||
["bad_rsh_prolog"] = ACTION_LOG,
|
||||
["rsh_text_after_rejected"] = ACTION_LOG,
|
||||
["bad_RPC"] = ACTION_LOG_PER_ORIG,
|
||||
["bad_RPC_program"] = ACTION_LOG,
|
||||
["bad_SYN_ack"] = ACTION_LOG,
|
||||
["bad_TCP_checksum"] = ACTION_LOG_PER_ORIG,
|
||||
["bad_UDP_checksum"] = ACTION_LOG_PER_ORIG,
|
||||
["baroque_SYN"] = ACTION_LOG,
|
||||
["base64_illegal_encoding"] = ACTION_LOG,
|
||||
["connection_originator_SYN_ack"] = ACTION_LOG_PER_ORIG,
|
||||
["corrupt_tcp_options"] = ACTION_LOG_PER_ORIG,
|
||||
["crud_trailing_HTTP_request"] = ACTION_LOG,
|
||||
["data_after_reset"] = ACTION_LOG,
|
||||
["data_before_established"] = ACTION_LOG,
|
||||
["data_without_SYN_ACK"] = ACTION_LOG,
|
||||
["DHCP_no_type_option"] = ACTION_LOG,
|
||||
["DHCP_wrong_msg_type"] = ACTION_LOG,
|
||||
["DHCP_wrong_op_type"] = ACTION_LOG,
|
||||
["DNS_AAAA_neg_length"] = ACTION_LOG,
|
||||
["DNS_Conn_count_too_large"] = ACTION_LOG,
|
||||
["DNS_NAME_too_long"] = ACTION_LOG,
|
||||
["DNS_RR_bad_length"] = ACTION_LOG,
|
||||
["DNS_RR_length_mismatch"] = ACTION_LOG,
|
||||
["DNS_RR_unknown_type"] = ACTION_LOG,
|
||||
["DNS_label_forward_compress_offset"] = ACTION_LOG_PER_ORIG,
|
||||
["DNS_label_len_gt_name_len"] = ACTION_LOG_PER_ORIG,
|
||||
["DNS_label_len_gt_pkt"] = ACTION_LOG_PER_ORIG,
|
||||
["DNS_label_too_long"] = ACTION_LOG_PER_ORIG,
|
||||
["DNS_truncated_RR_rdlength_lt_len"] = ACTION_LOG,
|
||||
["DNS_truncated_ans_too_short"] = ACTION_LOG,
|
||||
["DNS_truncated_len_lt_hdr_len"] = ACTION_LOG,
|
||||
["DNS_truncated_quest_too_short"] = ACTION_LOG,
|
||||
["dns_changed_number_of_responses"] = ACTION_LOG_PER_ORIG,
|
||||
["dns_reply_seen_after_done"] = ACTION_LOG_PER_ORIG,
|
||||
["excessive_data_without_further_acks"] = ACTION_LOG,
|
||||
["excess_RPC"] = ACTION_LOG_PER_ORIG,
|
||||
["excessive_RPC_len"] = ACTION_LOG_PER_ORIG,
|
||||
["FIN_advanced_last_seq"] = ACTION_LOG,
|
||||
["FIN_after_reset"] = ACTION_IGNORE,
|
||||
["FIN_storm"] = ACTION_NOTICE_PER_ORIG,
|
||||
["HTTP_bad_chunk_size"] = ACTION_LOG,
|
||||
["HTTP_chunked_transfer_for_multipart_message"] = ACTION_LOG,
|
||||
["HTTP_overlapping_messages"] = ACTION_LOG,
|
||||
["HTTP_unknown_method"] = ACTION_LOG,
|
||||
["HTTP_version_mismatch"] = ACTION_LOG,
|
||||
["ident_request_addendum"] = ACTION_LOG,
|
||||
["inappropriate_FIN"] = ACTION_LOG,
|
||||
["inflate_failed"] = ACTION_LOG,
|
||||
["invalid_irc_global_users_reply"] = ACTION_LOG,
|
||||
["irc_invalid_command"] = ACTION_LOG,
|
||||
["irc_invalid_dcc_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_invite_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_join_line"] = ACTION_LOG,
|
||||
["irc_invalid_kick_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_line"] = ACTION_LOG,
|
||||
["irc_invalid_mode_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_names_line"] = ACTION_LOG,
|
||||
["irc_invalid_njoin_line"] = ACTION_LOG,
|
||||
["irc_invalid_notice_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_oper_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_privmsg_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_reply_number"] = ACTION_LOG,
|
||||
["irc_invalid_squery_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_topic_reply"] = ACTION_LOG,
|
||||
["irc_invalid_who_line"] = ACTION_LOG,
|
||||
["irc_invalid_who_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_whois_channel_line"] = ACTION_LOG,
|
||||
["irc_invalid_whois_message_format"] = ACTION_LOG,
|
||||
["irc_invalid_whois_operator_line"] = ACTION_LOG,
|
||||
["irc_invalid_whois_user_line"] = ACTION_LOG,
|
||||
["irc_line_size_exceeded"] = ACTION_LOG,
|
||||
["irc_line_too_short"] = ACTION_LOG,
|
||||
["irc_too_many_invalid"] = ACTION_LOG,
|
||||
["line_terminated_with_single_CR"] = ACTION_LOG,
|
||||
["line_terminated_with_single_LF"] = ACTION_LOG,
|
||||
["malformed_ssh_identification"] = ACTION_LOG,
|
||||
["malformed_ssh_version"] = ACTION_LOG,
|
||||
["matching_undelivered_data"] = ACTION_LOG,
|
||||
["multiple_HTTP_request_elements"] = ACTION_LOG,
|
||||
["multiple_RPCs"] = ACTION_LOG_PER_ORIG,
|
||||
["non_IPv4_packet"] = ACTION_LOG_ONCE,
|
||||
["NUL_in_line"] = ACTION_LOG,
|
||||
["originator_RPC_reply"] = ACTION_LOG_PER_ORIG,
|
||||
["partial_finger_request"] = ACTION_LOG,
|
||||
["partial_ftp_request"] = ACTION_LOG,
|
||||
["partial_ident_request"] = ACTION_LOG,
|
||||
["partial_RPC"] = ACTION_LOG_PER_ORIG,
|
||||
["partial_RPC_request"] = ACTION_LOG,
|
||||
["pending_data_when_closed"] = ACTION_LOG,
|
||||
["pop3_bad_base64_encoding"] = ACTION_LOG,
|
||||
["pop3_client_command_unknown"] = ACTION_LOG,
|
||||
["pop3_client_sending_server_commands"] = ACTION_LOG,
|
||||
["pop3_malformed_auth_plain"] = ACTION_LOG,
|
||||
["pop3_server_command_unknown"] = ACTION_LOG,
|
||||
["pop3_server_sending_client_commands"] = ACTION_LOG,
|
||||
["possible_split_routing"] = ACTION_LOG,
|
||||
["premature_connection_reuse"] = ACTION_LOG,
|
||||
["repeated_SYN_reply_wo_ack"] = ACTION_LOG,
|
||||
["repeated_SYN_with_ack"] = ACTION_LOG,
|
||||
["responder_RPC_call"] = ACTION_LOG_PER_ORIG,
|
||||
["rlogin_text_after_rejected"] = ACTION_LOG,
|
||||
["RPC_rexmit_inconsistency"] = ACTION_LOG,
|
||||
["RPC_underflow"] = ACTION_LOG,
|
||||
["RST_storm"] = ACTION_LOG,
|
||||
["RST_with_data"] = ACTION_LOG,
|
||||
["simultaneous_open"] = ACTION_LOG_PER_CONN,
|
||||
["spontaneous_FIN"] = ACTION_IGNORE,
|
||||
["spontaneous_RST"] = ACTION_IGNORE,
|
||||
["SMB_parsing_error"] = ACTION_LOG,
|
||||
["no_smb_session_using_parsesambamsg"] = ACTION_LOG,
|
||||
["smb_andx_command_failed_to_parse"] = ACTION_LOG,
|
||||
["transaction_subcmd_missing"] = ACTION_LOG,
|
||||
["successful_RPC_reply_to_invalid_request"] = ACTION_NOTICE_PER_ORIG,
|
||||
["SYN_after_close"] = ACTION_LOG,
|
||||
["SYN_after_partial"] = ACTION_NOTICE_PER_ORIG,
|
||||
["SYN_after_reset"] = ACTION_LOG,
|
||||
["SYN_inside_connection"] = ACTION_LOG,
|
||||
["SYN_seq_jump"] = ACTION_LOG,
|
||||
["SYN_with_data"] = ACTION_LOG,
|
||||
["TCP_christmas"] = ACTION_LOG,
|
||||
["truncated_ARP"] = ACTION_LOG,
|
||||
["truncated_NTP"] = ACTION_LOG,
|
||||
["UDP_datagram_length_mismatch"] = ACTION_LOG_PER_ORIG,
|
||||
["unexpected_client_HTTP_data"] = ACTION_LOG,
|
||||
["unexpected_multiple_HTTP_requests"] = ACTION_LOG,
|
||||
["unexpected_server_HTTP_data"] = ACTION_LOG,
|
||||
["unmatched_HTTP_reply"] = ACTION_LOG,
|
||||
["unpaired_RPC_response"] = ACTION_LOG,
|
||||
["window_recision"] = ACTION_LOG,
|
||||
["double_%_in_URI"] = ACTION_LOG,
|
||||
["illegal_%_at_end_of_URI"] = ACTION_LOG,
|
||||
["unescaped_%_in_URI"] = ACTION_LOG,
|
||||
["unescaped_special_URI_char"] = ACTION_LOG,
|
||||
["deficit_netbios_hdr_len"] = ACTION_LOG,
|
||||
["excess_netbios_hdr_len"] = ACTION_LOG,
|
||||
["netbios_client_session_reply"] = ACTION_LOG,
|
||||
["netbios_raw_session_msg"] = ACTION_LOG,
|
||||
["netbios_server_session_request"] = ACTION_LOG,
|
||||
["unknown_netbios_type"] = ACTION_LOG,
|
||||
["excessively_large_fragment"] = ACTION_LOG,
|
||||
["excessively_small_fragment"] = ACTION_LOG_PER_ORIG,
|
||||
["fragment_inconsistency"] = ACTION_LOG_PER_ORIG,
|
||||
["fragment_overlap"] = ACTION_LOG_PER_ORIG,
|
||||
["fragment_protocol_inconsistency"] = ACTION_LOG,
|
||||
["fragment_size_inconsistency"] = ACTION_LOG_PER_ORIG,
|
||||
## These do indeed happen!
|
||||
["fragment_with_DF"] = ACTION_LOG,
|
||||
["incompletely_captured_fragment"] = ACTION_LOG,
|
||||
["bad_IP_checksum"] = ACTION_LOG_PER_ORIG,
|
||||
["bad_TCP_header_len"] = ACTION_LOG,
|
||||
["internally_truncated_header"] = ACTION_LOG,
|
||||
["truncated_IP"] = ACTION_LOG,
|
||||
["truncated_header"] = ACTION_LOG,
|
||||
} &default=ACTION_LOG &redef;
|
||||
|
||||
const weird_action: table[string] of WeirdAction = {
|
||||
# tcp_weird
|
||||
["above_hole_data_without_any_acks"] = WEIRD_FILE,
|
||||
["active_connection_reuse"] = WEIRD_FILE,
|
||||
["bad_HTTP_reply"] = WEIRD_FILE,
|
||||
["bad_HTTP_version"] = WEIRD_FILE,
|
||||
["bad_ICMP_checksum"] = WEIRD_FILE,
|
||||
["bad_ident_port"] = WEIRD_FILE,
|
||||
["bad_ident_reply"] = WEIRD_FILE,
|
||||
["bad_ident_request"] = WEIRD_FILE,
|
||||
["bad_rlogin_prolog"] = WEIRD_FILE,
|
||||
["bad_rsh_prolog"] = WEIRD_FILE,
|
||||
["rsh_text_after_rejected"] = WEIRD_FILE,
|
||||
["bad_RPC"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["bad_RPC_program"] = WEIRD_FILE,
|
||||
["bad_SYN_ack"] = WEIRD_FILE,
|
||||
["bad_TCP_checksum"] = WEIRD_FILE,
|
||||
["bad_UDP_checksum"] = WEIRD_FILE,
|
||||
["baroque_SYN"] = WEIRD_FILE,
|
||||
["base64_illegal_encoding"] = WEIRD_FILE,
|
||||
["connection_originator_SYN_ack"] = WEIRD_FILE,
|
||||
["corrupt_tcp_options"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["crud_trailing_HTTP_request"] = WEIRD_FILE,
|
||||
["data_after_reset"] = WEIRD_FILE,
|
||||
["data_before_established"] = WEIRD_FILE,
|
||||
["data_without_SYN_ACK"] = WEIRD_FILE,
|
||||
["DHCP_no_type_option"] = WEIRD_FILE,
|
||||
["DHCP_wrong_msg_type"] = WEIRD_FILE,
|
||||
["DHCP_wrong_op_type"] = WEIRD_FILE,
|
||||
["DNS_AAAA_neg_length"] = WEIRD_FILE,
|
||||
["DNS_Conn_count_too_large"] = WEIRD_FILE,
|
||||
["DNS_NAME_too_long"] = WEIRD_FILE,
|
||||
["DNS_RR_bad_length"] = WEIRD_FILE,
|
||||
["DNS_RR_length_mismatch"] = WEIRD_FILE,
|
||||
["DNS_RR_unknown_type"] = WEIRD_FILE,
|
||||
["DNS_label_forward_compress_offset"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["DNS_label_len_gt_name_len"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["DNS_label_len_gt_pkt"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["DNS_label_too_long"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["DNS_truncated_RR_rdlength_lt_len"] = WEIRD_FILE,
|
||||
["DNS_truncated_ans_too_short"] = WEIRD_FILE,
|
||||
["DNS_truncated_len_lt_hdr_len"] = WEIRD_FILE,
|
||||
["DNS_truncated_quest_too_short"] = WEIRD_FILE,
|
||||
["dns_changed_number_of_responses"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["dns_reply_seen_after_done"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["excessive_data_without_further_acks"] = WEIRD_FILE,
|
||||
["excess_RPC"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["excessive_RPC_len"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["FIN_advanced_last_seq"] = WEIRD_FILE,
|
||||
["FIN_after_reset"] = WEIRD_IGNORE,
|
||||
["FIN_storm"] = WEIRD_NOTICE_ALWAYS,
|
||||
["HTTP_bad_chunk_size"] = WEIRD_FILE,
|
||||
["HTTP_chunked_transfer_for_multipart_message"] = WEIRD_FILE,
|
||||
["HTTP_overlapping_messages"] = WEIRD_FILE,
|
||||
["HTTP_unknown_method"] = WEIRD_FILE,
|
||||
["HTTP_version_mismatch"] = WEIRD_FILE,
|
||||
["ident_request_addendum"] = WEIRD_FILE,
|
||||
["inappropriate_FIN"] = WEIRD_FILE,
|
||||
["inflate_data_failed"] = WEIRD_FILE,
|
||||
["inflate_failed"] = WEIRD_FILE,
|
||||
["invalid_irc_global_users_reply"] = WEIRD_FILE,
|
||||
["irc_invalid_command"] = WEIRD_FILE,
|
||||
["irc_invalid_dcc_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_invite_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_join_line"] = WEIRD_FILE,
|
||||
["irc_invalid_kick_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_line"] = WEIRD_FILE,
|
||||
["irc_invalid_mode_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_names_line"] = WEIRD_FILE,
|
||||
["irc_invalid_njoin_line"] = WEIRD_FILE,
|
||||
["irc_invalid_notice_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_oper_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_privmsg_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_reply_number"] = WEIRD_FILE,
|
||||
["irc_invalid_squery_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_topic_reply"] = WEIRD_FILE,
|
||||
["irc_invalid_who_line"] = WEIRD_FILE,
|
||||
["irc_invalid_who_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_whois_channel_line"] = WEIRD_FILE,
|
||||
["irc_invalid_whois_message_format"] = WEIRD_FILE,
|
||||
["irc_invalid_whois_operator_line"] = WEIRD_FILE,
|
||||
["irc_invalid_whois_user_line"] = WEIRD_FILE,
|
||||
["irc_line_size_exceeded"] = WEIRD_FILE,
|
||||
["irc_line_too_short"] = WEIRD_FILE,
|
||||
["irc_too_many_invalid"] = WEIRD_FILE,
|
||||
["line_terminated_with_single_CR"] = WEIRD_FILE,
|
||||
["line_terminated_with_single_LF"] = WEIRD_FILE,
|
||||
["malformed_ssh_identification"] = WEIRD_FILE,
|
||||
["malformed_ssh_version"] = WEIRD_FILE,
|
||||
["matching_undelivered_data"] = WEIRD_FILE,
|
||||
["multiple_HTTP_request_elements"] = WEIRD_FILE,
|
||||
["multiple_RPCs"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["non_IPv4_packet"] = WEIRD_NOTICE_ONCE,
|
||||
["NUL_in_line"] = WEIRD_FILE,
|
||||
["originator_RPC_reply"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["partial_finger_request"] = WEIRD_FILE,
|
||||
["partial_ftp_request"] = WEIRD_FILE,
|
||||
["partial_ident_request"] = WEIRD_FILE,
|
||||
["partial_RPC"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["partial_RPC_request"] = WEIRD_FILE,
|
||||
["pending_data_when_closed"] = WEIRD_FILE,
|
||||
["pop3_bad_base64_encoding"] = WEIRD_FILE,
|
||||
["pop3_client_command_unknown"] = WEIRD_FILE,
|
||||
["pop3_client_sending_server_commands"] = WEIRD_FILE,
|
||||
["pop3_malformed_auth_plain"] = WEIRD_FILE,
|
||||
["pop3_server_command_unknown"] = WEIRD_FILE,
|
||||
["pop3_server_sending_client_commands"] = WEIRD_FILE,
|
||||
["possible_split_routing"] = WEIRD_FILE,
|
||||
["premature_connection_reuse"] = WEIRD_FILE,
|
||||
["repeated_SYN_reply_wo_ack"] = WEIRD_FILE,
|
||||
["repeated_SYN_with_ack"] = WEIRD_FILE,
|
||||
["responder_RPC_call"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["rlogin_text_after_rejected"] = WEIRD_FILE,
|
||||
["RPC_rexmit_inconsistency"] = WEIRD_FILE,
|
||||
["RPC_underflow"] = WEIRD_FILE,
|
||||
["RST_storm"] = WEIRD_NOTICE_ALWAYS,
|
||||
["RST_with_data"] = WEIRD_FILE, # PC's do this
|
||||
["simultaneous_open"] = WEIRD_NOTICE_PER_CONN,
|
||||
["spontaneous_FIN"] = WEIRD_IGNORE,
|
||||
["spontaneous_RST"] = WEIRD_IGNORE,
|
||||
["SMB_parsing_error"] = WEIRD_FILE,
|
||||
["no_smb_session_using_parsesambamsg"] = WEIRD_FILE,
|
||||
["smb_andx_command_failed_to_parse"] = WEIRD_FILE,
|
||||
["transaction_subcmd_missing"] = WEIRD_FILE,
|
||||
["SSLv3_data_without_full_handshake"] = WEIRD_FILE,
|
||||
["unexpected_SSLv3_record"] = WEIRD_FILE,
|
||||
["successful_RPC_reply_to_invalid_request"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["SYN_after_close"] = WEIRD_FILE,
|
||||
["SYN_after_partial"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["SYN_after_reset"] = WEIRD_FILE,
|
||||
["SYN_inside_connection"] = WEIRD_FILE,
|
||||
["SYN_seq_jump"] = WEIRD_FILE,
|
||||
["SYN_with_data"] = WEIRD_FILE,
|
||||
["TCP_christmas"] = WEIRD_FILE,
|
||||
["truncated_ARP"] = WEIRD_FILE,
|
||||
["truncated_NTP"] = WEIRD_FILE,
|
||||
["UDP_datagram_length_mismatch"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["unexpected_client_HTTP_data"] = WEIRD_FILE,
|
||||
["unexpected_multiple_HTTP_requests"] = WEIRD_FILE,
|
||||
["unexpected_server_HTTP_data"] = WEIRD_FILE,
|
||||
["unmatched_HTTP_reply"] = WEIRD_FILE,
|
||||
["unpaired_RPC_response"] = WEIRD_FILE,
|
||||
["unsolicited_SYN_response"] = WEIRD_IGNORE,
|
||||
["window_recision"] = WEIRD_FILE,
|
||||
["double_%_in_URI"] = WEIRD_FILE,
|
||||
["illegal_%_at_end_of_URI"] = WEIRD_FILE,
|
||||
["unescaped_%_in_URI"] = WEIRD_FILE,
|
||||
["unescaped_special_URI_char"] = WEIRD_FILE,
|
||||
|
||||
["UDP_zone_transfer"] = WEIRD_NOTICE_ONCE,
|
||||
|
||||
["deficit_netbios_hdr_len"] = WEIRD_FILE,
|
||||
["excess_netbios_hdr_len"] = WEIRD_FILE,
|
||||
["netbios_client_session_reply"] = WEIRD_FILE,
|
||||
["netbios_raw_session_msg"] = WEIRD_FILE,
|
||||
["netbios_server_session_request"] = WEIRD_FILE,
|
||||
["unknown_netbios_type"] = WEIRD_FILE,
|
||||
|
||||
# flow_weird
|
||||
["excessively_large_fragment"] = WEIRD_NOTICE_ALWAYS,
|
||||
|
||||
# Code Red generates slews ...
|
||||
["excessively_small_fragment"] = WEIRD_NOTICE_PER_ORIG,
|
||||
|
||||
["fragment_inconsistency"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["fragment_overlap"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["fragment_protocol_inconsistency"] = WEIRD_NOTICE_ALWAYS,
|
||||
["fragment_size_inconsistency"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["fragment_with_DF"] = WEIRD_FILE, # these do indeed happen!
|
||||
["incompletely_captured_fragment"] = WEIRD_NOTICE_ALWAYS,
|
||||
|
||||
# net_weird
|
||||
["bad_IP_checksum"] = WEIRD_FILE,
|
||||
["bad_TCP_header_len"] = WEIRD_FILE,
|
||||
["internally_truncated_header"] = WEIRD_NOTICE_ALWAYS,
|
||||
["truncated_IP"] = WEIRD_FILE,
|
||||
["truncated_header"] = WEIRD_FILE,
|
||||
|
||||
# generated by policy script
|
||||
["Land_attack"] = WEIRD_NOTICE_PER_ORIG,
|
||||
["bad_pm_port"] = WEIRD_NOTICE_PER_ORIG,
|
||||
|
||||
["ICMP-unreachable for wrong state"] = WEIRD_NOTICE_PER_ORIG,
|
||||
|
||||
} &redef;
|
||||
|
||||
# table that maps weird types into a function that should be called
|
||||
# to determine the action.
|
||||
const weird_action_filters:
|
||||
table[string] of function(c: connection): WeirdAction &redef;
|
||||
|
||||
const weird_ignore_host: set[addr, string] &redef;
|
||||
## To completely ignore a specific weird for a host, add the host
|
||||
## and weird name into this set.
|
||||
const ignore_hosts: set[addr, string] &redef;
|
||||
|
||||
# But don't ignore these (for the weird file), it's handy keeping
|
||||
# track of clustered checksum errors.
|
||||
|
@ -233,26 +222,45 @@ export {
|
|||
"bad_ICMP_checksum",
|
||||
} &redef;
|
||||
|
||||
## This table is used to track identifier and name pairs that should be
|
||||
## temporarily ignored because the problem has already been reported.
|
||||
## This helps reduce the volume of high volume weirds by only allowing
|
||||
## a unique weird every ``create_expire`` interval.
|
||||
global weird_ignore: set[string, string] &create_expire=10min &redef;
|
||||
|
||||
## A state set which tracks unique weirds solely by the name to reduce
|
||||
## duplicate logging. This is not synchronized deliberately because it
|
||||
## could cause overload during storms
|
||||
global did_log: set[string, string] &create_expire=1day &redef;
|
||||
|
||||
## A state set which tracks unique weirds solely by the name to reduce
|
||||
## duplicate notices from being raised.
|
||||
global did_notice: set[string, string] &create_expire=1day &redef;
|
||||
|
||||
global log_weird: event(rec: Info);
|
||||
}
|
||||
|
||||
# id/msg pairs that should be ignored (because the problem has already
|
||||
# been reported).
|
||||
global weird_ignore: table[string] of set[string] &write_expire = 10 min;
|
||||
# These actions result in the output being limited and further redundant
|
||||
# weirds not progressing to being logged or noticed.
|
||||
const limiting_actions = {
|
||||
ACTION_LOG_ONCE,
|
||||
ACTION_LOG_PER_CONN,
|
||||
ACTION_LOG_PER_ORIG,
|
||||
ACTION_NOTICE_ONCE,
|
||||
ACTION_NOTICE_PER_CONN,
|
||||
ACTION_NOTICE_PER_ORIG,
|
||||
};
|
||||
|
||||
# For WEIRD_NOTICE_PER_CONN.
|
||||
global did_notice_conn: set[addr, port, addr, port, string]
|
||||
&read_expire = 1 day;
|
||||
# This is an internal set to track which Weird::Action values lead to notice
|
||||
# creation.
|
||||
const notice_actions = {
|
||||
ACTION_NOTICE,
|
||||
ACTION_NOTICE_PER_CONN,
|
||||
ACTION_NOTICE_PER_ORIG,
|
||||
ACTION_NOTICE_ONCE,
|
||||
};
|
||||
|
||||
# For WEIRD_NOTICE_PER_ORIG.
|
||||
global did_notice_orig: set[addr, string] &read_expire = 1 day;
|
||||
|
||||
# For WEIRD_NOTICE_ONCE.
|
||||
global did_weird_log: set[string] &read_expire = 1 day;
|
||||
|
||||
global did_inconsistency_msg: set[conn_id];
|
||||
|
||||
# Used to pass the optional connection into report_weird().
|
||||
# Used to pass the optional connection into report().
|
||||
global current_conn: connection;
|
||||
|
||||
event bro_init() &priority=5
|
||||
|
@ -260,12 +268,54 @@ event bro_init() &priority=5
|
|||
Log::create_stream(Weird::LOG, [$columns=Info, $ev=log_weird]);
|
||||
}
|
||||
|
||||
function report_weird(t: time, name: string, id: string, have_conn: bool,
|
||||
addl: string, action: WeirdAction, no_log: bool)
|
||||
function flow_id_string(src: addr, dst: addr): string
|
||||
{
|
||||
return fmt("%s -> %s", src, dst);
|
||||
}
|
||||
|
||||
function report(t: time, name: string, identifier: string, have_conn: bool, addl: string)
|
||||
{
|
||||
local action = actions[name];
|
||||
|
||||
# If this weird is to be ignored let's drop out of here very early.
|
||||
if ( action == ACTION_IGNORE || [name, identifier] in weird_ignore )
|
||||
return;
|
||||
|
||||
if ( action in limiting_actions )
|
||||
{
|
||||
if ( action in notice_actions )
|
||||
{
|
||||
# Handle notices
|
||||
if ( have_conn && action == ACTION_NOTICE_PER_ORIG )
|
||||
identifier = fmt("%s", current_conn$id$orig_h);
|
||||
else if ( action == ACTION_NOTICE_ONCE )
|
||||
identifier = "";
|
||||
|
||||
# If this weird was already noticed then we're done.
|
||||
if ( [name, identifier] in did_notice )
|
||||
return;
|
||||
add did_notice[name, identifier];
|
||||
}
|
||||
else
|
||||
{
|
||||
# Handle logging.
|
||||
if ( have_conn && action == ACTION_LOG_PER_ORIG )
|
||||
identifier = fmt("%s", current_conn$id$orig_h);
|
||||
else if ( action == ACTION_LOG_ONCE )
|
||||
identifier = "";
|
||||
|
||||
# If this weird was already logged then we're done.
|
||||
if ( [name, identifier] in did_log )
|
||||
return;
|
||||
add did_log[name, identifier];
|
||||
}
|
||||
}
|
||||
|
||||
# Create the Weird::Info record.
|
||||
local info: Info;
|
||||
info$ts = t;
|
||||
info$msg = name;
|
||||
info$name = name;
|
||||
info$peer = peer_description;
|
||||
if ( addl != "" )
|
||||
info$addl = addl;
|
||||
if ( have_conn )
|
||||
|
@ -274,128 +324,59 @@ function report_weird(t: time, name: string, id: string, have_conn: bool,
|
|||
info$id = current_conn$id;
|
||||
}
|
||||
|
||||
if ( action == WEIRD_IGNORE ||
|
||||
(id in weird_ignore && name in weird_ignore[id]) )
|
||||
return;
|
||||
|
||||
if ( action == WEIRD_UNSPECIFIED )
|
||||
{
|
||||
if ( name in weird_action && weird_action[name] == WEIRD_IGNORE )
|
||||
return;
|
||||
else
|
||||
{
|
||||
action = WEIRD_NOTICE_ALWAYS;
|
||||
info$notice = T;
|
||||
}
|
||||
}
|
||||
|
||||
if ( action in notice_actions && ! no_log )
|
||||
if ( action in notice_actions )
|
||||
{
|
||||
info$notice = T;
|
||||
|
||||
local n: Notice::Info;
|
||||
n$note = Weird_Activity;
|
||||
n$msg = info$msg;
|
||||
n$note = Activity;
|
||||
n$msg = info$name;
|
||||
if ( have_conn )
|
||||
n$conn = current_conn;
|
||||
if ( info?$addl )
|
||||
n$sub = info$addl;
|
||||
NOTICE(n);
|
||||
}
|
||||
else if ( id != "" && name !in weird_do_not_ignore_repeats )
|
||||
{
|
||||
if ( id !in weird_ignore )
|
||||
weird_ignore[id] = set() &mergeable;
|
||||
add weird_ignore[id][name];
|
||||
}
|
||||
|
||||
|
||||
# This is for the temporary ignoring to reduce volume for identical weirds.
|
||||
if ( name !in weird_do_not_ignore_repeats )
|
||||
add weird_ignore[name, identifier];
|
||||
|
||||
Log::write(Weird::LOG, info);
|
||||
}
|
||||
|
||||
function report_weird_conn(t: time, name: string, id: string, addl: string,
|
||||
c: connection)
|
||||
function report_conn(t: time, name: string, identifier: string, addl: string, c: connection)
|
||||
{
|
||||
if ( [c$id$orig_h, name] in weird_ignore_host ||
|
||||
[c$id$resp_h, name] in weird_ignore_host )
|
||||
local cid = c$id;
|
||||
if ( [cid$orig_h, name] in ignore_hosts ||
|
||||
[cid$resp_h, name] in ignore_hosts )
|
||||
return;
|
||||
|
||||
local no_log = F;
|
||||
local action = WEIRD_UNSPECIFIED;
|
||||
|
||||
if ( name in weird_action )
|
||||
{
|
||||
if ( name in weird_action_filters )
|
||||
action = weird_action_filters[name](c);
|
||||
|
||||
if ( action == WEIRD_UNSPECIFIED )
|
||||
action = weird_action[name];
|
||||
|
||||
local cid = c$id;
|
||||
|
||||
if ( action == WEIRD_NOTICE_PER_CONN )
|
||||
{
|
||||
if ( [cid$orig_h, cid$orig_p, cid$resp_h, cid$resp_p, name] in did_notice_conn )
|
||||
no_log = T;
|
||||
else
|
||||
add did_notice_conn[cid$orig_h, cid$orig_p, cid$resp_h, cid$resp_p, name];
|
||||
}
|
||||
|
||||
else if ( action == WEIRD_NOTICE_PER_ORIG )
|
||||
{
|
||||
if ( [c$id$orig_h, name] in did_notice_orig )
|
||||
no_log = T;
|
||||
else
|
||||
add did_notice_orig[c$id$orig_h, name];
|
||||
}
|
||||
|
||||
else if ( action == WEIRD_NOTICE_ONCE )
|
||||
{
|
||||
if ( name in did_weird_log )
|
||||
no_log = T;
|
||||
else
|
||||
add did_weird_log[name];
|
||||
}
|
||||
}
|
||||
|
||||
current_conn = c;
|
||||
report_weird(t, name, id, T, addl, action, no_log);
|
||||
report(t, name, identifier, T, addl);
|
||||
}
|
||||
|
||||
function report_weird_orig(t: time, name: string, id: string, orig: addr)
|
||||
function report_orig(t: time, name: string, identifier: string, orig: addr)
|
||||
{
|
||||
local no_log = F;
|
||||
local action = WEIRD_UNSPECIFIED;
|
||||
|
||||
if ( name in weird_action )
|
||||
{
|
||||
action = weird_action[name];
|
||||
if ( action == WEIRD_NOTICE_PER_ORIG )
|
||||
{
|
||||
if ( [orig, name] in did_notice_orig )
|
||||
no_log = T;
|
||||
else
|
||||
add did_notice_orig[orig, name];
|
||||
}
|
||||
}
|
||||
|
||||
report_weird(t, name, id, F, "", action, no_log);
|
||||
}
|
||||
if ( [orig, name] in ignore_hosts )
|
||||
return;
|
||||
|
||||
report(t, name, identifier, F, "");
|
||||
}
|
||||
|
||||
|
||||
# The following events come from core generated weirds typically.
|
||||
event conn_weird(name: string, c: connection, addl: string)
|
||||
{
|
||||
report_weird_conn(network_time(), name, id_string(c$id), addl, c);
|
||||
report_conn(network_time(), name, id_string(c$id), addl, c);
|
||||
}
|
||||
|
||||
event flow_weird(name: string, src: addr, dst: addr)
|
||||
{
|
||||
report_weird_orig(network_time(), name, fmt("%s -> %s", src, dst), src);
|
||||
report_orig(network_time(), name, flow_id_string(src, dst), src);
|
||||
}
|
||||
|
||||
event net_weird(name: string)
|
||||
{
|
||||
report_weird(network_time(), name, "", F, "", WEIRD_UNSPECIFIED, F);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
delete weird_ignore[id_string(c$id)];
|
||||
delete did_inconsistency_msg[c$id];
|
||||
report(network_time(), name, "", F, "");
|
||||
}
|
||||
|
|
|
@ -121,17 +121,21 @@ function parse_mozilla(unparsed_version: string,
|
|||
if ( 2 in parts )
|
||||
v = parse(parts[2], host, software_type)$version;
|
||||
}
|
||||
else if ( /MSIE 7.*Trident\/4\.0/ in unparsed_version )
|
||||
{
|
||||
software_name = "MSIE";
|
||||
v = [$major=8,$minor=0];
|
||||
}
|
||||
else if ( / MSIE [0-9\.]*b?[0-9]*;/ in unparsed_version )
|
||||
else if ( / MSIE / in unparsed_version )
|
||||
{
|
||||
software_name = "MSIE";
|
||||
parts = split_all(unparsed_version, /MSIE [0-9\.]*b?[0-9]*/);
|
||||
if ( 2 in parts )
|
||||
v = parse(parts[2], host, software_type)$version;
|
||||
if ( /Trident\/4\.0/ in unparsed_version )
|
||||
v = [$major=8,$minor=0];
|
||||
else if ( /Trident\/5\.0/ in unparsed_version )
|
||||
v = [$major=9,$minor=0];
|
||||
else if ( /Trident\/6\.0/ in unparsed_version )
|
||||
v = [$major=10,$minor=0];
|
||||
else
|
||||
{
|
||||
parts = split_all(unparsed_version, /MSIE [0-9]{1,2}\.*[0-9]*b?[0-9]*/);
|
||||
if ( 2 in parts )
|
||||
v = parse(parts[2], host, software_type)$version;
|
||||
}
|
||||
}
|
||||
else if ( /Version\/.*Safari\// in unparsed_version )
|
||||
{
|
||||
|
|
|
@ -54,14 +54,11 @@ event http_entity_data(c: connection, is_orig: bool, length: count, data: string
|
|||
## incorrect anyway.
|
||||
event content_gap(c: connection, is_orig: bool, seq: count, length: count) &priority=5
|
||||
{
|
||||
if ( is_orig || ! c?$http ) return;
|
||||
|
||||
if ( is_orig || ! c?$http || ! c$http$calculating_md5 ) return;
|
||||
|
||||
set_state(c, F, is_orig);
|
||||
if ( c$http$calculating_md5 )
|
||||
{
|
||||
c$http$calculating_md5 = F;
|
||||
md5_hash_finish(c$id);
|
||||
}
|
||||
c$http$calculating_md5 = F;
|
||||
md5_hash_finish(c$id);
|
||||
}
|
||||
|
||||
## When the file finishes downloading, finish the hash and generate a notice.
|
||||
|
|
|
@ -18,6 +18,9 @@ export {
|
|||
ts: time &log;
|
||||
uid: string &log;
|
||||
id: conn_id &log;
|
||||
## This represents the pipelined depth into the connection of this
|
||||
## request/response transaction.
|
||||
trans_depth: count &log;
|
||||
## The verb used in the HTTP request (GET, POST, HEAD, etc.).
|
||||
method: string &log &optional;
|
||||
## The value of the HOST header.
|
||||
|
@ -33,42 +36,34 @@ export {
|
|||
## The actual uncompressed content size of the data transferred from
|
||||
## the client.
|
||||
request_body_len: count &log &default=0;
|
||||
## This indicates whether or not there was an interruption while the
|
||||
## request body was being sent.
|
||||
request_body_interrupted: bool &log &default=F;
|
||||
## The actual uncompressed content size of the data transferred from
|
||||
## the server.
|
||||
response_body_len: count &log &default=0;
|
||||
## This indicates whether or not there was an interruption while the
|
||||
## request body was being sent. An interruption could cause hash
|
||||
## calculation to fail and a number of other problems since the
|
||||
## analyzer may not be able to get back on track with the connection.
|
||||
response_body_interrupted: bool &log &default=F;
|
||||
response_body_len: count &log &default=0;
|
||||
## The status code returned by the server.
|
||||
status_code: count &log &optional;
|
||||
status_code: count &log &optional;
|
||||
## The status message returned by the server.
|
||||
status_msg: string &log &optional;
|
||||
status_msg: string &log &optional;
|
||||
## The last 1xx informational reply code returned by the server.
|
||||
info_code: count &log &optional;
|
||||
info_code: count &log &optional;
|
||||
## The last 1xx informational reply message returned by the server.
|
||||
info_msg: string &log &optional;
|
||||
info_msg: string &log &optional;
|
||||
## The filename given in the Content-Disposition header
|
||||
## sent by the server.
|
||||
filename: string &log &optional;
|
||||
filename: string &log &optional;
|
||||
## This is a set of indicators of various attributes discovered and
|
||||
## related to a particular request/response pair.
|
||||
tags: set[Tags] &log;
|
||||
|
||||
## The username if basic-auth is performed for the request.
|
||||
username: string &log &optional;
|
||||
username: string &log &optional;
|
||||
## The password if basic-auth is performed for the request.
|
||||
password: string &log &optional;
|
||||
password: string &log &optional;
|
||||
|
||||
## This determines if the password will be captured for this request.
|
||||
capture_password: bool &default=default_capture_password;
|
||||
capture_password: bool &default=default_capture_password;
|
||||
|
||||
## All of the headers that may indicate if the request was proxied.
|
||||
proxied: set[string] &log &optional;
|
||||
proxied: set[string] &log &optional;
|
||||
};
|
||||
|
||||
type State: record {
|
||||
|
@ -131,6 +126,9 @@ function new_http_session(c: connection): Info
|
|||
tmp$ts=network_time();
|
||||
tmp$uid=c$uid;
|
||||
tmp$id=c$id;
|
||||
# $current_request is set prior to the Info record creation so we
|
||||
# can use the value directly here.
|
||||
tmp$trans_depth = c$http_state$current_request;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -141,7 +139,7 @@ function set_state(c: connection, request: bool, is_orig: bool)
|
|||
local s: State;
|
||||
c$http_state = s;
|
||||
}
|
||||
|
||||
|
||||
# These deal with new requests and responses.
|
||||
if ( request || c$http_state$current_request !in c$http_state$pending )
|
||||
c$http_state$pending[c$http_state$current_request] = new_http_session(c);
|
||||
|
@ -253,15 +251,9 @@ event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) &
|
|||
set_state(c, F, is_orig);
|
||||
|
||||
if ( is_orig )
|
||||
{
|
||||
c$http$request_body_len = stat$body_length;
|
||||
c$http$request_body_interrupted = stat$interrupted;
|
||||
}
|
||||
else
|
||||
{
|
||||
c$http$response_body_len = stat$body_length;
|
||||
c$http$response_body_interrupted = stat$interrupted;
|
||||
}
|
||||
}
|
||||
|
||||
event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) &priority = -5
|
||||
|
|
|
@ -19,9 +19,9 @@ export {
|
|||
ts: time &log;
|
||||
uid: string &log;
|
||||
id: conn_id &log;
|
||||
## Internally generated "message id" that ties back to the particular
|
||||
## message in the SMTP log where this entity was seen.
|
||||
mid: string &log;
|
||||
## A count to represent the depth of this message transaction in a
|
||||
## single connection where multiple messages were transferred.
|
||||
trans_depth: count &log;
|
||||
## The filename seen in the Content-Disposition header.
|
||||
filename: string &log &optional;
|
||||
## Track how many bytes of the MIME encoded file have been seen.
|
||||
|
@ -90,7 +90,7 @@ function set_session(c: connection, new_entity: bool)
|
|||
info$ts=network_time();
|
||||
info$uid=c$uid;
|
||||
info$id=c$id;
|
||||
info$mid=c$smtp$mid;
|
||||
info$trans_depth=c$smtp$trans_depth;
|
||||
|
||||
c$smtp$current_entity = info;
|
||||
++c$smtp_state$mime_level;
|
||||
|
|
|
@ -11,10 +11,9 @@ export {
|
|||
ts: time &log;
|
||||
uid: string &log;
|
||||
id: conn_id &log;
|
||||
## This is an internally generated "message id" that can be used to
|
||||
## map between SMTP messages and MIME entities in the SMTP entities
|
||||
## log.
|
||||
mid: string &log;
|
||||
## This is a number that indicates the number of messages deep into
|
||||
## this connection where this particular message was transferred.
|
||||
trans_depth: count &log;
|
||||
helo: string &log &optional;
|
||||
mailfrom: string &log &optional;
|
||||
rcptto: set[string] &log &optional;
|
||||
|
@ -98,8 +97,11 @@ function new_smtp_log(c: connection): Info
|
|||
l$ts=network_time();
|
||||
l$uid=c$uid;
|
||||
l$id=c$id;
|
||||
l$mid=unique_id("@");
|
||||
if ( c?$smtp_state && c$smtp_state?$helo )
|
||||
# The messages_transferred count isn't incremented until the message is
|
||||
# finished so we need to increment the count by 1 here.
|
||||
l$trans_depth = c$smtp_state$messages_transferred+1;
|
||||
|
||||
if ( c$smtp_state?$helo )
|
||||
l$helo = c$smtp_state$helo;
|
||||
|
||||
# The path will always end with the hosts involved in this connection.
|
||||
|
@ -165,7 +167,6 @@ event smtp_reply(c: connection, is_orig: bool, code: count, cmd: string,
|
|||
event smtp_reply(c: connection, is_orig: bool, code: count, cmd: string,
|
||||
msg: string, cont_resp: bool) &priority=-5
|
||||
{
|
||||
set_smtp_session(c);
|
||||
if ( cmd == "." )
|
||||
{
|
||||
# Track the number of messages seen in this session.
|
||||
|
|
|
@ -103,25 +103,35 @@ function check_ssh_connection(c: connection, done: bool)
|
|||
return;
|
||||
|
||||
# Make sure conn_size_analyzer is active by checking
|
||||
# resp$num_bytes_ip
|
||||
if ( !c$resp?$num_bytes_ip )
|
||||
# resp$num_bytes_ip. In general it should always be active though.
|
||||
if ( ! c$resp?$num_bytes_ip )
|
||||
return;
|
||||
|
||||
# If this is still a live connection and the byte count has not
|
||||
# crossed the threshold, just return and let the resheduled check happen later.
|
||||
if ( !done && c$resp$num_bytes_ip < authentication_data_size )
|
||||
# Remove the IP and TCP header length from the total size.
|
||||
# TODO: Fix for IPv6. This whole approach also seems to break in some
|
||||
# cases where there are more header bytes than num_bytes_ip.
|
||||
local header_bytes = c$resp$num_pkts*32 + c$resp$num_pkts*20;
|
||||
local server_bytes = c$resp$num_bytes_ip;
|
||||
if ( server_bytes >= header_bytes )
|
||||
server_bytes = server_bytes - header_bytes;
|
||||
else
|
||||
server_bytes = c$resp$size;
|
||||
|
||||
# If this is still a live connection and the byte count has not crossed
|
||||
# the threshold, just return and let the rescheduled check happen later.
|
||||
if ( ! done && server_bytes < authentication_data_size )
|
||||
return;
|
||||
|
||||
# Make sure the server has sent back more than 50 bytes to filter out
|
||||
# hosts that are just port scanning. Nothing is ever logged if the server
|
||||
# doesn't send back at least 50 bytes.
|
||||
if ( c$resp$num_bytes_ip < 50 )
|
||||
if ( server_bytes < 50 )
|
||||
return;
|
||||
|
||||
c$ssh$direction = Site::is_local_addr(c$id$orig_h) ? OUTBOUND : INBOUND;
|
||||
c$ssh$resp_size = c$resp$num_bytes_ip;
|
||||
c$ssh$resp_size = server_bytes;
|
||||
|
||||
if ( c$resp$num_bytes_ip < authentication_data_size )
|
||||
if ( server_bytes < authentication_data_size )
|
||||
{
|
||||
c$ssh$status = "failure";
|
||||
event SSH::heuristic_failed_login(c);
|
||||
|
|
|
@ -493,40 +493,41 @@ export {
|
|||
} &default="UNKNOWN";
|
||||
|
||||
const x509_errors: table[count] of string = {
|
||||
[0] = "X509_V_OK",
|
||||
[1] = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT",
|
||||
[2] = "X509_V_ERR_UNABLE_TO_GET_CRL",
|
||||
[3] = "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE",
|
||||
[4] = "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE",
|
||||
[5] = "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY",
|
||||
[6] = "X509_V_ERR_CERT_SIGNATURE_FAILURE",
|
||||
[7] = "X509_V_ERR_CRL_SIGNATURE_FAILURE",
|
||||
[8] = "X509_V_ERR_CERT_NOT_YET_VALID",
|
||||
[9] = "X509_V_ERR_CERT_HAS_EXPIRED",
|
||||
[10] = "X509_V_ERR_CRL_NOT_YET_VALID",
|
||||
[11] = "X509_V_ERR_CRL_HAS_EXPIRED",
|
||||
[12] = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD",
|
||||
[13] = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD",
|
||||
[14] = "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD",
|
||||
[15] = "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD",
|
||||
[16] = "X509_V_ERR_OUT_OF_MEM",
|
||||
[17] = "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT",
|
||||
[18] = "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN",
|
||||
[19] = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
||||
[20] = "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
||||
[21] = "X509_V_ERR_CERT_CHAIN_TOO_LONG",
|
||||
[22] = "X509_V_ERR_CERT_REVOKED",
|
||||
[23] = "X509_V_ERR_INVALID_CA",
|
||||
[24] = "X509_V_ERR_PATH_LENGTH_EXCEEDED",
|
||||
[25] = "X509_V_ERR_INVALID_PURPOSE",
|
||||
[26] = "X509_V_ERR_CERT_UNTRUSTED",
|
||||
[27] = "X509_V_ERR_CERT_REJECTED",
|
||||
[28] = "X509_V_ERR_SUBJECT_ISSUER_MISMATCH",
|
||||
[29] = "X509_V_ERR_AKID_SKID_MISMATCH",
|
||||
[30] = "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH",
|
||||
[31] = "X509_V_ERR_KEYUSAGE_NO_CERTSIGN",
|
||||
[32] = "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER",
|
||||
[33] = "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
|
||||
[0] = "ok",
|
||||
[1] = "unable to get issuer cert",
|
||||
[2] = "unable to get crl",
|
||||
[3] = "unable to decrypt cert signature",
|
||||
[4] = "unable to decrypt crl signature",
|
||||
[5] = "unable to decode issuer public key",
|
||||
[6] = "cert signature failure",
|
||||
[7] = "crl signature failure",
|
||||
[8] = "cert not yet valid",
|
||||
[9] = "cert has expired",
|
||||
[10] = "crl not yet valid",
|
||||
[11] = "crl has expired",
|
||||
[12] = "error in cert not before field",
|
||||
[13] = "error in cert not after field",
|
||||
[14] = "error in crl last update field",
|
||||
[15] = "error in crl next update field",
|
||||
[16] = "out of mem",
|
||||
[17] = "depth zero self signed cert",
|
||||
[18] = "self signed cert in chain",
|
||||
[19] = "unable to get issuer cert locally",
|
||||
[20] = "unable to verify leaf signature",
|
||||
[21] = "cert chain too long",
|
||||
[22] = "cert revoked",
|
||||
[23] = "invalid ca",
|
||||
[24] = "path length exceeded",
|
||||
[25] = "invalid purpose",
|
||||
[26] = "cert untrusted",
|
||||
[27] = "cert rejected",
|
||||
[28] = "subject issuer mismatch",
|
||||
[29] = "akid skid mismatch",
|
||||
[30] = "akid issuer serial mismatch",
|
||||
[31] = "keyusage no certsign",
|
||||
[32] = "unable to get crl issuer",
|
||||
[33] = "unhandled critical extension"
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,5 +8,5 @@ module Communication;
|
|||
event bro_init() &priority=-10
|
||||
{
|
||||
enable_communication();
|
||||
listen(listen_interface, listen_port, listen_encrypted);
|
||||
listen(listen_interface, listen_port, listen_ssl);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,10 @@ function configuration_update_func(p: event_peer)
|
|||
# We don't want to update non-const globals because that's usually
|
||||
# where state is stored and those values will frequently be declared
|
||||
# with &redef so that attributes can be redefined.
|
||||
if ( t$constant && t$redefinable )
|
||||
#
|
||||
# NOTE: functions are currently not fully supported for serialization and hence
|
||||
# aren't sent.
|
||||
if ( t$constant && t$redefinable && t$type_name != "func" )
|
||||
{
|
||||
send_id(p, id);
|
||||
++cnt;
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
##!
|
||||
|
||||
module LoadedScripts;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
type Info: record {
|
||||
name: string &log;
|
||||
## Name of the script loaded potentially with spaces included before
|
||||
## the file name to indicate load depth. The convention is two spaces
|
||||
## per level of depth.
|
||||
name: string &log;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ export {
|
|||
}
|
||||
|
||||
redef record connection += {
|
||||
## This field is to indicate whether or not the processing for detecting
|
||||
## and logging the service for this connection is complete.
|
||||
known_services_done: bool &default=F;
|
||||
};
|
||||
|
||||
|
@ -60,14 +62,15 @@ function known_services_done(c: connection)
|
|||
c$known_services_done = T;
|
||||
|
||||
if ( ! addr_matches_host(id$resp_h, service_tracking) ||
|
||||
"ftp-data" in c$service ) # don't include ftp data sessions
|
||||
"ftp-data" in c$service || # don't include ftp data sessions
|
||||
("DNS" in c$service && c$resp$size == 0) ) # for dns, require that the server talks.
|
||||
return;
|
||||
|
||||
# If no protocol was detected, wait a short
|
||||
# time before attempting to log in case a protocol is detected
|
||||
# on another connection.
|
||||
if ( |c$service| == 0 )
|
||||
schedule 2mins { log_it(network_time(), id$resp_h, id$resp_p, c$service) };
|
||||
schedule 5min { log_it(network_time(), id$resp_h, id$resp_p, c$service) };
|
||||
else
|
||||
event log_it(network_time(), id$resp_h, id$resp_p, c$service);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
##! This script handles core generated connection related "weird" events to
|
||||
##! push weird information about connections into the weird framework.
|
||||
##! For live operational deployments, this can frequently cause load issues
|
||||
##! due to large numbers of these events being passed between nodes.
|
||||
##! due to large numbers of these events and quite possibly shouldn't be
|
||||
##! loaded.
|
||||
|
||||
@load base/frameworks/notice
|
||||
|
||||
module Weird;
|
||||
module Conn;
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
|
@ -20,14 +21,11 @@ export {
|
|||
|
||||
event rexmit_inconsistency(c: connection, t1: string, t2: string)
|
||||
{
|
||||
if ( c$id !in did_inconsistency_msg )
|
||||
{
|
||||
NOTICE([$note=Retransmission_Inconsistency,
|
||||
$conn=c,
|
||||
$msg=fmt("%s rexmit inconsistency (%s) (%s)",
|
||||
id_string(c$id), t1, t2)]);
|
||||
add did_inconsistency_msg[c$id];
|
||||
}
|
||||
NOTICE([$note=Retransmission_Inconsistency,
|
||||
$conn=c,
|
||||
$msg=fmt("%s rexmit inconsistency (%s) (%s)",
|
||||
id_string(c$id), t1, t2),
|
||||
$identifier=fmt("%s", c$id)]);
|
||||
}
|
||||
|
||||
event ack_above_hole(c: connection)
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
##! This script adds authoritative and additional responses for the current
|
||||
##! query to the DNS log. It can cause severe overhead due to the need
|
||||
##! for all authoritative and additional responses to have events generated.
|
||||
##! This script is not recommended for use on heavily loaded links.
|
||||
|
||||
@load base/protocols/dns/main
|
||||
|
||||
redef dns_skip_all_auth = F;
|
||||
|
@ -7,12 +12,14 @@ module DNS;
|
|||
|
||||
export {
|
||||
redef record Info += {
|
||||
## Authoritative responses for the query.
|
||||
auth: set[string] &log &optional;
|
||||
## Additional responses for the query.
|
||||
addl: set[string] &log &optional;
|
||||
};
|
||||
}
|
||||
|
||||
event do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=4
|
||||
event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=4
|
||||
{
|
||||
# The "ready" flag will be set here. This causes the setting from the
|
||||
# base script to be overridden since the base script will log immediately
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
##! Script for detecting strange activity within DNS.
|
||||
##!
|
||||
##! Notices raised:
|
||||
##!
|
||||
##! * :bro:enum:`DNS::External_Name`
|
||||
##!
|
||||
##! A remote host resolves to a local host, but the name is not considered
|
||||
##! to be within a local zone. :bro:id:`local_zones` variable **must**
|
||||
##! be set appropriately for this detection.
|
||||
##! This script detects names which are not within zones considered to be
|
||||
##! local but resolving to addresses considered local.
|
||||
##! The :bro:id:`Site::local_zones` variable **must** be set appropriately for
|
||||
##! this detection.
|
||||
|
||||
@load base/frameworks/notice/main
|
||||
@load base/frameworks/notice
|
||||
@load base/utils/site
|
||||
|
||||
module DNS;
|
||||
|
@ -16,8 +11,8 @@ module DNS;
|
|||
export {
|
||||
redef enum Notice::Type += {
|
||||
## Raised when a non-local name is found to be pointing at a local host.
|
||||
## This only works appropriately when all of your authoritative DNS
|
||||
## servers are located in your :bro:id:`Site::local_nets`.
|
||||
## :bro:id:`Site::local_zones` variable **must** be set appropriately
|
||||
## for this detection.
|
||||
External_Name,
|
||||
};
|
||||
}
|
||||
|
@ -30,11 +25,11 @@ event dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priori
|
|||
# Check for responses from remote hosts that point at local hosts
|
||||
# but the name is not considered to be within a "local" zone.
|
||||
if ( Site::is_local_addr(a) && # referring to a local host
|
||||
!Site::is_local_addr(c$id$resp_h) && # response from an external nameserver
|
||||
!Site::is_local_name(ans$query) ) # name isn't in a local zone.
|
||||
! Site::is_local_name(ans$query) ) # name isn't in a local zone.
|
||||
{
|
||||
NOTICE([$note=External_Name,
|
||||
$msg=fmt("%s is pointing to a local host - %s.", ans$query, a),
|
||||
$conn=c]);
|
||||
$conn=c,
|
||||
$identifier=cat(a,ans$query)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
@load base/frameworks/notice/main
|
||||
@load base/protocols/ftp/main
|
||||
##! Detect various potentially bad FTP activities.
|
||||
|
||||
@load base/frameworks/notice
|
||||
@load base/protocols/ftp
|
||||
|
||||
module FTP;
|
||||
|
||||
|
@ -21,6 +23,7 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
|
|||
/[Ee][Xx][Ee][Cc]/ in c$ftp$cmdarg$arg )
|
||||
{
|
||||
NOTICE([$note=Site_Exec_Success, $conn=c,
|
||||
$msg=fmt("%s %s", c$ftp$cmdarg$cmd, c$ftp$cmdarg$arg)]);
|
||||
$msg=fmt("FTP command: %s %s", c$ftp$cmdarg$cmd, c$ftp$cmdarg$arg),
|
||||
$identifier=cat(c$id$orig_h, c$id$resp_h, "SITE EXEC")]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
##! Software detection with the FTP protocol.
|
||||
##!
|
||||
##! TODO:
|
||||
##!
|
||||
##! * Detect server software with initial 220 message
|
||||
##! * Detect client software with password given for anonymous users
|
||||
##! (e.g. cyberduck@example.net)
|
||||
|
||||
@load base/frameworks/software/main
|
||||
# TODO:
|
||||
#
|
||||
# * Detect server software with initial 220 message
|
||||
# * Detect client software with password given for anonymous users
|
||||
# (e.g. cyberduck@example.net)
|
||||
|
||||
@load base/frameworks/software
|
||||
|
||||
module FTP;
|
||||
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
##! documentation for the :doc:base/protocols/http/file-hash.bro script to see how to
|
||||
##! configure which transfers will have hashes calculated.
|
||||
|
||||
@load base/frameworks/notice/main
|
||||
@load base/protocols/http/main
|
||||
@load base/protocols/http/utils
|
||||
@load base/protocols/http/file-hash
|
||||
@load base/frameworks/notice
|
||||
@load base/protocols/http
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
##! SQL injection detection in HTTP.
|
||||
##! SQL injection attack detection in HTTP.
|
||||
|
||||
@load base/frameworks/notice
|
||||
@load base/frameworks/metrics
|
||||
|
@ -8,7 +8,10 @@ module HTTP;
|
|||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
## Indicates that a host performing SQL injection attacks was detected.
|
||||
SQL_Injection_Attacker,
|
||||
## Indicates that a host was seen to have SQL injection attacks against
|
||||
## it. This is tracked by IP address as opposed to hostname.
|
||||
SQL_Injection_Attack_Against,
|
||||
};
|
||||
|
||||
|
@ -49,9 +52,13 @@ export {
|
|||
|
||||
event bro_init() &priority=3
|
||||
{
|
||||
# Add filters to the metrics so that the metrics framework knows how to
|
||||
# determine when it looks like an actual attack and how to respond when
|
||||
# thresholds are crossed.
|
||||
|
||||
Metrics::add_filter(SQL_ATTACKER, [$log=F,
|
||||
$notice_threshold=sqli_requests_threshold,
|
||||
$break_interval=sqli_requests_interval,
|
||||
$break_interval=sqli_requests_interval,
|
||||
$note=SQL_Injection_Attacker]);
|
||||
Metrics::add_filter(SQL_ATTACKS_AGAINST, [$log=F,
|
||||
$notice_threshold=sqli_requests_threshold,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
@load base/frameworks/signatures/main
|
||||
@load base/frameworks/software/main
|
||||
@load base/protocols/http/main
|
||||
@load base/protocols/http/utils
|
||||
@load base/frameworks/signatures
|
||||
@load base/frameworks/software
|
||||
@load base/protocols/http
|
||||
|
||||
module HTTP;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
##! This script take advantage of a few ways that installed plugin information
|
||||
##! leaks from web browsers
|
||||
##! leaks from web browsers.
|
||||
|
||||
@load base/protocols/http
|
||||
@load base/frameworks/software
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
##! Software identification and extraction for HTTP traffic.
|
||||
|
||||
@load base/frameworks/software/main
|
||||
@load base/frameworks/software
|
||||
|
||||
module HTTP;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
##! This script extracts and logs variables from the requested URI
|
||||
|
||||
@load base/protocols/http/main
|
||||
@load base/protocols/http/utils
|
||||
@load base/protocols/http
|
||||
|
||||
module HTTP;
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ export {
|
|||
const ignore_guessers: table[subnet] of subnet &redef;
|
||||
|
||||
## Keeps track of hosts identified as guessing passwords.
|
||||
global password_guessers: set[addr] &read_expire=guessing_timeout+1hr &synchronized;
|
||||
global password_guessers: set[addr]
|
||||
&read_expire=guessing_timeout+1hr &synchronized &redef;
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
##! This implements all of the additional information and geodata detections
|
||||
##! for SSH analysis.
|
||||
|
||||
@load base/frameworks/notice/main
|
||||
@load base/protocols/ssh/main
|
||||
@load base/frameworks/notice
|
||||
@load base/protocols/ssh
|
||||
|
||||
module SSH;
|
||||
|
||||
|
@ -11,17 +11,17 @@ export {
|
|||
## If an SSH login is seen to or from a "watched" country based on the
|
||||
## :bro:id:`SSH::watched_countries` variable then this notice will
|
||||
## be generated.
|
||||
Login_From_Watched_Country,
|
||||
Watched_Country_Login,
|
||||
};
|
||||
|
||||
redef record Info += {
|
||||
## Add geographic data related to the "remote" host of the connection.
|
||||
remote_location: geo_location &log &optional;
|
||||
};
|
||||
|
||||
## The set of countries for which you'd like to throw notices upon
|
||||
## successful login
|
||||
const watched_countries: set[string] = {"RO"} &redef;
|
||||
|
||||
redef record Info += {
|
||||
## Add geographic data related to the "remote" host of the connection.
|
||||
remote_location: geo_location &log &optional;
|
||||
};
|
||||
}
|
||||
|
||||
event SSH::heuristic_successful_login(c: connection) &priority=5
|
||||
|
@ -35,8 +35,10 @@ event SSH::heuristic_successful_login(c: connection) &priority=5
|
|||
|
||||
if ( location?$country_code && location$country_code in watched_countries )
|
||||
{
|
||||
NOTICE([$note=Login_From_Watched_Country,
|
||||
NOTICE([$note=Watched_Country_Login,
|
||||
$conn=c,
|
||||
$msg=fmt("SSH login from watched country: %s", location$country_code)]);
|
||||
$msg=fmt("SSH login %s watched country: %s",
|
||||
(c$ssh$direction == OUTBOUND) ? "to" : "from",
|
||||
location$country_code)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
@load base/frameworks/notice/main
|
||||
##! This script will generate a notice if an apparent SSH login originates
|
||||
##! or heads to a host with a reverse hostname that looks suspicious. By
|
||||
##! default, the regular expression to match "interesting" hostnames includes
|
||||
##! names that are typically used for infrastructure hosts like nameservers,
|
||||
##! mail servers, web servers and ftp servers.
|
||||
|
||||
@load base/frameworks/notice
|
||||
|
||||
module SSH;
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
## Generated if a login originates from a host matched by the
|
||||
## Generated if a login originates or responds with a host and the
|
||||
## reverse hostname lookup resolves to a name matched by the
|
||||
## :bro:id:`interesting_hostnames` regular expression.
|
||||
Login_From_Interesting_Hostname,
|
||||
## Generated if a login goes to a host matched by the
|
||||
## :bro:id:`interesting_hostnames` regular expression.
|
||||
Login_To_Interesting_Hostname,
|
||||
Interesting_Hostname_Login,
|
||||
};
|
||||
|
||||
## Strange/bad host names to see successful SSH logins from or to.
|
||||
|
@ -25,26 +29,16 @@ export {
|
|||
|
||||
event SSH::heuristic_successful_login(c: connection)
|
||||
{
|
||||
# Check to see if this login came from an interesting hostname.
|
||||
when ( local orig_hostname = lookup_addr(c$id$orig_h) )
|
||||
for ( host in set(c$id$orig_h, c$id$resp_h) )
|
||||
{
|
||||
if ( interesting_hostnames in orig_hostname )
|
||||
when ( local hostname = lookup_addr(host) )
|
||||
{
|
||||
NOTICE([$note=Login_From_Interesting_Hostname,
|
||||
$conn=c,
|
||||
$msg=fmt("Interesting login from hostname: %s", orig_hostname),
|
||||
$sub=orig_hostname]);
|
||||
}
|
||||
}
|
||||
# Check to see if this login went to an interesting hostname.
|
||||
when ( local resp_hostname = lookup_addr(c$id$resp_h) )
|
||||
{
|
||||
if ( interesting_hostnames in resp_hostname )
|
||||
{
|
||||
NOTICE([$note=Login_To_Interesting_Hostname,
|
||||
$conn=c,
|
||||
$msg=fmt("Interesting login to hostname: %s", resp_hostname),
|
||||
$sub=resp_hostname]);
|
||||
if ( interesting_hostnames in hostname )
|
||||
{
|
||||
NOTICE([$note=Interesting_Hostname_Login,
|
||||
$msg=fmt("Interesting login from hostname: %s", hostname),
|
||||
$sub=hostname, $conn=c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
@load base/frameworks/software/main
|
||||
##! This script extracts SSH client and server information from SSH
|
||||
##! connections and forwards it to the software framework.
|
||||
|
||||
@load base/frameworks/software
|
||||
|
||||
module SSH;
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ event bro_init() &priority=5
|
|||
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string) &priority=3
|
||||
{
|
||||
# Make sure this is the server cert and we have a hash for it.
|
||||
if ( chain_idx == 0 && ! c$ssl?$cert_hash ) return;
|
||||
if ( chain_idx != 0 || ! c$ssl?$cert_hash )
|
||||
return;
|
||||
|
||||
local host = c$id$resp_h;
|
||||
if ( [host, c$ssl$cert_hash] !in certs && addr_matches_host(host, cert_tracking) )
|
||||
|
|
|
@ -1,26 +1,29 @@
|
|||
##! Perform full certificate chain validation for SSL certificates.
|
||||
|
||||
@load base/frameworks/notice/main
|
||||
@load base/protocols/ssl/main
|
||||
|
||||
@load base/frameworks/notice
|
||||
@load base/protocols/ssl
|
||||
@load protocols/ssl/cert-hash
|
||||
|
||||
module SSL;
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
## This notice indicates that the result of validating the certificate
|
||||
## along with it's full certificate chain was invalid.
|
||||
Invalid_Server_Cert
|
||||
};
|
||||
|
||||
redef record Info += {
|
||||
## This stores and logs the result of certificate validation for
|
||||
## this connection.
|
||||
validation_status: string &log &optional;
|
||||
};
|
||||
|
||||
## MD5 hash values for recently validated certs along with the validation
|
||||
## status message are kept in this table so avoid constant validation
|
||||
## status message are kept in this table to avoid constant validation
|
||||
## everytime the same certificate is seen.
|
||||
global recently_validated_certs: table[string] of string = table()
|
||||
&read_expire=5mins &synchronized;
|
||||
&read_expire=5mins &synchronized &redef;
|
||||
}
|
||||
|
||||
event ssl_established(c: connection) &priority=3
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
@load ./remove-high-volume-notices
|
||||
@load ./packet-fragments
|
||||
@load ./warnings
|
|
@ -1,10 +0,0 @@
|
|||
##! This strives to tune out high volume and less useful data
|
||||
##! from the notice log.
|
||||
|
||||
@load base/frameworks/notice
|
||||
@load base/frameworks/notice/weird
|
||||
|
||||
redef Notice::ignored_types += {
|
||||
## Only allow these to go in the weird log.
|
||||
Weird::Weird_Activity,
|
||||
};
|
|
@ -20,6 +20,10 @@ redef Software::vulnerable_versions += {
|
|||
# This adds signatures to detect cleartext forward and reverse windows shells.
|
||||
redef signature_files += "frameworks/signatures/detect-windows-shells.sig";
|
||||
|
||||
# Uncomment the following line to begin receiving (by default hourly) emails
|
||||
# containing all of your notices.
|
||||
# redef Notice::policy += { [$action = Notice::ACTION_ALARM, $priority = 0] };
|
||||
|
||||
# Load all of the scripts that detect software in various protocols.
|
||||
@load protocols/http/software
|
||||
#@load protocols/http/detect-webapps
|
||||
|
|
|
@ -58,6 +58,5 @@
|
|||
@load tuning/__load__.bro
|
||||
@load tuning/defaults/__load__.bro
|
||||
@load tuning/defaults/packet-fragments.bro
|
||||
@load tuning/defaults/remove-high-volume-notices.bro
|
||||
@load tuning/defaults/warnings.bro
|
||||
@load tuning/track-all-assets.bro
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue