From 94743732644317f00927e58c460e24114d807acf Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Fri, 5 Feb 2016 15:12:20 -0300 Subject: [PATCH] General improvements on audit logs information Making actions: msg, logdata, tag and others to work in the same fashion that they work on ModSecurity v2.x --- headers/modsecurity/rule.h | 52 +++++++++++++++++++++++++++++++ headers/modsecurity/transaction.h | 9 +++--- src/actions/log_data.cc | 12 +++---- src/actions/msg.cc | 26 ++++++++++++++-- src/actions/tag.cc | 25 ++++++++++++++- src/rule.cc | 7 +++++ src/transaction.cc | 40 ++++++++++++++++++++++++ 7 files changed, 157 insertions(+), 14 deletions(-) diff --git a/headers/modsecurity/rule.h b/headers/modsecurity/rule.h index 91d396fa..f736e827 100644 --- a/headers/modsecurity/rule.h +++ b/headers/modsecurity/rule.h @@ -76,12 +76,64 @@ class Rule { bool m_secmarker; std::string m_fileName; int m_lineNumber; + std::list m_tags; + + std::string m_log_data; + std::string m_log_message; private: bool m_unconditional; int m_referenceCount; }; +class RuleMessage { + public: + RuleMessage(Rule *rule) { + m_ruleFile = rule->m_fileName; + m_ruleLine = rule->m_lineNumber; + m_ruleId = rule->rule_id; + m_ruleRev = 0; + m_message = std::string(""); + m_data = std::string(""); + m_severity = std::string(""); + m_ver = std::string(""); + m_maturity = 0; + m_accuracy = 0; + m_tags = std::string(""); + m_rule = rule; + }; + RuleMessage(Rule *rule, std::string message) { + m_ruleFile = rule->m_fileName; + m_ruleLine = rule->m_lineNumber; + m_ruleId = rule->rule_id; + m_ruleRev = 0; + m_message = message; + m_data = std::string(""); + m_severity = std::string(""); + m_ver = std::string(""); + m_maturity = 0; + m_accuracy = 0; + m_tags = std::string(""); + m_rule = rule; + }; + + std::string m_match; + std::string m_ruleFile; + int m_ruleLine; + int m_ruleId; + int m_ruleRev; + std::string m_message; + std::string m_data; + std::string m_severity; + std::string m_ver; + int m_maturity; + int m_accuracy; + std::string m_tags; + + Rule *m_rule; +}; + + } // namespace modsecurity #endif diff --git a/headers/modsecurity/transaction.h b/headers/modsecurity/transaction.h index d0eb39bc..0c751abe 100644 --- a/headers/modsecurity/transaction.h +++ b/headers/modsecurity/transaction.h @@ -71,6 +71,7 @@ class ModSecurity; class Transaction; class Rules; class Collections; +class RuleMessage; namespace actions { class Action; } @@ -264,14 +265,14 @@ class Transaction { /** * This variable holds all the messages asked to be save by the utilization - * of the actions: `log_data' and `msg'. These should be included on the - * auditlogs. + * of the actions: `log_data' and `msg'. These should be included on the + * auditlogs. */ - std::list m_rulesMessages; + std::list m_rulesMessages; /** * The list m_ruleTags contains all tags that were specified by the - * action `tag'. + * action `tag'. */ std::list m_ruleTags; diff --git a/src/actions/log_data.cc b/src/actions/log_data.cc index 6562fbd0..a1281b23 100644 --- a/src/actions/log_data.cc +++ b/src/actions/log_data.cc @@ -22,6 +22,7 @@ #include "modsecurity/transaction.h" #include "src/utils.h" #include "src/macro_expansion.h" +#include "modsecurity/rule.h" namespace modsecurity { namespace actions { @@ -35,14 +36,11 @@ LogData::LogData(std::string action) bool LogData::evaluate(Rule *rule, Transaction *transaction) { - std::string msg = MacroExpansion::expand(m_data, transaction); -#ifndef NO_LOGS - transaction->debug(9, "Saving msg: " + msg); -#endif - transaction->m_rulesMessages.push_back(msg); - transaction->serverLog(msg); - return true; + std::string data = MacroExpansion::expand(m_data, transaction); + + rule->m_log_data = data; } + } // namespace actions } // namespace modsecurity diff --git a/src/actions/msg.cc b/src/actions/msg.cc index a8f79541..309e923e 100644 --- a/src/actions/msg.cc +++ b/src/actions/msg.cc @@ -22,6 +22,25 @@ #include "modsecurity/transaction.h" #include "src/utils.h" #include "src/macro_expansion.h" +#include "modsecurity/rule.h" + +/* + * Description: Assigns a custom message to the rule or chain in which it + * appears. The message will be logged along with every alert. + * + * Action Group: Meta-data + * + * Example: + * SecRule &REQUEST_HEADERS:Host "@eq 0" "log,id:60008,severity:2,msg:'Request Missing a Host Header'" + * + * Note : The msg information appears in the error and/or audit log files + * and is not sent back to the client in response headers. + * + * Note 2: The msg action can appear multiple times in the SecRule, however + * just the last one will be take into consideration. + * + */ + namespace modsecurity { namespace actions { @@ -36,13 +55,16 @@ Msg::Msg(std::string action) bool Msg::evaluate(Rule *rule, Transaction *transaction) { std::string msg = MacroExpansion::expand(m_msg, transaction); + #ifndef NO_LOGS transaction->debug(9, "Saving msg: " + msg); #endif - transaction->m_rulesMessages.push_back(msg); - transaction->serverLog(msg); + + rule->m_log_message = msg; + return true; } + } // namespace actions } // namespace modsecurity diff --git a/src/actions/tag.cc b/src/actions/tag.cc index 92b64b71..45cb59b4 100644 --- a/src/actions/tag.cc +++ b/src/actions/tag.cc @@ -22,6 +22,29 @@ #include "modsecurity/transaction.h" #include "src/utils.h" #include "src/macro_expansion.h" +#include "modsecurity/rule.h" + +/** + * Description: Assigns a tag (category) to a rule or a chain. + * + * Action Group: Meta-data + * + * Example: + * + * SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \ + * "phase:2,rev:'2.1.3',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \ + * {TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}" + * + * + * The tag information appears along with other rule metadata. The + * purpose of the tagging mechanism to allow easy automated categorization + * of events. Multiple tags can be specified on the same rule. Use forward + * slashes to create a hierarchy of categories (as in the example). Since + * ModSecurity 2.6.0 tag supports macro expansion. + * + * + */ + namespace modsecurity { namespace actions { @@ -39,7 +62,7 @@ bool Tag::evaluate(Rule *rule, Transaction *transaction) { #ifndef NO_LOGS transaction->debug(9, "Rule tag: " + tag); #endif - transaction->m_ruleTags.push_back(tag); + rule->m_tags.push_back(tag); return true; } diff --git a/src/rule.cc b/src/rule.cc index dd3e392c..0a1a577d 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -508,6 +508,13 @@ bool Rule::evaluate(Transaction *trasn) { e.pop_back(); } } + + if (!m_log_message.empty() || !m_log_data.empty()) { + RuleMessage *ruleMessage = new modsecurity::RuleMessage(this, m_log_message); + ruleMessage->m_data = m_log_data; + trasn->m_rulesMessages.push_back(ruleMessage); + } + return ret; } diff --git a/src/transaction.cc b/src/transaction.cc index 34de2706..9f327b32 100644 --- a/src/transaction.cc +++ b/src/transaction.cc @@ -40,6 +40,7 @@ #include "audit_log/audit_log.h" #include "src/unique_id.h" #include "src/utils.h" +#include "modsecurity/rule.h" using modsecurity::actions::Action; using modsecurity::RequestBodyProcessor::Multipart; @@ -1527,7 +1528,46 @@ std::string Transaction::toJSON(int parts) { /* end: producer */ yajl_gen_map_close(g); + + /* messages */ + yajl_gen_string(g, + reinterpret_cast("messages"), + strlen("messages")); + yajl_gen_array_open(g); + for (auto a : m_rulesMessages) { + yajl_gen_map_open(g); + LOGFY_ADD("message", a->m_message.c_str()); + yajl_gen_string(g, + reinterpret_cast("producer"), + strlen("producer")); + yajl_gen_map_open(g); + LOGFY_ADD("ruleId", std::to_string(a->m_ruleId).c_str()); + LOGFY_ADD("file", a->m_ruleFile.c_str()); + LOGFY_ADD("lineNumber", std::to_string(a->m_ruleLine).c_str()); + LOGFY_ADD("data", a->m_data.c_str()); + LOGFY_ADD("serverity", a->m_severity.c_str()); + LOGFY_ADD("ver", a->m_ver.c_str()); + + yajl_gen_string(g, + reinterpret_cast("tags"), + strlen("tags")); + yajl_gen_array_open(g); + for (auto b : a->m_rule->m_tags) { + yajl_gen_string(g, + reinterpret_cast(b.c_str()), + strlen(b.c_str())); + } + yajl_gen_array_close(g); + + LOGFY_ADD("maturity", std::to_string(a->m_maturity).c_str()); + LOGFY_ADD("accuracy", std::to_string(a->m_accuracy).c_str()); + yajl_gen_map_close(g); + yajl_gen_map_close(g); + } + yajl_gen_array_close(g); + /* end: messages */ } + /* end: transaction */ yajl_gen_map_close(g);