2024-04-14 12:55:54 +00:00

830 lines
27 KiB
C++

#include "ips_signatures.h"
#include <sstream>
#include <algorithm>
#include "ips_comp.h"
#include "ips_basic_policy.h"
#include "snort_basic_policy.h"
#include "generic_rulebase/parameters_config.h"
#include "generic_rulebase/triggers_config.h"
#include "rule_detection.h"
#include "helper.h"
#include "config.h"
#include "context.h"
#include "ips_entry.h"
#include "ips_metric.h"
#include "ips_common_types.h"
USE_DEBUG_FLAG(D_IPS);
using namespace IPSSignatureSubTypes;
using namespace ReportIS;
using namespace std;
using MatchType = BaseSignature::MatchType;
static const LogTriggerConf default_triger;
static const map<IPSLevel, Severity> severities = {
{ IPSLevel::CRITICAL, Severity::CRITICAL },
{ IPSLevel::HIGH, Severity::HIGH },
{ IPSLevel::MEDIUM_HIGH, Severity::HIGH },
{ IPSLevel::MEDIUM, Severity::MEDIUM },
{ IPSLevel::MEDIUM_LOW, Severity::LOW },
{ IPSLevel::LOW, Severity::LOW },
{ IPSLevel::VERY_LOW, Severity::INFO }
};
static const map<string, IPSLevel> levels = {
{ "Critical", IPSLevel::CRITICAL },
{ "High", IPSLevel::HIGH },
{ "Medium High", IPSLevel::MEDIUM_HIGH },
{ "Medium", IPSLevel::MEDIUM },
{ "Medium Low", IPSLevel::MEDIUM_LOW },
{ "Low", IPSLevel::LOW },
{ "Very Low", IPSLevel::VERY_LOW }
};
static IPSLevel
getLevel(const string &level_string, const string &attr_name)
{
auto index = levels.find(level_string);
if (index == levels.end()) {
reportConfigurationError(
"Unknown level: '" + level_string + "' in attribute " + attr_name
);
}
return index->second;
}
void
IPSSignatureMetaData::setIndicators(const string &_source, const string &_version)
{
source = _source;
version = _version;
}
string
IPSSignatureMetaData::getSeverityString() const
{
switch (severity) {
case IPSLevel::VERY_LOW:
return "Very Low";
case IPSLevel::LOW:
return "Low";
case IPSLevel::MEDIUM_LOW:
return "Medium Low";
case IPSLevel::MEDIUM:
return "Medium";
case IPSLevel::MEDIUM_HIGH:
return "Medium High";
case IPSLevel::HIGH:
return "High";
case IPSLevel::CRITICAL:
return "Critical";
}
dbgAssert(false) << "Illegal severity value: " << static_cast<uint>(severity);
return "Critical";
}
string
IPSSignatureMetaData::getConfidenceString() const
{
if (confidence <= IPSLevel::LOW) return "Low";
if (confidence >= IPSLevel::HIGH) return "High";
return "Medium";
}
string
IPSSignatureMetaData::getPerformanceString() const
{
switch (performance) {
case IPSLevel::VERY_LOW:
return "Very Low";
case IPSLevel::LOW:
return "Low";
case IPSLevel::MEDIUM_LOW:
return "Medium Low";
case IPSLevel::MEDIUM:
return "Medium";
case IPSLevel::MEDIUM_HIGH:
return "Medium High";
case IPSLevel::HIGH:
return "High";
case IPSLevel::CRITICAL:
return "Critical";
}
dbgAssert(false) << "Illegal performance value: " << static_cast<uint>(performance);
return "Critical";
}
void
IPSSignatureMetaData::load(cereal::JSONInputArchive &ar)
{
string severity_string, confidence_string, performance_string;
ar(
cereal::make_nvp("maintrainId", protection_id),
cereal::make_nvp("protectionName", sig_name),
cereal::make_nvp("severity", severity_string),
cereal::make_nvp("lastUpdate", update),
cereal::make_nvp("confidenceLevel", confidence_string),
cereal::make_nvp("performanceImpact", performance_string),
cereal::make_nvp("cveList", cve_list),
cereal::make_nvp("tags", tag_list)
);
severity = getLevel(severity_string, "severity");
confidence = getLevel(confidence_string, "confidence");
performance = getLevel(performance_string, "performance");
try {
ar(cereal::make_nvp("logAttackName", event_log));
} catch (cereal::Exception &) {
event_log = "IPS Signature '" + sig_name + "' Found";
ar.setNextName(nullptr);
}
try {
ar(cereal::make_nvp("silent", is_silent));
} catch (cereal::Exception &) {
ar.setNextName(nullptr);
}
}
static const size_t protection_type_pos = strlen("Protection_Type_");
static const size_t vul_type_pos = strlen("Vul_Type_");
string
IPSSignatureSubTypes::IPSSignatureMetaData::getIncidentType() const
{
for (auto &tag : tag_list) {
if (tag.compare(0, vul_type_pos, "Vul_Type_") == 0) {
auto incident_type = tag.substr(vul_type_pos);
replace(incident_type.begin(), incident_type.end(), '_', ' ');
if (incident_type == "Vulnerability") return "Vulnerability exploit attempt";
return incident_type;
}
}
for (auto &tag : tag_list) {
if (tag.compare(0, protection_type_pos, "Protection_Type_") == 0) {
auto incident_type = tag.substr(protection_type_pos);
replace(incident_type.begin(), incident_type.end(), '_', ' ');
if (incident_type == "Vulnerability") return "Vulnerability exploit attempt";
return incident_type;
}
}
return "";
}
static const size_t year_start_pos = strlen("Threat_Year_");
bool
IPSSignatureMetaData::isYearAtLeast(const Maybe<int> &year) const
{
if (!year.ok()) return true;
auto protection_year = getYear();
if (!protection_year.ok()) return true;
return *protection_year >= *year;
}
Maybe<int>
IPSSignatureMetaData::getYear() const
{
for (auto &tag : tag_list) {
if (tag.compare(0, year_start_pos, "Threat_Year_") == 0) {
if (tag.size() != year_start_pos + 4) {
dbgWarning(D_IPS) << "Threat year tag (" << tag << ") doen't meet expected format";
return false;
}
int protection_year =
(tag[year_start_pos] - '0') * 1000 +
(tag[year_start_pos + 1] - '0') * 100 +
(tag[year_start_pos + 2] - '0') * 10 +
(tag[year_start_pos + 3] - '0');
return protection_year;
}
}
return genError("Year not found");
}
void
CompleteSignature::load(cereal::JSONInputArchive &ar)
{
ar(cereal::make_nvp("protectionMetadata", metadata));
RuleDetection rule_detection(metadata.getName());
ar(cereal::make_nvp("detectionRules", rule_detection));
rule = rule_detection.getRule();
}
MatchType
CompleteSignature::getMatch(const set<PMPattern> &matches) const
{
return rule->getMatch(matches);
}
set<PMPattern>
CompleteSignature::patternsInSignature() const
{
return rule->patternsInSignature();
}
void
CompleteSignature::setIndicators(const string &source, const string &version)
{
metadata.setIndicators(source, version);
}
template <typename ErrorType>
static string
getSubString(const Maybe<Buffer, ErrorType> &buf, uint max_size = 0)
{
if (max_size == 0) max_size = buf.unpack().size();
const Buffer &real_buf = buf.unpack();
auto res = real_buf.size() <= max_size ? real_buf : real_buf.getSubBuffer(0, max_size);
return static_cast<string>(res);
}
ActionResults
SignatureAndAction::getAction(const IPSEntry &ips_state) const
{
dbgDebug(D_IPS) << "matching exceptions";
unordered_map<string, set<string>> exceptions_dict;
exceptions_dict["protectionName"].insert(signature->getName());
ScopedContext ctx;
ctx.registerValue<string>("protectionName", signature->getName());
auto env = Singleton::Consume<I_Environment>::by<IPSComp>();
auto host = env->get<string>(HttpTransactionData::host_name_ctx);
if (host.ok()) exceptions_dict["hostName"].insert(*host);
auto client_ip = env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
if (client_ip.ok()) {
stringstream client_ip_str;
client_ip_str << client_ip.unpack();
exceptions_dict["sourceIP"].insert(client_ip_str.str());
}
auto path = ips_state.getBuffer("HTTP_PATH_DECODED");
if (path.size()) exceptions_dict["url"].insert(static_cast<string>(path));
auto env_source_identifier = env->get<string>(HttpTransactionData::source_identifier);
if (env_source_identifier.ok()) {
exceptions_dict["sourceIdentifier"].insert(*env_source_identifier);
}
auto behaviors = getBehavior(exceptions_dict);
set<BehaviorValue> override_actions;
vector<string> override_ids;
for (auto const &behavior : behaviors) {
if (behavior.getKey() == BehaviorKey::ACTION) {
override_actions.insert(behavior.getValue());
const string &override_id = behavior.getId();
if (!override_id.empty()) override_ids.push_back(override_id);
}
}
if (override_actions.find(BehaviorValue::IGNORE) != override_actions.end()) {
dbgDebug(D_IPS) << "Exception matched - action=Detect";
return make_tuple(IPSSignatureSubTypes::SignatureAction::DETECT, string("Skip"), override_ids);
}
if (override_actions.find(BehaviorValue::ACCEPT) != override_actions.end()) {
dbgDebug(D_IPS) << "Exception matched - action=Detect";
return make_tuple(IPSSignatureSubTypes::SignatureAction::DETECT, string("Accept"), override_ids);
}
if (override_actions.find(BehaviorValue::REJECT) != override_actions.end()) {
dbgDebug(D_IPS) << "Exception matched - action=Prevent";
return make_tuple(IPSSignatureSubTypes::SignatureAction::PREVENT, string("Drop"), override_ids);
}
return make_tuple(action, string("None"), override_ids);
}
static const auto req_body = LogTriggerConf::WebLogFields::webBody;
static const auto headers = LogTriggerConf::WebLogFields::webHeaders;
static const auto url_path = LogTriggerConf::WebLogFields::webUrlPath;
static const auto url_query = LogTriggerConf::WebLogFields::webUrlQuery;
static const auto res_body = LogTriggerConf::WebLogFields::responseBody;
static const auto res_code = LogTriggerConf::WebLogFields::responseCode;
LogTriggerConf
SignatureAndAction::getTrigger() const
{
if (trigger_id.empty()) return getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
return Singleton::Consume<I_GenericRulebase>::by<IPSComp>()->getLogTriggerConf(trigger_id);
}
set<ParameterBehavior>
SignatureAndAction::getBehavior(const unordered_map<string, set<string>> &exceptions_dict) const
{
I_GenericRulebase *i_rulebase = Singleton::Consume<I_GenericRulebase>::by<IPSComp>();
if (exception_id.empty()) return i_rulebase->getBehavior(exceptions_dict);
return i_rulebase->getParameterException(exception_id).getBehavior(exceptions_dict);
}
bool
SignatureAndAction::matchSilent(const Buffer &sample) const
{
dbgTrace(D_IPS) << "Matched silent signature";
MatchEvent(signature, IPSSignatureSubTypes::SignatureAction::IGNORE).notify();
ScopedContext ctx;
ctx.registerValue("Audience Team", AudienceTeam::SIGNATURE_DEVELOPERS);
LogGen log(
"Silent Protection",
Audience::INTERNAL,
Severity::INFO,
Priority::MEDIUM,
LogField("practiceType", "Threat Prevention"),
Tags::IPS,
StreamType::JSON_FOG
);
log << LogField("signatureVersion", signature->getUpdateVersion())
<< LogField("protectionId", signature->getName())
<< LogField("indicatorsSource", signature->getSource())
<< LogField("indicatorsVersion", signature->getFeedVersion())
<< LogField("incidentType", signature->getIncidentType())
<< LogField("matchedSample", static_cast<string>(sample), LogFieldOption::XORANDB64);
auto env = Singleton::Consume<I_Environment>::by<IPSComp>();
auto table = Singleton::Consume<I_Table>::by<IPSComp>();
auto &ips_state = table->getState<IPSEntry>();
auto method = env->get<string>(HttpTransactionData::method_ctx);
if (method.ok()) log << LogField("httpMethod", method.unpack());
auto path = env->get<Buffer>("HTTP_PATH_DECODED");
if (path.ok()) log << LogField("httpUriPath", getSubString(path, 1536), LogFieldOption::XORANDB64);
auto req_header = ips_state.getTransactionData(IPSCommonTypes::requests_header_for_log);
if (req_header.ok()) log << LogField("httpRequestHeaders", getSubString(req_header), LogFieldOption::XORANDB64);
auto res_code = env->get<Buffer>("HTTP_RESPONSE_CODE");
if (res_code.ok()) log << LogField("httpResponseCode", static_cast<string>(res_code.unpack()));
auto req_body = env->get<Buffer>("HTTP_REQUEST_BODY");
auto res_body = env->get<Buffer>("HTTP_RESPONSE_BODY");
uint req_size = req_body.ok() ? req_body.unpack().size() : 0;
uint res_size = res_body.ok() ? res_body.unpack().size() : 0;
if (req_size + res_size > 1536) {
if (req_size + 500 > 1536) {
res_size = std::min(500u, res_size);
req_size = 1536 - res_size;
} else {
res_size = 1536 - req_size;
}
}
if (req_size) log << LogField("httpRequestBody", getSubString(req_body, req_size), LogFieldOption::XORANDB64);
if (res_size) log << LogField("httpResponseBody", getSubString(res_body, res_size), LogFieldOption::XORANDB64);
return false;
}
bool
SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMPattern> &pattern) const
{
if (signature->getMatch(pattern) != MatchType::MATCH) {
dbgTrace(D_IPS) << "Signature doesn't match";
return false;
}
if (signature->isSilent()) return matchSilent(context_buffer);
auto table = Singleton::Consume<I_Table>::by<IPSComp>();
auto &ips_state = table->getState<IPSEntry>();
auto override_action = getAction(ips_state);
MatchEvent(signature, get<0>(override_action)).notify();
if (get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::IGNORE) {
dbgDebug(D_IPS) << "Ignored signature";
return false;
}
dbgDebug(D_IPS) << "Signature matched - sending log";
auto trigger = getTrigger();
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL;
if (get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::DETECT) severity = Severity::INFO;
LogGen log = trigger(
"Web Request",
LogTriggerConf::SecurityType::ThreatPrevention,
severity,
Priority::HIGH,
is_prevent,
LogField("practiceType", "Threat Prevention"),
Tags::IPS
);
log
<< LogField("matchedSignatureConfidence", signature->getConfidenceString())
<< LogField("matchedSignaturePerformance", signature->getPerformanceString())
<< LogField("matchedSignatureSeverity", signature->getSeverityString())
<< LogField("matchedSignatureCVE", makeSeparatedStr(signature->getCveList(), ", "))
<< LogField("signatureVersion", signature->getUpdateVersion())
<< LogField("protectionId", signature->getName())
<< LogField("indicatorsSource", signature->getSource())
<< LogField("indicatorsVersion", signature->getFeedVersion())
<< LogField("waapIncidentType", signature->getIncidentType());
if (context_buffer.size() < 1024) {
log << LogField("matchedSample", static_cast<string>(context_buffer), LogFieldOption::XORANDB64);
} else {
auto sample = context_buffer;
sample.keepHead(1024);
log << LogField("matchedSample", static_cast<string>(sample), LogFieldOption::XORANDB64);
}
auto year = signature->getYear();
if (year.ok()) log << LogField("matchedSignatureYear", to_string(*year));
auto env = Singleton::Consume<I_Environment>::by<IPSComp>();
auto host = env->get<string>(HttpTransactionData::host_name_ctx);
if (host.ok()) log << LogField("httpHostName", host.unpack());
auto client_ip = env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
if (client_ip.ok()) {
stringstream client_ip_str;
client_ip_str << client_ip.unpack();
log << LogField("sourceIP", client_ip_str.str());
}
auto proxy_ip = env->get<string>(HttpTransactionData::proxy_ip_ctx);
if (proxy_ip.ok()) {
log << LogField("proxyIP", static_cast<string>(proxy_ip.unpack()));
}
auto source_identifier = env->get<string>(HttpTransactionData::source_identifier);
if (source_identifier.ok()) {
log << LogField("httpSourceId", static_cast<string>(source_identifier.unpack()));
}
auto req_header = ips_state.getTransactionData(IPSCommonTypes::requests_header_for_log);
if (req_header.ok() && trigger.isWebLogFieldActive(headers)) {
log << LogField("httpRequestHeaders", static_cast<string>(req_header.unpack()), LogFieldOption::XORANDB64);
}
auto client_port = env->get<uint16_t>(HttpTransactionData::client_port_ctx);
if (client_port.ok()) log << LogField("sourcePort", client_port.unpack());
auto method = env->get<string>(HttpTransactionData::method_ctx);
if (method.ok()) log << LogField("httpMethod", method.unpack());
uint max_size = getConfigurationWithDefault<uint>(1536, "IPS", "Max Field Size");
auto path = env->get<Buffer>("HTTP_PATH_DECODED");
if (path.ok() && trigger.isWebLogFieldActive(url_path)) {
log << LogField("httpUriPath", getSubString(path, max_size), LogFieldOption::XORANDB64);
}
auto query = env->get<Buffer>("HTTP_QUERY_DECODED");
if (query.ok() && trigger.isWebLogFieldActive(url_query)) {
log << LogField("httpUriQuery", getSubString(query, max_size), LogFieldOption::XORANDB64);
}
auto res_code = env->get<Buffer>("HTTP_RESPONSE_CODE");
if (res_code.ok() && trigger.isWebLogFieldActive(::res_code)) {
log << LogField("httpResponseCode", static_cast<string>(res_code.unpack()));
}
auto req_body = env->get<Buffer>("HTTP_REQUEST_BODY");
auto res_body = env->get<Buffer>("HTTP_RESPONSE_BODY");
uint req_size = req_body.ok() && trigger.isWebLogFieldActive(::req_body) ? req_body.unpack().size() : 0;
uint res_size = res_body.ok() && trigger.isWebLogFieldActive(::res_body) ? res_body.unpack().size() : 0;
if (req_size + res_size > max_size) {
if (req_size + 500 > max_size) {
res_size = std::min(500u, res_size);
req_size = max_size - res_size;
} else {
res_size = max_size - req_size;
}
}
if (req_size) log << LogField("httpRequestBody", getSubString(req_body, req_size), LogFieldOption::XORANDB64);
if (res_size) log << LogField("httpResponseBody", getSubString(res_body, res_size), LogFieldOption::XORANDB64);
log << LogField("waapOverride", get<1>(override_action));
if (!get<2>(override_action).empty()) log.addToOrigin(LogField("exceptionIdList", get<2>(override_action)));
log << LogField("securityAction", is_prevent ? "Prevent" : "Detect");
return is_prevent;
}
void
IPSSignaturesResource::load(cereal::JSONInputArchive &ar)
{
if (!IPSHelper::hasDeobfuscation()) return;
vector<CompleteSignature> sigs;
cereal::load(ar, sigs);
all_signatures.reserve(sigs.size());
for (auto &sig : sigs) {
all_signatures.emplace_back(make_shared<CompleteSignature>(move(sig)));
}
}
class CompleteSignatureWrapper
{
public:
void
load(cereal::JSONInputArchive &ar)
{
try {
sig.load(ar);
is_loaded = true;
} catch (const cereal::Exception &e) {
ar.finishNode();
reportError(e.what());
} catch (const Config::ConfigException &e) {
ar.finishNode();
reportError(e.getError());
}
}
bool isOk() const { return is_loaded; }
void setIndicators(const string &source, const string &version) { sig.setIndicators(source, version); }
shared_ptr<CompleteSignature> getPtr() { return make_shared<CompleteSignature>(move(sig)); }
private:
void
reportError(const string &err)
{
dbgError(D_IPS) << "Failed to load signature due to: " << err;
if (sig.getName() != "") {
string remediation =
"Verify the validity of the '" +
sig.getName() +
"' signature.";
LogGen(
"Could not load a Snort signature from configured file",
ReportIS::Level::ACTION,
ReportIS::Audience::SECURITY,
ReportIS::Severity::CRITICAL,
ReportIS::Priority::URGENT,
LogField("EventTopic", "Snort Signatures"),
ReportIS::Tags::POLICY_INSTALLATION
) << LogField("EventRemediation", remediation);
}
}
CompleteSignature sig;
bool is_loaded = false;
};
void
SnortSignaturesResourceFile::load(cereal::JSONInputArchive &ar)
{
string time;
vector<CompleteSignatureWrapper> sigs;
ar(
cereal::make_nvp("modificationTime", time),
cereal::make_nvp("name", name),
cereal::make_nvp("protections", sigs)
);
all_signatures.reserve(sigs.size());
for (auto &sig : sigs) {
if (sig.isOk()) {
sig.setIndicators(name, time);
all_signatures.emplace_back(sig.getPtr());
}
}
}
void
SnortSignaturesResource::load(cereal::JSONInputArchive &ar)
{
cereal::load(ar, files);
}
void
IPSSignaturesPerContext::addSignature(const IPSSignatureSubTypes::SignatureAndAction &sig)
{
auto patterns = sig.patternsInSignature();
if (patterns.empty()) {
signatures_without_lss.push_back(sig);
return;
}
for (auto &pat : patterns) {
signatures_per_lss[pat].push_back(sig);
}
}
void
IPSSignaturesPerContext::calcFirstTier(const string &ctx_name)
{
std::set<PMPattern> patterns;
for (const auto &lss_to_sig : signatures_per_lss) {
patterns.emplace(lss_to_sig.first);
}
first_tier = Singleton::Consume<I_FirstTierAgg>::by<IPSSignaturesPerContext>()->getHook(ctx_name, patterns);
}
set<PMPattern>
IPSSignaturesPerContext::getFirstTierMatches(const Buffer &buffer) const
{
return first_tier->ok() ? first_tier->scanBuf(buffer) : set<PMPattern>();
}
bool
IPSSignaturesPerContext::isMatchedPrevent(const Buffer &context_buffer) const
{
auto first_tier_res = getFirstTierMatches(context_buffer);
for (auto &pat : first_tier_res) {
auto find = signatures_per_lss.find(pat);
if (find == signatures_per_lss.end()) continue;
for (auto &sig : find->second) {
if (sig.isMatchedPrevent(context_buffer, first_tier_res)) return true;
}
}
for (auto &sig : signatures_without_lss) {
if (sig.isMatchedPrevent(context_buffer, first_tier_res)) return true;
}
return false;
}
void
IPSSignatures::load(cereal::JSONInputArchive &ar)
{
ar(
cereal::make_nvp("assetName", asset_name),
cereal::make_nvp("practiceName", practice_name)
);
try {
ar(cereal::make_nvp("assetId", asset_id));
} catch (const cereal::Exception &e) {
ar.setNextName(nullptr);
asset_id = "";
}
try {
ar(cereal::make_nvp("practiceId", practice_id));
} catch (const cereal::Exception &e) {
ar.setNextName(nullptr);
practice_id = "";
}
try {
ar(cereal::make_nvp("sourceIdentifier", source_id));
for (auto &ch : source_id) {
ch = tolower(ch);
}
} catch (const cereal::Exception &e) {
ar.setNextName(nullptr);
source_id = "";
}
RuleSelector ruleSelector;
ruleSelector.load(ar);
std::vector<IPSSignatureSubTypes::SignatureAndAction> signatures = ruleSelector.selectSignatures();
if (signatures.empty()) {
dbgDebug(D_IPS) << "[IPS] Could not find any match between rules and signatures.";
return;
}
for (const auto &sig : signatures) {
auto &sig_contexts = sig.getContext();
for (auto &sig_context : sig_contexts) {
signatures_per_context[sig_context].addSignature(sig);
}
}
for (auto &sig_per_ctx : signatures_per_context) {
sig_per_ctx.second.calcFirstTier(sig_per_ctx.first);
}
}
bool
IPSSignatures::isMatchedPrevent(const string &context_name, const Buffer &context_buffer) const
{
auto curr_sig = signatures_per_context.find(context_name);
if (curr_sig == signatures_per_context.end()) {
dbgDebug(D_IPS) << "[IPS] No signatures for " << context_name;
return false;
}
auto &config = getConfiguration<IPSSignatures>("IPS", "IpsProtections");
ScopedContext ctx;
auto SOURCE = EnvKeyAttr::LogSection::SOURCE;
if (config.ok()) {
ctx.registerValue<string>("practiceName", (*config).getPractice(), SOURCE);
ctx.registerValue<string>("practiceId", (*config).getPracticeId(), SOURCE);
}
ctx.registerValue<string>("practiceSubType", "Web IPS", SOURCE);
auto is_matched = curr_sig->second.isMatchedPrevent(context_buffer);
return is_matched;
}
bool
IPSSignatures::isEmpty(const std::string &context) const
{
return signatures_per_context.find(context) == signatures_per_context.end();
}
void
SnortSignatures::load(cereal::JSONInputArchive &ar)
{
ar(
cereal::make_nvp("assetName", asset_name),
cereal::make_nvp("practiceName", practice_name)
);
try {
ar(cereal::make_nvp("assetId", asset_id));
} catch (const cereal::Exception &e) {
ar.setNextName(nullptr);
asset_id = "";
}
try {
ar(cereal::make_nvp("practiceId", practice_id));
} catch (const cereal::Exception &e) {
ar.setNextName(nullptr);
practice_id = "";
}
try {
ar(cereal::make_nvp("sourceIdentifier", source_id));
for (auto &ch : source_id) {
ch = tolower(ch);
}
} catch (const cereal::Exception &e) {
ar.setNextName(nullptr);
source_id = "";
}
SnortRuleSelector ruleSelector;
ruleSelector.load(ar);
std::vector<IPSSignatureSubTypes::SignatureAndAction> signatures = ruleSelector.selectSignatures();
if (signatures.empty()) {
dbgDebug(D_IPS) << "[Snort] Could not find any match between rules and signatures.";
return;
}
for (const auto &sig : signatures) {
auto &sig_contexts = sig.getContext();
for (auto &sig_context : sig_contexts) {
signatures_per_context[sig_context].addSignature(sig);
}
}
for (auto &sig_per_ctx: signatures_per_context) {
sig_per_ctx.second.calcFirstTier(sig_per_ctx.first);
}
}
bool
SnortSignatures::isMatchedPrevent(const string &context_name, const Buffer &context_buffer) const
{
auto curr_sig = signatures_per_context.find(context_name);
if (curr_sig == signatures_per_context.end()) {
dbgDebug(D_IPS) << "[Snort] No signatures for " << context_name;
return false;
}
auto &config = getConfiguration<SnortSignatures>("IPSSnortSigs", "SnortProtections");
ScopedContext ctx;
auto SOURCE = EnvKeyAttr::LogSection::SOURCE;
if (config.ok()) {
ctx.registerValue<string>("assetName", (*config).getAsset(), SOURCE);
ctx.registerValue<string>("assetId", (*config).getAssetId(), SOURCE);
ctx.registerValue<string>("practiceName", (*config).getPractice(), SOURCE);
ctx.registerValue<string>("practiceId", (*config).getPracticeId(), SOURCE);
}
ctx.registerValue<string>("practiceSubType", "Web Snort", SOURCE);
auto is_matched = curr_sig->second.isMatchedPrevent(context_buffer);
return is_matched;
}
bool
SnortSignatures::isEmpty(const std::string &context) const
{
return signatures_per_context.find(context) == signatures_per_context.end();
}