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.
This commit is contained in:
Jon Siwek 2019-04-01 18:27:53 -07:00
parent 956674745b
commit 995368e68c
47 changed files with 289 additions and 152 deletions

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);