Feb 15th 2023 update

This commit is contained in:
Ned Wright
2023-02-15 19:09:38 +00:00
parent f7934cd09d
commit 6a9b33ff93
159 changed files with 16474 additions and 2096 deletions

View File

@@ -22,6 +22,8 @@
using namespace std;
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
string AssetMatcher::ctx_key = "asset_id";
AssetMatcher::AssetMatcher(const vector<string> &params)
@@ -36,5 +38,15 @@ AssetMatcher::evalVariable() const
I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>();
auto bc_asset_id_ctx = env->get<GenericConfigId>(AssetMatcher::ctx_key);
if (bc_asset_id_ctx.ok()) {
dbgTrace(D_RULEBASE_CONFIG)
<< "Asset ID: "
<< asset_id
<< "; Current set assetId context: "
<< *bc_asset_id_ctx;
} else {
dbgTrace(D_RULEBASE_CONFIG) << "Asset ID: " << asset_id << ". Empty context";
}
return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id;
}

View File

@@ -95,6 +95,8 @@ MatchQuery::load(cereal::JSONInputArchive &archive_in)
is_specific_label = false;
}
}
is_ignore_keyword = (key == "indicator");
if (condition_type != Conditions::Exist) {
archive_in(cereal::make_nvp("value", value));
for(const auto &val: value) {
@@ -221,23 +223,34 @@ MatchQuery::getAllKeys() const
}
bool
MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_pairs) const
MatchQuery::matchAttributes(
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords ) const
{
if (type == MatchType::Condition) {
auto key_value_pair = key_value_pairs.find(key);
if (key_value_pair == key_value_pairs.end()) {
dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key;
return false;
}
return matchAttributes(key_value_pair->second);
return matchAttributes(key_value_pair->second, matched_override_keywords);
} else if (type == MatchType::Operator && operator_type == Operators::And) {
for (const MatchQuery &inner_match: items) {
if (!inner_match.matchAttributes(key_value_pairs)) return false;
if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords)) {
return false;
}
}
return true;
} else if (type == MatchType::Operator && operator_type == Operators::Or) {
// With 'or' condition, evaluate matched override keywords first and add the ones that were fully matched
set<string> inner_override_keywords;
for (const MatchQuery &inner_match: items) {
if (inner_match.matchAttributes(key_value_pairs)) return true;
inner_override_keywords.clear();
if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords)) {
matched_override_keywords.insert(inner_override_keywords.begin(), inner_override_keywords.end());
return true;
}
}
return false;
} else {
@@ -246,18 +259,39 @@ MatchQuery::matchAttributes(const unordered_map<string, set<string>> &key_value_
return false;
}
MatchQuery::MatchResult
MatchQuery::getMatch( const unordered_map<string, set<string>> &key_value_pairs) const
{
MatchQuery::MatchResult matches;
matches.matched_keywords = make_shared<set<string>>();
matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords);
return matches;
}
bool
MatchQuery::matchAttributes(const set<string> &values) const
MatchQuery::matchAttributes(
const unordered_map<string, set<string>> &key_value_pairs) const
{
return getMatch(key_value_pairs).is_match;
}
bool
MatchQuery::matchAttributes(
const set<string> &values,
set<string> &matched_override_keywords) const
{
auto &type = condition_type;
bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn;
bool match = isRegEx() ? matchAttributesRegEx(values) : matchAttributesString(values);
bool match = isRegEx() ? matchAttributesRegEx(values, matched_override_keywords) : matchAttributesString(values);
return negate ? !match : match;
}
bool
MatchQuery::matchAttributesRegEx(const set<string> &values) const
MatchQuery::matchAttributesRegEx(
const set<string> &values,
set<string> &matched_override_keywords) const
{
bool res = false;
boost::cmatch value_matcher;
for (const boost::regex &val_regex : regex_values) {
for (const string &requested_match_value : values) {
@@ -268,11 +302,16 @@ MatchQuery::matchAttributesRegEx(const set<string> &values) const
value_matcher,
val_regex))
{
return true;
res = true;
if (is_ignore_keyword) {
matched_override_keywords.insert(requested_match_value);
} else {
return res;
}
}
}
}
return false;
return res;
}
bool

View File

@@ -108,19 +108,50 @@ ParameterException::load(cereal::JSONInputArchive &archive_in)
}
set<ParameterBehavior>
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
ParameterException::getBehavior(
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords) const
{
set<ParameterBehavior> matched_behaviors;
matched_override_keywords.clear();
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
for (const MatchBehaviorPair &match_behavior_pair: match_queries) {
if (match_behavior_pair.match.matchAttributes(key_value_pairs)) {
MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs);
if (match_res.is_match) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches.";
matched_behaviors.insert(match_behavior_pair.behavior);
// When matching indicators with action=ignore, we expect no behavior override.
// Instead, a matched keywords list should be returned which will be later removed from score calculation
if (match_res.matched_keywords->size() > 0 && match_behavior_pair.behavior == action_ignore) {
matched_override_keywords.insert(match_res.matched_keywords->begin(),
match_res.matched_keywords->end());
} else {
matched_behaviors.insert(match_behavior_pair.behavior);
}
}
}
if (match_queries.empty() && match.matchAttributes(key_value_pairs)) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
matched_behaviors.insert(behavior);
if (match_queries.empty()) {
MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs);
if (match_res.is_match) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
// When matching indicators with action=ignore, we expect no behavior override.
// Instead, a matched keywords list should be returned which will be later removed from score calculation
if (match_res.matched_keywords->size() > 0 && behavior == action_ignore) {
matched_override_keywords.insert(match_res.matched_keywords->begin(),
match_res.matched_keywords->end());
} else {
matched_behaviors.insert(behavior);
}
}
}
return matched_behaviors;
}
set<ParameterBehavior>
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
{
set<string> keywords;
return getBehavior(key_value_pairs, keywords);
}

View File

@@ -124,16 +124,36 @@ setTriggersFlag(const string &key, cereal::JSONInputArchive &ar, EnumClass flag,
}
static void
setLogConfiguration(const ReportIS::StreamType &log_type, const string &log_server_url = "")
setLogConfiguration(
const ReportIS::StreamType &log_type,
const string &log_server_url = "",
const string &protocol = ""
)
{
dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url;
if (log_server_url != "") {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url);
if (log_server_url != "" && protocol != "") {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url, protocol);
} else {
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type);
}
}
static string
parseProtocolWithDefault(
const std::string &default_value,
const std::string &key_name,
cereal::JSONInputArchive &archive_in
)
{
string value;
try {
archive_in(cereal::make_nvp(key_name, value));
} catch (const cereal::Exception &e) {
return default_value;
}
return value;
}
void
LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
{
@@ -142,6 +162,9 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
parseJSONKey<string>("verbosity", verbosity, archive_in);
parseJSONKey<string>("urlForSyslog", url_for_syslog, archive_in);
parseJSONKey<string>("urlForCef", url_for_cef, archive_in);
parseJSONKey<string>("syslogProtocol", syslog_protocol, archive_in);
syslog_protocol = parseProtocolWithDefault("UDP", "syslogProtocol", archive_in);
cef_protocol = parseProtocolWithDefault("UDP", "cefProtocol", archive_in);
setTriggersFlag("webBody", archive_in, WebLogFields::webBody, log_web_fields);
setTriggersFlag("webHeaders", archive_in, WebLogFields::webHeaders, log_web_fields);
@@ -197,11 +220,14 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
case ReportIS::StreamType::JSON_LOG_FILE:
setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE);
break;
case ReportIS::StreamType::JSON_K8S_SVC:
setLogConfiguration(ReportIS::StreamType::JSON_K8S_SVC);
break;
case ReportIS::StreamType::SYSLOG:
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog());
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog(), syslog_protocol);
break;
case ReportIS::StreamType::CEF:
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef());
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef(), cef_protocol);
break;
case ReportIS::StreamType::NONE: break;
case ReportIS::StreamType::COUNT: break;