Merge remote-tracking branch 'origin/topic/jsiwek/bounded-weirds'

* origin/topic/jsiwek/bounded-weirds:
  Fix reporter net_weird API usage for unknown_mobility_type
  Remove variable content from weird names
This commit is contained in:
Johanna Amann 2019-04-03 09:44:53 -07:00
commit 99c89d55d6
47 changed files with 311 additions and 151 deletions

23
CHANGES
View file

@ -1,4 +1,27 @@
2.6-200 | 2019-04-03 09:44:53 -0700
* Fix reporter net_weird API usage for unknown_mobility_type
(Jon Siwek, Corelight)
* Remove variable content from weird names
This changes many weird names to move non-static content from the
weird name into the "addl" field to help ensure the total number of
weird names is reasonably bounded. Note the net_weird and flow_weird
events do not have an "addl" parameter, so information may no longer
be available in those cases -- to make it available again we'd need
to either (1) define new events that contain such a parameter, or
(2) change net_weird/flow_weird event signature (which is a breaking
change for user-code at the moment).
Also, the generic handling of binpac exceptions for analyzers which
to not otherwise catch and handle them has been changed from a Weird
to a ProtocolViolation.
Finally, a new "file_weird" event has been added for reporting
weirdness found during file analysis. (Jon Siwek, Corelight)
2.6-197 | 2019-04-03 09:08:58 -0700
* Make Syslog analyzer accept non-conformant messages that omit Priority.

46
NEWS
View file

@ -66,6 +66,8 @@ New Functionality
- Add support for SMB filenames in the intel framework.
- Added a new event for weirdness found via file analysis: ``file_weird``.
Changed Functionality
---------------------
@ -103,6 +105,50 @@ Changed Functionality
- The Broker C++ API has some breaking changes, see it's own NEWS file for
details on how to migrate old code.
- Some Weirds associated with generic binpac parsing exceptions in analyzers
that didn't otherwise handle them (like syslog, modbus, dnp3) are now
a ProtocolViolation instead
- Weird names that contained variable content and may result in an unbounded
number of weird names have been renamed to remove the variable content
(which has been made available in the "addl" field of conn_weirds):
- "unknown_dce_rpc_auth_type_%d" -> unknown_dce_rpc_auth_type
- "gtp_invalid_info_element_%d" -> gtp_invalid_info_element
- "unknown_netbios_type:" 0x%x -> unknown_netbios_type
- "excess_netbios_hdr_len" (%d > %d) -> excess_netbios_hdr_len
- "deficit_netbios_hdr_len" (%d > %d) -> deficit_netbios_hdr_len
- "bad_RPC_program (%d)" -> bad_RPC_program
- "unknown_MOUNT_request(%u)" -> unknown_MOUNT_request
- "unknown_NFS_request(%u)" -> unknown_NFS_request
- "RPC resync: discard %d bytes\n" -> RPC_resync
- "RPC_message_too_long (%d64)" -> RPC_message_too_long
- "socks5_unsupported_authentication_method_%d" -> socks5_unsupported_authentication_method
- "socks5_unsupported_authentication_%d_%d" -> socks5_unsupported_authentication
- "ssh_unknown_kex_algorithm=%s" -> ssh_unknown_kex_algorithm
- "Encountered unknown type in server name ssl extension: %d" -> ssl_ext_unknown_server_name_type
- "UDP_datagram_length_mismatch(%d!=%d)" -> UDP_datagram_length_mismatch
- "OPENSSL Could not parse OCSP request (fuid %s)" -> openssl_ocsp_request_parse_error
- "OPENSSL Could not parse OCSP response (fuid %s)" -> openssl_ocsp_response_parse_error
- "Could not parse X509 certificate (fuid %s)" -> x509_cert_parse_error
- "Certificate with invalid BasicConstraint. fuid %s" -> x509_invalid_basic_constraint
- "Could not parse subject alternative names. fuid %s" -> x509_san_parse_error
- "DNS-field does not contain an IA5String. fuid %s" -> x509_san_non_string
- "Weird IP address length %d in subject alternative name. fuid %s" -> x509_san_ip_length
- "Could not parse time in X509 certificate (fuid %s) -- UTCTime has wrong length" -> x509_utc_length
- "Could not parse UTC time in non-YY-format in X509 certificate (x509 %s)" -> x509_utc_format
- "Could not parse time in X509 certificate (fuid %s) -- Generalized time has wrong length" -> x509_gen_time_length
- "Invalid time type in X509 certificate (fuid %s)" -> x509_invalid_time_type
- "Could not parse time in X509 certificate (fuid %s) -- additional char after time" -> x509_time_add_char
- "Could not parse time in X509 certificate (fuid %s) -- not enough bytes remaining for offset" -> x509_time_offset_underflow
- "Could not parse time in X509 certificate (fuid %s) -- unknown offset type" -> x509_time_offset_type
- "X509::GetExtensionFromBIO: %s" -> x509_get_ext_from_bio
- "unknown_mobility_type_%d" -> unknown_mobility_type
- "unknown_routing_type_%d" -> unknown_routing_type
- "unknown_protocol_%d" -> unknown_protocol
- "unknown_gre_version_%d" -> unknown_gre_version
- "unknown_gre_protocol_%u16" -> unknown_gre_protocol
Removed Functionality
---------------------

View file

@ -1 +1 @@
2.6-197
2.6-200

2
doc

@ -1 +1 @@
Subproject commit 2e66f807daafe754e40571e3d2c10080b6db36cb
Subproject commit 5aa921f0f6ce2931e446a11f2a10cffb7f0dbc09

View file

@ -422,3 +422,13 @@ event net_weird(name: string)
local i = Info($ts=network_time(), $name=name);
weird(i);
}
event file_weird(name: string, f: fa_file, addl: string)
{
local i = Info($ts=network_time(), $name=name, $addl=f$id);
if ( addl != "" )
i$addl += fmt(": %s", addl);
weird(i);
}

View file

@ -319,6 +319,7 @@ set(bro_SRCS
UID.cc
Val.cc
Var.cc
WeirdState.cc
bsd-getopt-long.c
bro_inet_ntop.c
cq.c

View file

@ -1075,27 +1075,5 @@ void Connection::CheckFlowLabel(bool is_orig, uint32 flow_label)
bool Connection::PermitWeird(const char* name, uint64 threshold, uint64 rate,
double duration)
{
auto& state = weird_state[name];
++state.count;
if ( state.count <= threshold )
return true;
if ( state.count == threshold + 1)
state.sampling_start_time = network_time;
else
{
if ( network_time > state.sampling_start_time + duration )
{
state.sampling_start_time = 0;
state.count = 1;
return true;
}
}
auto num_above_threshold = state.count - threshold;
if ( rate )
return num_above_threshold % rate == 0;
else
return false;
return ::PermitWeird(weird_state, name, threshold, rate, duration);
}

View file

@ -17,6 +17,7 @@
#include "IPAddr.h"
#include "TunnelEncapsulation.h"
#include "UID.h"
#include "WeirdState.h"
#include "analyzer/Tag.h"
#include "analyzer/Analyzer.h"
@ -345,14 +346,7 @@ protected:
analyzer::pia::PIA* primary_PIA;
Bro::UID uid; // Globally unique connection ID.
struct WeirdState {
WeirdState() { count = 0; sampling_start_time = 0; }
uint64 count = 0;
double sampling_start_time = 0;
};
std::unordered_map<std::string, WeirdState> weird_state;
WeirdStateMap weird_state;
};
class ConnectionTimer : public Timer {

View file

@ -288,7 +288,7 @@ RecordVal* IPv6_Hdr::BuildRecordVal(VectorVal* chain) const
}
default:
reporter->Weird(fmt("unknown_mobility_type_%d", mob->ip6mob_type));
reporter->Weird("unknown_mobility_type");
break;
}
@ -553,7 +553,7 @@ void IPv6_Hdr_Chain::ProcessRoutingHeader(const struct ip6_rthdr* r, uint16 len)
#endif
default:
reporter->Weird(fmt("unknown_routing_type_%d", r->ip6r_type));
reporter->Weird(SrcAddr(), DstAddr(), "unknown_routing_type");
break;
}
}

View file

@ -13,6 +13,7 @@
#include "Timer.h"
#include "plugin/Plugin.h"
#include "plugin/Manager.h"
#include "file_analysis/File.h"
#ifdef SYSLOG_INT
extern "C" {
@ -213,12 +214,14 @@ void Reporter::Syslog(const char* fmt, ...)
va_end(ap);
}
void Reporter::WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* addl, const char* fmt_name, ...)
void Reporter::WeirdHelper(EventHandlerPtr event, Val* conn_val, file_analysis::File* f, const char* addl, const char* fmt_name, ...)
{
val_list* vl = new val_list(1);
if ( conn_val )
vl->append(conn_val);
else if ( f )
vl->append(f->GetVal()->Ref());
if ( addl )
vl->append(new StringVal(addl));
@ -339,7 +342,21 @@ void Reporter::Weird(const char* name)
return;
}
WeirdHelper(net_weird, 0, 0, "%s", name);
WeirdHelper(net_weird, 0, 0, 0, "%s", name);
}
void Reporter::Weird(file_analysis::File* f, const char* name, const char* addl)
{
UpdateWeirdStats(name);
if ( ! WeirdOnSamplingWhiteList(name) )
{
if ( ! f->PermitWeird(name, weird_sampling_threshold,
weird_sampling_rate, weird_sampling_duration) )
return;
}
WeirdHelper(file_weird, 0, f, addl, "%s", name);
}
void Reporter::Weird(Connection* conn, const char* name, const char* addl)
@ -353,7 +370,7 @@ void Reporter::Weird(Connection* conn, const char* name, const char* addl)
return;
}
WeirdHelper(conn_weird, conn->BuildConnVal(), addl, "%s", name);
WeirdHelper(conn_weird, conn->BuildConnVal(), 0, addl, "%s", name);
}
void Reporter::Weird(const IPAddr& orig, const IPAddr& resp, const char* name)

View file

@ -17,6 +17,7 @@
#include "IPAddr.h"
namespace analyzer { class Analyzer; }
namespace file_analysis { class File; }
class Connection;
class Location;
class Reporter;
@ -84,6 +85,7 @@ public:
// Report a traffic weirdness, i.e., an unexpected protocol situation
// that may lead to incorrectly processing a connnection.
void Weird(const char* name); // Raises net_weird().
void Weird(file_analysis::File* f, const char* name, const char* addl = ""); // Raises file_weird().
void Weird(Connection* conn, const char* name, const char* addl = ""); // Raises conn_weird().
void Weird(const IPAddr& orig, const IPAddr& resp, const char* name); // Raises flow_weird().
@ -238,7 +240,7 @@ private:
// The order if addl, name needs to be like that since fmt_name can
// contain format specifiers
void WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* addl, const char* fmt_name, ...) __attribute__((format(printf, 5, 6)));;
void WeirdHelper(EventHandlerPtr event, Val* conn_val, file_analysis::File* f, const char* addl, const char* fmt_name, ...) __attribute__((format(printf, 6, 7)));;
void WeirdFlowHelper(const IPAddr& orig, const IPAddr& resp, const char* fmt_name, ...) __attribute__((format(printf, 4, 5)));;
void UpdateWeirdStats(const char* name);
inline bool WeirdOnSamplingWhiteList(const char* name)

View file

@ -537,8 +537,7 @@ void NetSessions::DoNextPacket(double t, const Packet* pkt, const IP_Hdr* ip_hdr
if ( gre_version != 0 && gre_version != 1 )
{
Weird(fmt("unknown_gre_version_%d", gre_version), ip_hdr,
encapsulation);
Weird("unknown_gre_version", ip_hdr, encapsulation);
return;
}
@ -613,8 +612,7 @@ void NetSessions::DoNextPacket(double t, const Packet* pkt, const IP_Hdr* ip_hdr
else
{
// Not IPv4/IPv6 payload.
Weird(fmt("unknown_gre_protocol_%" PRIu16, proto_typ), ip_hdr,
encapsulation);
Weird("unknown_gre_protocol", ip_hdr, encapsulation);
return;
}
@ -747,7 +745,7 @@ void NetSessions::DoNextPacket(double t, const Packet* pkt, const IP_Hdr* ip_hdr
}
default:
Weird(fmt("unknown_protocol_%d", proto), pkt, encapsulation);
Weird("unknown_protocol", pkt, encapsulation);
return;
}

30
src/WeirdState.cc Normal file
View file

@ -0,0 +1,30 @@
#include "WeirdState.h"
#include "Net.h"
bool PermitWeird(WeirdStateMap& wsm, const char* name, uint64_t threshold,
uint64_t rate, double duration)
{
auto& state = wsm[name];
++state.count;
if ( state.count <= threshold )
return true;
if ( state.count == threshold + 1)
state.sampling_start_time = network_time;
else
{
if ( network_time > state.sampling_start_time + duration )
{
state.sampling_start_time = 0;
state.count = 1;
return true;
}
}
auto num_above_threshold = state.count - threshold;
if ( rate )
return num_above_threshold % rate == 0;
else
return false;
}

21
src/WeirdState.h Normal file
View file

@ -0,0 +1,21 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef WEIRDSTATE_H
#define WEIRDSTATE_H
#include <string>
#include <unordered_map>
struct WeirdState {
WeirdState() { count = 0; sampling_start_time = 0; }
uint64_t count = 0;
double sampling_start_time = 0;
};
using WeirdStateMap = std::unordered_map<std::string, WeirdState>;
bool PermitWeird(WeirdStateMap& wsm, const char* name, uint64_t threshold,
uint64_t rate, double duration);
#endif // WEIRDSTATE_H

View file

@ -223,7 +223,7 @@ void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, uint64 seq,
}
catch ( binpac::Exception const &e )
{
Weird(e.c_msg());
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
}
}
}
@ -246,7 +246,7 @@ void Analyzer::NextStream(int len, const u_char* data, bool is_orig)
}
catch ( binpac::Exception const &e )
{
Weird(e.c_msg());
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
}
}
}
@ -269,7 +269,7 @@ void Analyzer::NextUndelivered(uint64 seq, int len, bool is_orig)
}
catch ( binpac::Exception const &e )
{
Weird(e.c_msg());
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
}
}
}

View file

@ -126,6 +126,4 @@ void BitTorrent_Analyzer::DeliverWeird(const char* msg, bool orig)
vl->append(new StringVal(msg));
ConnectionEvent(bittorrent_peer_weird, vl);
}
else
Weird(msg);
}

View file

@ -253,8 +253,6 @@ void BitTorrentTracker_Analyzer::DeliverWeird(const char* msg, bool orig)
vl->append(new StringVal(msg));
ConnectionEvent(bt_tracker_weird, vl);
}
else
Weird(msg);
}
bool BitTorrentTracker_Analyzer::ParseRequest(char* line)
@ -326,8 +324,11 @@ bool BitTorrentTracker_Analyzer::ParseRequest(char* line)
case BTT_REQ_DONE:
if ( *line )
DeliverWeird(fmt("Got post request data: %s\n", line),
true);
{
auto msg = fmt("Got post request data: %s\n", line);
Weird("bittorrent_tracker_data_post_request", msg);
DeliverWeird(msg, true);
}
break;
default:

View file

@ -40,7 +40,6 @@ flow BitTorrent_Flow(is_orig: bool) {
if ( pstrlen != 19 ||
memcmp("BitTorrent protocol", pstr.begin(), 19) )
{
connection()->bro_analyzer()->Weird(fmt("BitTorrent: invalid handshake (pstrlen: %hhu, pstr: %.*s)", pstrlen, 19, pstr.begin()));
throw Exception("invalid handshake");
}

View file

@ -43,7 +43,7 @@ refine connection DCE_RPC_Conn += {
ntlm->DeliverStream(${auth.blob}.length(), ${auth.blob}.begin(), is_orig);
break;
default:
bro_analyzer()->Weird(fmt("unknown_dce_rpc_auth_type_%d",${auth.type}));
bro_analyzer()->Weird("unknown_dce_rpc_auth_type", fmt("%d", ${auth.type}));
break;
}

View file

@ -319,7 +319,7 @@ void CreatePDP_Request(const BroAnalyzer& a, const GTPv1_Header* pdu)
rv->Assign(21, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
a->Weird("gtp_invalid_info_element", fmt("%d", (*v)[i]->type()));
break;
}
}
@ -388,7 +388,7 @@ void CreatePDP_Response(const BroAnalyzer& a, const GTPv1_Header* pdu)
rv->Assign(12, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
a->Weird("gtp_invalid_info_element", fmt("%d", (*v)[i]->type()));
break;
}
}
@ -466,7 +466,7 @@ void UpdatePDP_Request(const BroAnalyzer& a, const GTPv1_Header* pdu)
rv->Assign(15, BuildEndUserAddr(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
a->Weird("gtp_invalid_info_element", fmt("%d", (*v)[i]->type()));
break;
}
}
@ -526,7 +526,7 @@ void UpdatePDP_Response(const BroAnalyzer& a, const GTPv1_Header* pdu)
rv->Assign(9, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
a->Weird("gtp_invalid_info_element", fmt("%d", (*v)[i]->type()));
break;
}
}
@ -560,7 +560,7 @@ void DeletePDP_Request(const BroAnalyzer& a, const GTPv1_Header* pdu)
rv->Assign(2, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
a->Weird("gtp_invalid_info_element", fmt("%d", (*v)[i]->type()));
break;
}
}
@ -591,7 +591,7 @@ void DeletePDP_Response(const BroAnalyzer& a, const GTPv1_Header* pdu)
rv->Assign(1, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
a->Weird("gtp_invalid_info_element", fmt("%d", (*v)[i]->type()));
break;
}
}

View file

@ -97,7 +97,7 @@ int NetbiosSSN_Interpreter::ParseMessage(unsigned int type, unsigned int flags,
return ParseDatagram(data, len, is_query);
default:
analyzer->Weird(fmt("unknown_netbios_type: 0x%x", type));
analyzer->Weird("unknown_netbios_type", fmt("0x%x", type));
return 1;
}
}
@ -143,7 +143,7 @@ int NetbiosSSN_Interpreter::ParseMessageTCP(const u_char* data, int len,
NetbiosSSN_RawMsgHdr hdr(data, len);
if ( hdr.length > unsigned(len) )
analyzer->Weird(fmt("excess_netbios_hdr_len (%d > %d)",
analyzer->Weird("excess_netbios_hdr_len", fmt("(%d > %d)",
hdr.length, len));
else if ( hdr.length < unsigned(len) )
@ -162,12 +162,12 @@ int NetbiosSSN_Interpreter::ParseMessageUDP(const u_char* data, int len,
NetbiosDGM_RawMsgHdr hdr(data, len);
if ( unsigned(hdr.length-14) > unsigned(len) )
analyzer->Weird(fmt("excess_netbios_hdr_len (%d > %d)",
analyzer->Weird("excess_netbios_hdr_len", fmt("(%d > %d)",
hdr.length, len));
else if ( hdr.length < unsigned(len) )
{
analyzer->Weird(fmt("deficit_netbios_hdr_len (%d < %d)",
analyzer->Weird("deficit_netbios_hdr_len", fmt("(%d < %d)",
hdr.length, len));
len = hdr.length;
}

View file

@ -17,7 +17,7 @@ using namespace analyzer::rpc;
int MOUNT_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
{
if ( c->Program() != 100005 )
Weird(fmt("bad_RPC_program (%d)", c->Program()));
Weird("bad_RPC_program", fmt("%d", c->Program()));
uint32 proc = c->Proc();
// The call arguments, depends on the call type obviously ...
@ -49,7 +49,7 @@ int MOUNT_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
n = 0;
}
else
Weird(fmt("unknown_MOUNT_request(%u)", proc));
Weird("unknown_MOUNT_request", fmt("%u", proc));
// Return 1 so that replies to unprocessed calls will still
// be processed, and the return status extracted.

View file

@ -17,7 +17,7 @@ using namespace analyzer::rpc;
int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
{
if ( c->Program() != 100003 )
Weird(fmt("bad_RPC_program (%d)", c->Program()));
Weird("bad_RPC_program", fmt("%d", c->Program()));
uint32 proc = c->Proc();
// The call arguments, depends on the call type obviously ...
@ -103,7 +103,7 @@ int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
n = 0;
}
else
Weird(fmt("unknown_NFS_request(%u)", proc));
Weird("unknown_NFS_request", fmt("%u", proc));
// Return 1 so that replies to unprocessed calls will still
// be processed, and the return status extracted.

View file

@ -371,9 +371,9 @@ void RPC_Interpreter::Event_RPC_Reply(uint32_t xid, BifEnum::rpc_status status,
}
}
void RPC_Interpreter::Weird(const char* msg)
void RPC_Interpreter::Weird(const char* msg, const char* addl)
{
analyzer->Weird(msg);
analyzer->Weird(msg, addl);
}
@ -532,9 +532,7 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
DEBUG_MSG("%.6f RPC resync: "
"discard small pieces: %d\n",
network_time, len);
Conn()->Weird(
fmt("RPC resync: discard %d bytes\n",
len));
Conn()->Weird("RPC_resync", fmt("discard %d bytes\n", len));
}
NeedResync();
@ -677,7 +675,7 @@ void Contents_RPC::DeliverStream(int len, const u_char* data, bool orig)
// network_time, IsOrig(), marker, last_frag, msg_buf.GetExpected(), msg_buf.GetProcessed(), len);
if ( ! msg_buf.AddToExpected(marker) )
Conn()->Weird(fmt("RPC_message_too_long (%" PRId64 ")" , msg_buf.GetExpected()));
Conn()->Weird("RPC_message_too_long", fmt("%" PRId64, msg_buf.GetExpected()));
if ( last_frag )
state = WAIT_FOR_LAST_DATA;

View file

@ -123,7 +123,7 @@ protected:
void Event_RPC_Call(RPC_CallInfo* c);
void Event_RPC_Reply(uint32_t xid, BifEnum::rpc_status status, int reply_len);
void Weird(const char* name);
void Weird(const char* name, const char* addl = "");
PDict(RPC_CallInfo) calls;
analyzer::Analyzer* analyzer;

View file

@ -161,13 +161,13 @@ refine connection SOCKS_Conn += {
function socks5_unsupported_authentication_method(auth_method: uint8): bool
%{
reporter->Weird(bro_analyzer()->Conn(), fmt("socks5_unsupported_authentication_method_%d", auth_method));
reporter->Weird(bro_analyzer()->Conn(), "socks5_unsupported_authentication_method", fmt("%d", auth_method));
return true;
%}
function socks5_unsupported_authentication_version(auth_method: uint8, version: uint8): bool
%{
reporter->Weird(bro_analyzer()->Conn(), fmt("socks5_unsupported_authentication_%d_%d", auth_method, version));
reporter->Weird(bro_analyzer()->Conn(), "socks5_unsupported_authentication", fmt("method %d, version %d", auth_method, version));
return true;
%}

View file

@ -415,7 +415,7 @@ refine connection SSH_Conn += {
return true;
bro_analyzer()->Weird(fmt("ssh_unknown_kex_algorithm=%s", c_str(kex_algorithm_)));
bro_analyzer()->Weird("ssh_unknown_kex_algorithm", c_str(kex_algorithm_));
return true;
}

View file

@ -172,7 +172,7 @@ refine connection Handshake_Conn += {
ServerName* servername = (*list)[i];
if ( servername->name_type() != 0 )
{
bro_analyzer()->Weird(fmt("Encountered unknown type in server name ssl extension: %d", servername->name_type()));
bro_analyzer()->Weird("ssl_ext_unknown_server_name_type", fmt("%d", servername->name_type()));
continue;
}

View file

@ -124,7 +124,7 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
int ulen = ntohs(up->uh_ulen);
if ( ulen != len )
Weird(fmt("UDP_datagram_length_mismatch(%d!=%d)", ulen, len));
Weird("UDP_datagram_length_mismatch", fmt("%d != %d", ulen, len));
len -= sizeof(struct udphdr);
ulen -= sizeof(struct udphdr);

View file

@ -421,7 +421,7 @@ event conn_stats%(c: connection, os: endpoint_stats, rs: endpoint_stats%);
##
## addl: Optional additional context further describing the situation.
##
## .. bro:see:: flow_weird net_weird
## .. bro:see:: flow_weird net_weird file_weird
##
## .. note:: "Weird" activity is much more common in real-world network traffic
## than one would intuitively expect. While in principle, any protocol
@ -444,7 +444,7 @@ event conn_weird%(name: string, c: connection, addl: string%);
##
## dst: The destination address corresponding to the activity.
##
## .. bro:see:: conn_weird net_weird
## .. bro:see:: conn_weird net_weird file_weird
##
## .. note:: "Weird" activity is much more common in real-world network traffic
## than one would intuitively expect. While in principle, any protocol
@ -462,7 +462,7 @@ event flow_weird%(name: string, src: addr, dst: addr%);
## scripts use this name in filtering policies that specify which
## "weirds" are worth reporting.
##
## .. bro:see:: flow_weird
## .. bro:see:: flow_weird file_weird
##
## .. note:: "Weird" activity is much more common in real-world network traffic
## than one would intuitively expect. While in principle, any protocol
@ -470,6 +470,27 @@ event flow_weird%(name: string, src: addr, dst: addr%);
## endpoint's implementation interprets an RFC quite liberally.
event net_weird%(name: string%);
## Generated for unexpected activity that is tied to a file.
## When Bro's packet analysis encounters activity that
## does not conform to a protocol's specification, it raises one of the
## ``*_weird`` events to report that.
##
## name: A unique name for the specific type of "weird" situation. Bro's default
## scripts use this name in filtering policies that specify which
## "weirds" are worth reporting.
##
## f: The corresponding file.
##
## addl: Additional information related to the weird.
##
## .. bro:see:: flow_weird net_weird conn_weird
##
## .. note:: "Weird" activity is much more common in real-world network traffic
## than one would intuitively expect. While in principle, any protocol
## violation could be an attack attempt, it's much more likely that an
## endpoint's implementation interprets an RFC quite liberally.
event file_weird%(name: string, f: fa_file, addl: string%);
## Generated regularly for the purpose of profiling Bro's processing. This event
## is raised for every :bro:id:`load_sample_freq` packet. For these packets,
## Bro records script-level functions executed during their processing as well

View file

@ -649,3 +649,9 @@ void File::FileEvent(EventHandlerPtr h, val_list* vl)
analyzers.DrainModifications();
}
}
bool File::PermitWeird(const char* name, uint64 threshold, uint64 rate,
double duration)
{
return ::PermitWeird(weird_state, name, threshold, rate, duration);
}

View file

@ -13,6 +13,7 @@
#include "Tag.h"
#include "AnalyzerSet.h"
#include "BroString.h"
#include "WeirdState.h"
namespace file_analysis {
@ -192,6 +193,13 @@ public:
*/
bool SetMime(const string& mime_type);
/**
* Whether to permit a weird to carry on through the full reporter/weird
* framework.
*/
bool PermitWeird(const char* name, uint64 threshold, uint64 rate,
double duration);
protected:
friend class Manager;
friend class FileReassembler;
@ -325,6 +333,8 @@ protected:
BroString::CVec chunks;
} bof_buffer; /**< Beginning of file buffer. */
WeirdStateMap weird_state;
static int id_idx;
static int parent_id_idx;
static int source_idx;

View file

@ -160,11 +160,11 @@ bool file_analysis::OCSP::EndOfFile()
if (!req)
{
reporter->Weird(fmt("OPENSSL Could not parse OCSP request (fuid %s)", GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "openssl_ocsp_request_parse_error");
return false;
}
ParseRequest(req, GetFile()->GetID().c_str());
ParseRequest(req);
OCSP_REQUEST_free(req);
}
else
@ -173,12 +173,12 @@ bool file_analysis::OCSP::EndOfFile()
if (!resp)
{
reporter->Weird(fmt("OPENSSL Could not parse OCSP response (fuid %s)", GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "openssl_ocsp_response_parse_error");
return false;
}
OCSP_RESPVal* resp_val = new OCSP_RESPVal(resp); // resp_val takes ownership
ParseResponse(resp_val, GetFile()->GetID().c_str());
ParseResponse(resp_val);
Unref(resp_val);
}
@ -412,7 +412,7 @@ static uint64 parse_request_version(OCSP_REQUEST* req)
}
#endif
void file_analysis::OCSP::ParseRequest(OCSP_REQUEST* req, const char* fid)
void file_analysis::OCSP::ParseRequest(OCSP_REQUEST* req)
{
char buf[OCSP_STRING_BUF_SIZE]; // we need a buffer for some of the openssl functions
memset(buf, 0, sizeof(buf));
@ -453,7 +453,7 @@ void file_analysis::OCSP::ParseRequest(OCSP_REQUEST* req, const char* fid)
BIO_free(bio);
}
void file_analysis::OCSP::ParseResponse(OCSP_RESPVal *resp_val, const char* fid)
void file_analysis::OCSP::ParseResponse(OCSP_RESPVal *resp_val)
{
OCSP_RESPONSE *resp = resp_val->GetResp();
//OCSP_RESPBYTES *resp_bytes = resp->responseBytes;
@ -532,7 +532,7 @@ void file_analysis::OCSP::ParseResponse(OCSP_RESPVal *resp_val, const char* fid)
produced_at = OCSP_resp_get0_produced_at(basic_resp);
#endif
vl->append(new Val(GetTimeFromAsn1(produced_at, fid, reporter), TYPE_TIME));
vl->append(new Val(GetTimeFromAsn1(produced_at, GetFile(), reporter), TYPE_TIME));
// responses
@ -579,7 +579,7 @@ void file_analysis::OCSP::ParseResponse(OCSP_RESPVal *resp_val, const char* fid)
// revocation time and reason if revoked
if ( status == V_OCSP_CERTSTATUS_REVOKED )
{
rvl->append(new Val(GetTimeFromAsn1(revoke_time, fid, reporter), TYPE_TIME));
rvl->append(new Val(GetTimeFromAsn1(revoke_time, GetFile(), reporter), TYPE_TIME));
if ( reason != OCSP_REVOKED_STATUS_NOSTATUS )
{
@ -596,12 +596,12 @@ void file_analysis::OCSP::ParseResponse(OCSP_RESPVal *resp_val, const char* fid)
}
if ( this_update )
rvl->append(new Val(GetTimeFromAsn1(this_update, fid, reporter), TYPE_TIME));
rvl->append(new Val(GetTimeFromAsn1(this_update, GetFile(), reporter), TYPE_TIME));
else
rvl->append(new Val(0.0, TYPE_TIME));
if ( next_update )
rvl->append(new Val(GetTimeFromAsn1(next_update, fid, reporter), TYPE_TIME));
rvl->append(new Val(GetTimeFromAsn1(next_update, GetFile(), reporter), TYPE_TIME));
else
rvl->append(new Val(0.0, TYPE_TIME));

View file

@ -29,8 +29,8 @@ protected:
OCSP(RecordVal* args, File* file, bool request);
private:
void ParseResponse(OCSP_RESPVal*, const char* fid = 0);
void ParseRequest(OCSP_REQUEST*, const char* fid = 0);
void ParseResponse(OCSP_RESPVal*);
void ParseRequest(OCSP_REQUEST*);
void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) override;
std::string ocsp_data;

View file

@ -47,14 +47,14 @@ bool file_analysis::X509::EndOfFile()
::X509* ssl_cert = d2i_X509(NULL, &cert_char, cert_data.size());
if ( ! ssl_cert )
{
reporter->Weird(fmt("Could not parse X509 certificate (fuid %s)", GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "x509_cert_parse_error");
return false;
}
X509Val* cert_val = new X509Val(ssl_cert); // cert_val takes ownership of ssl_cert
// parse basic information into record.
RecordVal* cert_record = ParseCertificate(cert_val, GetFile()->GetID().c_str());
RecordVal* cert_record = ParseCertificate(cert_val, GetFile());
// and send the record on to scriptland
val_list* vl = new val_list();
@ -86,7 +86,7 @@ bool file_analysis::X509::EndOfFile()
return false;
}
RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char* fid)
RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, File* f)
{
::X509* ssl_cert = cert_val->GetCertificate();
@ -133,8 +133,8 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char*
pX509Cert->Assign(3, new StringVal(len, buf));
BIO_free(bio);
pX509Cert->Assign(5, new Val(GetTimeFromAsn1(X509_get_notBefore(ssl_cert), fid, reporter), TYPE_TIME));
pX509Cert->Assign(6, new Val(GetTimeFromAsn1(X509_get_notAfter(ssl_cert), fid, reporter), TYPE_TIME));
pX509Cert->Assign(5, new Val(GetTimeFromAsn1(X509_get_notBefore(ssl_cert), f, reporter), TYPE_TIME));
pX509Cert->Assign(6, new Val(GetTimeFromAsn1(X509_get_notAfter(ssl_cert), f, reporter), TYPE_TIME));
// we only read 255 bytes because byte 256 is always 0.
// if the string is longer than 255, that will be our null-termination,
@ -236,7 +236,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex)
}
else
reporter->Weird(fmt("Certificate with invalid BasicConstraint. fuid %s", GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "x509_invalid_basic_constraint");
}
void file_analysis::X509::ParseExtensionsSpecific(X509_EXTENSION* ex, bool global, ASN1_OBJECT* ext_asn, const char* oid)
@ -266,7 +266,7 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext)
GENERAL_NAMES *altname = (GENERAL_NAMES*)X509V3_EXT_d2i(ext);
if ( ! altname )
{
reporter->Weird(fmt("Could not parse subject alternative names. fuid %s", GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "x509_san_parse_error");
return;
}
@ -286,7 +286,7 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext)
{
if ( ASN1_STRING_type(gen->d.ia5) != V_ASN1_IA5STRING )
{
reporter->Weird(fmt("DNS-field does not contain an IA5String. fuid %s", GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "x509_san_non_string");
continue;
}
@ -337,7 +337,7 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext)
else
{
reporter->Weird(fmt("Weird IP address length %d in subject alternative name. fuid %s", gen->d.ip->length, GetFile()->GetID().c_str()));
reporter->Weird(GetFile(), "x509_san_ip_length", fmt("%d", gen->d.ip->length));
continue;
}
}

View file

@ -79,13 +79,13 @@ public:
*
* @param cert_val The certificate to converts.
*
* @param fid A file ID associated with the certificate, if any
* @param f A file associated with the certificate, if any
* (primarily for error reporting).
*
* @param Returns the new record value and passes ownership to
* caller.
*/
static RecordVal* ParseCertificate(X509Val* cert_val, const char* fid = 0);
static RecordVal* ParseCertificate(X509Val* cert_val, File* file = 0);
static file_analysis::Analyzer* Instantiate(RecordVal* args, File* file)
{ return new X509(args, file); }

View file

@ -20,9 +20,16 @@ X509Common::X509Common(file_analysis::Tag arg_tag, RecordVal* arg_args, File* ar
{
}
double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid, Reporter* reporter)
static void EmitWeird(const char* name, File* file, const char* addl = "")
{
if ( file )
reporter->Weird(file, name, addl);
else
reporter->Weird(name);
}
double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, File* f, Reporter* reporter)
{
const char *fid = arg_fid ? arg_fid : "";
time_t lResult = 0;
char lBuffer[26];
@ -35,14 +42,14 @@ double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid,
{
if ( remaining < 11 || remaining > 17 )
{
reporter->Weird(fmt("Could not parse time in X509 certificate (fuid %s) -- UTCTime has wrong length", fid));
EmitWeird("x509_utc_length", f);
return 0;
}
if ( pString[remaining-1] != 'Z' )
{
// not valid according to RFC 2459 4.1.2.5.1
reporter->Weird(fmt("Could not parse UTC time in non-YY-format in X509 certificate (x509 %s)", fid));
EmitWeird("x509_utc_format", f);
return 0;
}
@ -71,7 +78,7 @@ double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid,
if ( remaining < 12 || remaining > 23 )
{
reporter->Weird(fmt("Could not parse time in X509 certificate (fuid %s) -- Generalized time has wrong length", fid));
EmitWeird("x509_gen_time_length", f);
return 0;
}
@ -82,7 +89,7 @@ double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid,
}
else
{
reporter->Weird(fmt("Invalid time type in X509 certificate (fuid %s)", fid));
EmitWeird("x509_invalid_time_type", f);
return 0;
}
@ -115,7 +122,7 @@ double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid,
else
{
reporter->Weird(fmt("Could not parse time in X509 certificate (fuid %s) -- additional char after time", fid));
EmitWeird("x509_time_add_char", f);
return 0;
}
@ -130,13 +137,13 @@ double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid,
{
if ( remaining < 5 )
{
reporter->Weird(fmt("Could not parse time in X509 certificate (fuid %s) -- not enough bytes remaining for offset", fid));
EmitWeird("x509_time_offset_underflow", f);
return 0;
}
if ((*pString != '+') && (*pString != '-'))
{
reporter->Weird(fmt("Could not parse time in X509 certificate (fuid %s) -- unknown offset type", fid));
EmitWeird("x509_time_offset_type", f);
return 0;
}
@ -249,7 +256,7 @@ void file_analysis::X509Common::ParseExtension(X509_EXTENSION* ex, EventHandlerP
}
}
StringVal* ext_val = GetExtensionFromBIO(bio);
StringVal* ext_val = GetExtensionFromBIO(bio, GetFile());
if ( ! ext_val )
ext_val = new StringVal(0, "");
@ -282,7 +289,7 @@ void file_analysis::X509Common::ParseExtension(X509_EXTENSION* ex, EventHandlerP
ParseExtensionsSpecific(ex, global, ext_asn, oid);
}
StringVal* file_analysis::X509Common::GetExtensionFromBIO(BIO* bio)
StringVal* file_analysis::X509Common::GetExtensionFromBIO(BIO* bio, File* f)
{
BIO_flush(bio);
ERR_clear_error();
@ -292,7 +299,7 @@ StringVal* file_analysis::X509Common::GetExtensionFromBIO(BIO* bio)
{
char tmp[120];
ERR_error_string_n(ERR_get_error(), tmp, sizeof(tmp));
reporter->Weird(fmt("X509::GetExtensionFromBIO: %s", tmp));
EmitWeird("x509_get_ext_from_bio", f, tmp);
BIO_free_all(bio);
return 0;
}

View file

@ -25,11 +25,13 @@ public:
* @param bio the OpenSSL BIO to read. It will be freed by the function,
* including when an error occurs.
*
* @param f an associated file, if any (used for error reporting).
*
* @return The X509 extension value.
*/
static StringVal* GetExtensionFromBIO(BIO* bio);
static StringVal* GetExtensionFromBIO(BIO* bio, File* f = 0);
static double GetTimeFromAsn1(const ASN1_TIME* atime, const char* arg_fid, Reporter* reporter);
static double GetTimeFromAsn1(const ASN1_TIME* atime, File* f, Reporter* reporter);
protected:
X509Common(file_analysis::Tag arg_tag, RecordVal* arg_args, File* arg_file);

View file

@ -127,6 +127,27 @@ function Reporter::conn_weird%(name: string, c: connection, addl: string &defaul
return val_mgr->GetBool(1);
%}
## Generates a "file" weird.
##
## name: the name of the weird.
##
## f: the file associated with the weird.
##
## addl: additional information to accompany the weird.
##
## Returns: true if the file was still valid, else false.
function Reporter::file_weird%(name: string, f: fa_file, addl: string &default=""%): bool
%{
auto fuid = f->AsRecordVal()->Lookup(0)->AsStringVal();
auto file = file_mgr->LookupFile(fuid->CheckString());
if ( ! file )
return val_mgr->GetBool(0);
reporter->Weird(file, name->CheckString(), addl->CheckString());
return val_mgr->GetBool(1);
%}
## Gets the weird sampling whitelist
##
## Returns: Current weird sampling whitelist

View file

@ -6,5 +6,5 @@
#open 2012-04-05-21-56-51
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer
#types time string addr port addr port string string bool string
1333663011.602839 - - - - - unknown_protocol_135 - F bro
1333663011.602839 - - - - - unknown_protocol - F bro
#close 2012-04-05-21-56-51

View file

@ -3,7 +3,7 @@
#empty_field (empty)
#unset_field -
#path conn
#open 2016-07-13-16-16-30
#open 2019-04-02-01-01-40
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
1093521678.945447 CHhAvVGS1DHFjwGM9 10.0.0.57 2387 10.0.0.3 502 tcp - 0.000493 0 0 SF - - 0 FafA 2 80 2 80 -
@ -13,6 +13,6 @@
1093522946.554059 CUM0KZ3MLUfNB0cl11 10.0.0.57 2585 10.0.0.8 502 tcp - 76.561880 926 0 SF - - 0 ShADafF 8 1254 7 288 -
1093523065.562221 CmES5u32sYpV7JYN 10.0.0.8 502 10.0.0.57 4446 tcp - 155.114237 128 0 SF - - 0 ShADaFf 16 776 15 608 -
1153491879.610371 CP5puj4I8PtEU4qzYg 192.168.66.235 2582 166.161.16.230 502 tcp - 2.905078 0 0 S0 - - 0 S 2 96 0 0 -
1153491888.530306 C37jN32gN3y3AZzyf6 192.168.66.235 2582 166.161.16.230 502 tcp modbus 85.560847 1692 1278 S1 - - 0 ShADad 167 8380 181 8522 -
1153491888.530306 C37jN32gN3y3AZzyf6 192.168.66.235 2582 166.161.16.230 502 tcp - 85.560847 1692 1278 S1 - - 0 ShADad 167 8380 181 8522 -
1342774499.588269 C3eiCBGOLw3VtHfOj 10.1.1.234 51411 10.10.5.85 502 tcp modbus 2100.811351 237936 4121200 S2 - - 0 ShADdaF 39659 2300216 20100 5166412 -
#close 2016-07-13-16-16-33
#close 2019-04-02-01-01-42

View file

@ -1,13 +0,0 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path weird
#open 2016-07-13-16-16-39
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer
#types time string addr port addr port string string bool string
1153491909.414066 - - - - - truncated_IP - F bro
1153491912.529443 CHhAvVGS1DHFjwGM9 192.168.66.235 2582 166.161.16.230 502 binpac exception: out_of_bound: WriteSingleRegisterRequest: 4 > 0 - F bro
1153491920.661039 CHhAvVGS1DHFjwGM9 192.168.66.235 2582 166.161.16.230 502 TCP_ack_underflow_or_misorder - F bro
1153491929.715910 CHhAvVGS1DHFjwGM9 192.168.66.235 2582 166.161.16.230 502 TCP_seq_underflow_or_misorder - F bro
#close 2016-07-13-16-16-39

View file

@ -1,10 +0,0 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path weird
#open 2018-08-30-14-12-39
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer
#types time string addr port addr port string string bool string
1445502056.228889 CHhAvVGS1DHFjwGM9 192.168.2.166 1987 192.168.88.95 502 binpac exception: out_of_bound: ReadWriteMultipleRegistersRequest:write_register_values: 16932 > 191 - F bro
#close 2018-08-30-14-12-39

View file

@ -7,6 +7,7 @@
# @TEST-EXEC: btest-diff coverage
# @TEST-EXEC: btest-diff conn.log
redef DPD::ignore_violations_after = 1;
event modbus_message(c: connection, headers: ModbusHeaders, is_orig: bool)
{

View file

@ -1,10 +1,8 @@
# @TEST-EXEC: bro -r $TRACES/modbus/fuzz-72.trace
# @TEST-EXEC: btest-diff modbus.log
# @TEST-EXEC: btest-diff weird.log
# The pcap has a flow with some fuzzed modbus traffic in it that should cause
# the binpac-generated analyzer code to throw a binpac::ExceptionOutOfBound.
# This should be correctly caught as a type of binpac::Exception and the
# binpac::ModbusTCP::Exception type that's defined as part of the analyzer
# shouldn't interfere with that handling and definitely shouldn't crash bro.
# A weird is currently emitted for parsing exceptions.

View file

@ -12,4 +12,3 @@
# data buffer.
# @TEST-EXEC: bro -r $TRACES/modbus/4SICS-GeekLounge-151022-min.pcap
# @TEST-EXEC: btest-diff weird.log

View file

@ -7,3 +7,5 @@
@load protocols/modbus/known-masters-slaves.bro
@load protocols/modbus/track-memmap.bro
redef DPD::ignore_violations_after = 1;