From a2a47798e948abede8e0bebd03338645c52a780b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Fri, 6 May 2016 14:20:03 -0300 Subject: [PATCH] Adds support to the collection SESSION and setsid action --- headers/modsecurity/collection/collections.h | 4 +- headers/modsecurity/modsecurity.h | 1 + src/Makefile.am | 1 + src/actions/set_sid.cc | 55 +++++++++++++++++++ src/actions/set_sid.h | 45 +++++++++++++++ src/collection/collections.cc | 37 ++++++++++++- src/modsecurity.cc | 1 + src/parser/seclang-parser.yy | 12 ++-- src/transaction.cc | 3 +- test/test-cases/regression/action-setsid.json | 37 +++++++++++++ test/test-cases/secrules-language-tests | 2 +- 11 files changed, 186 insertions(+), 12 deletions(-) create mode 100644 src/actions/set_sid.cc create mode 100644 src/actions/set_sid.h create mode 100644 test/test-cases/regression/action-setsid.json diff --git a/headers/modsecurity/collection/collections.h b/headers/modsecurity/collection/collections.h index a4001923..6e83c1e7 100644 --- a/headers/modsecurity/collection/collections.h +++ b/headers/modsecurity/collection/collections.h @@ -45,7 +45,7 @@ namespace collection { class Collections : public std::unordered_map { public: - Collections(Collection *global, Collection *ip); + Collections(Collection *global, Collection *ip, Collection *session); ~Collections(); void store(std::string key, std::string value); @@ -86,9 +86,11 @@ class Collections : std::string m_global_collection_key; std::string m_ip_collection_key; + std::string m_session_collection_key; Collection *m_global_collection; Collection *m_ip_collection; + Collection *m_session_collection; }; } // namespace collection diff --git a/headers/modsecurity/modsecurity.h b/headers/modsecurity/modsecurity.h index 060449f3..094fcb66 100644 --- a/headers/modsecurity/modsecurity.h +++ b/headers/modsecurity/modsecurity.h @@ -224,6 +224,7 @@ class ModSecurity { collection::Collection *m_global_collection; collection::Collection *m_ip_collection; + collection::Collection *m_session_collection; private: std::string m_connector; diff --git a/src/Makefile.am b/src/Makefile.am index 0968524d..8f5c5e56 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,6 +79,7 @@ ACTIONS = \ actions/rev.cc \ actions/rule_id.cc \ actions/severity.cc \ + actions/set_sid.cc \ actions/set_var.cc \ actions/status.cc \ actions/skip_after.cc \ diff --git a/src/actions/set_sid.cc b/src/actions/set_sid.cc new file mode 100644 index 00000000..940e7dba --- /dev/null +++ b/src/actions/set_sid.cc @@ -0,0 +1,55 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include "actions/set_sid.h" + +#include +#include + +#include "modsecurity/transaction.h" +#include "modsecurity/rule.h" +#include "src/macro_expansion.h" +#include "src/utils.h" + +namespace modsecurity { +namespace actions { + + +bool SetSID::init(std::string *error) { + m_collection_key = std::string(action, 0, action.length()); + + if (m_collection_key.empty()) { + return false; + } + + return true; +} + + +bool SetSID::evaluate(Rule *rule, Transaction *t) { + std::string colNameExpanded = MacroExpansion::expand(m_collection_key, t); + +#ifndef NO_LOGS + t->debug(8, "Session ID initiated with value: \'" + + colNameExpanded + "\'."); +#endif + + t->m_collections.m_session_collection_key = colNameExpanded; + + return true; +} + +} // namespace actions +} // namespace modsecurity diff --git a/src/actions/set_sid.h b/src/actions/set_sid.h new file mode 100644 index 00000000..fa6c2b38 --- /dev/null +++ b/src/actions/set_sid.h @@ -0,0 +1,45 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include + +#include "actions/action.h" + +#ifndef SRC_ACTIONS_SET_SID_H_ +#define SRC_ACTIONS_SET_SID_H_ + +class Transaction; + +namespace modsecurity { +class Transaction; +namespace actions { + + +class SetSID : public Action { + public: + explicit SetSID(std::string _action) + : Action(_action) { } + + bool evaluate(Rule *rule, Transaction *transaction) override; + bool init(std::string *error) override; + private: + std::string m_collection_key; +}; + + +} // namespace actions +} // namespace modsecurity + +#endif // SRC_ACTIONS_SET_SID_H_ diff --git a/src/collection/collections.cc b/src/collection/collections.cc index f67a48eb..f242985f 100644 --- a/src/collection/collections.cc +++ b/src/collection/collections.cc @@ -34,11 +34,12 @@ namespace collection { Collections::Collections(Collection *global, - Collection *ip) + Collection *ip, Collection *session) : m_global_collection_key(""), m_ip_collection_key(""), m_global_collection(global), m_ip_collection(ip), + m_session_collection(session), m_transient(new backend::InMemoryPerProcess()) { /* Create collection TX */ this->emplace("TX", new backend::InMemoryPerProcess()); @@ -69,6 +70,13 @@ void Collections::storeOrUpdateFirst(const std::string& collectionName, return; } + if (tolower(collectionName) == "session" + && !m_session_collection_key.empty()) { + m_session_collection->storeOrUpdateFirst(collectionName + ":" + + variableName, m_session_collection_key, targetValue); + return; + } + try { Collection *collection; collection = this->at(collectionName); @@ -137,6 +145,12 @@ std::string* Collections::resolveFirst(const std::string& collectionName, + ":" + var, m_global_collection_key); } + if (tolower(collectionName) == "session" + && !m_session_collection_key.empty()) { + return m_session_collection->resolveFirst(toupper(collectionName) + + ":" + var, m_session_collection_key); + } + for (auto &a : *this) { if (tolower(a.first) == tolower(collectionName)) { std::string *res = a.second->resolveFirst(toupper(a.first) @@ -175,6 +189,13 @@ void Collections::resolveSingleMatch(const std::string& var, return; } + if (tolower(collection) == "session" + && !m_session_collection_key.empty()) { + m_session_collection->resolveSingleMatch(var, + m_session_collection_key, l); + return; + } + try { this->at(collection)->resolveSingleMatch(var, l); } catch (...) { } @@ -203,6 +224,13 @@ void Collections::resolveMultiMatches(const std::string& var, return; } + if (tolower(collection) == "session" + && !m_session_collection_key.empty()) { + m_session_collection->resolveMultiMatches(var, + m_session_collection_key, l); + return; + } + try { this->at(collection)->resolveMultiMatches(var, l); } catch (...) { } @@ -231,6 +259,13 @@ void Collections::resolveRegularExpression(const std::string& var, return; } + if (tolower(collection) == "session" + && !m_session_collection_key.empty()) { + m_session_collection->resolveRegularExpression(toupper(collection) + + ":" + var, m_session_collection_key, l); + return; + } + try { this->at(collection)->resolveRegularExpression(var, l); } catch (...) { } diff --git a/src/modsecurity.cc b/src/modsecurity.cc index 61fa83d4..47467189 100644 --- a/src/modsecurity.cc +++ b/src/modsecurity.cc @@ -48,6 +48,7 @@ ModSecurity::ModSecurity() : m_connector(""), m_global_collection(new collection::backend::InMemoryPerProcess()), m_ip_collection(new collection::backend::InMemoryPerProcess()), + m_session_collection(new collection::backend::InMemoryPerProcess()), m_logCb(NULL) { UniqueId::uniqueId(); srand(time(NULL)); diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index 7f33ba66..fa73fa39 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -24,6 +24,7 @@ class Driver; #include "actions/audit_log.h" #include "actions/ctl_audit_log_parts.h" #include "actions/init_col.h" +#include "actions/set_sid.h" #include "actions/set_var.h" #include "actions/severity.h" #include "actions/skip_after.h" @@ -66,6 +67,7 @@ using modsecurity::actions::Accuracy; using modsecurity::actions::Action; using modsecurity::actions::CtlAuditLogParts; using modsecurity::actions::InitCol; +using modsecurity::actions::SetSID; using modsecurity::actions::SetVar; using modsecurity::actions::Severity; using modsecurity::actions::Tag; @@ -906,7 +908,7 @@ act: TODO: setEnv is not implemented yet. std::string error; - SetEnv *setEnv = new SetEnv($1); + SetEnv *setEnv = new s($1); if (setEnv->init(&error) == false) { driver.parserError << error; @@ -919,12 +921,8 @@ act: } | ACTION_SETSID { - /* - - TODO: setSID is not implemented yet. - std::string error; - SetEnv *setSID = new SetSID($1); + SetSID *setSID = new SetSID($1); if (setSID->init(&error) == false) { driver.parserError << error; @@ -932,8 +930,6 @@ act: } $$ = setSID; - */ - $$ = Action::instantiate($1); } | ACTION_SETUID { diff --git a/src/transaction.cc b/src/transaction.cc index c99a3020..b69dd1cd 100644 --- a/src/transaction.cc +++ b/src/transaction.cc @@ -112,7 +112,8 @@ Transaction::Transaction(ModSecurity *ms, Rules *rules, void *logCbData) m_creationTimeStamp(cpu_seconds()), m_logCbData(logCbData), m_ms(ms), - m_collections(ms->m_global_collection, ms->m_ip_collection) { + m_collections(ms->m_global_collection, ms->m_ip_collection, + ms->m_session_collection) { m_id = std::to_string(this->m_timeStamp) + \ std::to_string(generate_transaction_unique_id()); m_rules->incrementReferenceCount(); diff --git a/test/test-cases/regression/action-setsid.json b/test/test-cases/regression/action-setsid.json new file mode 100644 index 00000000..82c94139 --- /dev/null +++ b/test/test-cases/regression/action-setsid.json @@ -0,0 +1,37 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing setsid action", + "expected":{ + "debug_log": "Saving variable: SESSION:score with value: 5" + }, + "client":{ + "ip":"200.249.12.31", + "port":123 + }, + "request":{ + "headers":{ + "Host":"localhost", + "User-Agent":"curl/7.38.0", + "Accept":"*/*", + "User-Agent":"My sweet little browser", + "Cookie": "PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120" + }, + "uri":"/?key=value&key=other_value", + "method":"GET" + }, + "server":{ + "ip":"200.249.12.31", + "port":80 + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecRule REQUEST_HEADERS:User-Agent \"^(.*)$\" \"id:'900018',phase:1,t:none,t:sha1,t:hexEncode,setsid:%{REQUEST_COOKIES:PHPSESSID}%,nolog,pass\"", + "SecRule REQUEST_HEADERS \".*\" \"id:'900021',phase:1,setvar:SESSION.score=+10\"", + "SecRule REQUEST_HEADERS:User-Agent \"^(.*)$\" \"id:'900068',phase:1,t:none,t:sha1,t:hexEncode,setsid:%{REQUEST_COOKIES:PHPSESSID}2,nolog,pass\"", + "SecRule REQUEST_HEADERS \".*\" \"id:'900022',phase:1,setvar:SESSION.score=+5\"" + ] + } +] \ No newline at end of file diff --git a/test/test-cases/secrules-language-tests b/test/test-cases/secrules-language-tests index ee477d11..8089e2ef 160000 --- a/test/test-cases/secrules-language-tests +++ b/test/test-cases/secrules-language-tests @@ -1 +1 @@ -Subproject commit ee477d117430f695fd556afa7132de923ccd5d76 +Subproject commit 8089e2ef12e8572c7d9feb8463e608b20de928ba