From 5d64f73817a98c78dd8db3fa9d70e079a9abac72 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Thu, 21 Jul 2016 13:09:22 -0300 Subject: [PATCH] Makes RULE collection to be resolved inside a macro expansion --- src/actions/set_var.cc | 4 +- src/collection/collections.cc | 1 - src/macro_expansion.cc | 36 ++++++- src/macro_expansion.h | 2 + src/variables/rule.cc | 11 +- test/test-cases/regression/variable-RULE.json | 102 +++++++++++++++++- 6 files changed, 143 insertions(+), 13 deletions(-) diff --git a/src/actions/set_var.cc b/src/actions/set_var.cc index 02738dd9..e543f63e 100644 --- a/src/actions/set_var.cc +++ b/src/actions/set_var.cc @@ -90,9 +90,9 @@ bool SetVar::init(std::string *error) { bool SetVar::evaluate(Rule *rule, Transaction *transm_parser_payload) { std::string targetValue; std::string m_variableNameExpanded = MacroExpansion::expand(m_variableName, - transm_parser_payload); + rule, transm_parser_payload); std::string resolvedPre = MacroExpansion::expand(m_predicate, - transm_parser_payload); + rule, transm_parser_payload); if (m_operation == setOperation) { targetValue = resolvedPre; diff --git a/src/collection/collections.cc b/src/collection/collections.cc index 71d3f7c8..d1e322f1 100644 --- a/src/collection/collections.cc +++ b/src/collection/collections.cc @@ -81,7 +81,6 @@ void Collections::storeOrUpdateFirst(const std::string& collectionName, return; } - if (tolower(collectionName) == "session" && !m_session_collection_key.empty()) { m_session_collection->storeOrUpdateFirst(collectionName + ":" diff --git a/src/macro_expansion.cc b/src/macro_expansion.cc index aecdfefa..ca177353 100644 --- a/src/macro_expansion.cc +++ b/src/macro_expansion.cc @@ -15,6 +15,11 @@ #include "src/macro_expansion.h" #include "modsecurity/transaction.h" +#include "modsecurity/collection/variable.h" +#include "src/variables/rule.h" +#include "src/variables/tx.h" +#include "src/variables/highest_severity.h" + namespace modsecurity { @@ -35,8 +40,15 @@ std::string MacroExpansion::expandKeepOriginal(const std::string& input, std::string MacroExpansion::expand(const std::string& input, Transaction *transaction) { + return expand(input, NULL, transaction); +} + + +std::string MacroExpansion::expand(const std::string& input, + modsecurity::Rule *rule, Transaction *transaction) { std::string res; size_t pos = input.find("%{"); + std::string v; if (pos != std::string::npos) { res = input; @@ -59,7 +71,27 @@ std::string MacroExpansion::expand(const std::string& input, std::string col = std::string(variable, 0, collection); std::string var = std::string(variable, collection + 1, variable.length() - (collection + 1)); - variableValue = transaction->m_collections.resolveFirst(col, var); + + if (col == "RULE") { + if (rule == NULL) { + transaction->debug(9, "macro expansion: cannot resolve " \ + "RULE variable without the Rule object"); + goto ops; + } + modsecurity::Variables::Rule r("RULE:" + var); + std::vector l; + r.evaluateInternal(transaction, rule, &l); + if (l.size() > 0) { + v = l[0]->m_value; + variableValue = &v; + } + for (auto *i : l) { + delete i; + } + } else { + variableValue = transaction->m_collections.resolveFirst(col, + var); + } } res.erase(start, end - start + 1); @@ -70,7 +102,7 @@ std::string MacroExpansion::expand(const std::string& input, if (variableValue != NULL) { res.insert(start, *variableValue); } - +ops: pos = res.find("%{"); } diff --git a/src/macro_expansion.h b/src/macro_expansion.h index 3895a39d..23ba22fc 100644 --- a/src/macro_expansion.h +++ b/src/macro_expansion.h @@ -33,6 +33,8 @@ class MacroExpansion { static std::string expand(const std::string& input, Transaction *transaction); + static std::string expand(const std::string& input, + modsecurity::Rule *r, Transaction *transaction); static std::string expandKeepOriginal(const std::string& input, Transaction *transaction); }; diff --git a/src/variables/rule.cc b/src/variables/rule.cc index 4c2de01c..20a0134e 100644 --- a/src/variables/rule.cc +++ b/src/variables/rule.cc @@ -44,6 +44,7 @@ #include "src/actions/xmlns.h" #include "src/actions/log_data.h" #include "src/actions/msg.h" +#include "src/utils.h" namespace modsecurity { namespace Variables { @@ -52,6 +53,7 @@ void Rule::evaluateInternal(Transaction *t, modsecurity::Rule *rule, std::vector *l) { std::map envs; + std::string m_name_upper = toupper(m_name); // id envs.insert(std::pair("RULE:id", @@ -86,14 +88,17 @@ void Rule::evaluateInternal(Transaction *t, for (actions::Action *i : acts) { actions::Msg *a = reinterpret_cast(i); if (a) { + std::string data = a->data(t); envs.insert(std::pair("RULE:msg", - a->data(t))); + data)); } } for (auto& x : envs) { - if ((x.first.substr(0, m_name.size() + 1).compare(m_name + ":") != 0) - && (x.first != m_name)) { + std::string xup = toupper(x.first); + if ((xup.substr(0, m_name_upper.size() + 1) + .compare(m_name_upper + ":") != 0) + && (xup != m_name_upper)) { continue; } l->push_back(new collection::Variable(x.first, x.second)); diff --git a/test/test-cases/regression/variable-RULE.json b/test/test-cases/regression/variable-RULE.json index a2c1a76f..a2bd18c7 100644 --- a/test/test-cases/regression/variable-RULE.json +++ b/test/test-cases/regression/variable-RULE.json @@ -2,7 +2,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: RULE (1/5)", + "title":"Testing Variables :: RULE (1/7)", "client":{ "ip":"200.249.12.31", "port":123 @@ -48,7 +48,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: RULE (2/5)", + "title":"Testing Variables :: RULE (2/7)", "client":{ "ip":"200.249.12.31", "port":123 @@ -94,7 +94,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: RULE (3/5)", + "title":"Testing Variables :: RULE (3/7)", "client":{ "ip":"200.249.12.31", "port":123 @@ -140,7 +140,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: RULE (4/5)", + "title":"Testing Variables :: RULE (4/7)", "client":{ "ip":"200.249.12.31", "port":123 @@ -186,7 +186,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: RULE (5/5)", + "title":"Testing Variables :: RULE (5/7)", "client":{ "ip":"200.249.12.31", "port":123 @@ -228,6 +228,98 @@ "SecDebugLogLevel 9", "SecRule RULE:msg \"@contains test\" \"id:1,msg:'message123',phase:3,pass,t:trim\"" ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: RULE (6/7)", + "client":{ + "ip":"200.249.12.31", + "port":123 + }, + "server":{ + "ip":"200.249.12.31", + "port":80 + }, + "request":{ + "headers":{ + "Host":"localhost", + "User-Agent":"curl/7.38.0", + "Accept":"*/*", + "Content-Length": "27", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri":"/", + "method":"POST", + "body": [ + "param1=value1¶m2=value2" + ] + }, + "response":{ + "headers":{ + "Date":"Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type":"text/html" + }, + "body":[ + "no need." + ] + }, + "expected":{ + "debug_log":" Target value: \"message123\" \\(Variable: RULE:msg\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule rule:msg \"@contains test\" \"id:1,msg:'message123',phase:3,pass,t:trim\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: RULE (7/7)", + "client":{ + "ip":"200.249.12.31", + "port":123 + }, + "server":{ + "ip":"200.249.12.31", + "port":80 + }, + "request":{ + "headers":{ + "Host":"localhost", + "User-Agent":"curl/7.38.0", + "Accept":"*/*", + "Content-Length": "27", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri":"/", + "method":"POST", + "body": [ + "param1=value1¶m2=value2" + ] + }, + "response":{ + "headers":{ + "Date":"Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type":"text/html" + }, + "body":[ + "no need." + ] + }, + "expected":{ + "debug_log":"Saving variable: IP:block_reason with value: message123" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule rule:msg \"@contains message\" \"id:1,setvar:'ip.block_reason=%{RULE.msg}%',msg:'message123',phase:3,pass,t:trim\"" + ] } ]