From ad9393a8c21e8bcabbb6c25ab3c840b2ad9f2624 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Fri, 7 Aug 2015 02:03:07 -0300 Subject: [PATCH] Adds support for the tag action --- headers/modsecurity/assay.h | 1 + src/Makefile.am | 1 + src/actions/tag.cc | 45 ++++++++ src/actions/tag.h | 44 ++++++++ src/parser/seclang-parser.yy | 25 +++++ src/parser/seclang-scanner.ll | 4 +- test/test-cases/regression/action-tag.json | 122 +++++++++++++++++++++ 7 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/actions/tag.cc create mode 100644 src/actions/tag.h create mode 100644 test/test-cases/regression/action-tag.json diff --git a/headers/modsecurity/assay.h b/headers/modsecurity/assay.h index 66bd3130..01a58fb7 100644 --- a/headers/modsecurity/assay.h +++ b/headers/modsecurity/assay.h @@ -260,6 +260,7 @@ class Assay { Rules *m_rules; std::list rulesMessages; + std::list ruleTags; private: std::ofstream myfile; diff --git a/src/Makefile.am b/src/Makefile.am index 9c7e7433..1d16bb51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,6 +64,7 @@ ACTIONS = \ actions/severity.cc \ actions/set_var.cc \ actions/status.cc \ + actions/tag.cc \ actions/transformations/base64_decode.cc \ actions/transformations/base64_decode_ext.cc \ actions/transformations/cmd_line.cc \ diff --git a/src/actions/tag.cc b/src/actions/tag.cc new file mode 100644 index 00000000..f1418cc9 --- /dev/null +++ b/src/actions/tag.cc @@ -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 "actions/tag.h" + +#include +#include + +#include "actions/action.h" +#include "modsecurity/assay.h" +#include "src/utils.h" +#include "src/macro_expansion.h" + +namespace ModSecurity { +namespace actions { + +Tag::Tag(std::string action) + : Action(action, RunTimeOnlyIfMatchKind), + m_tag(action) { + m_tag.erase(0, 1); + m_tag.pop_back(); +} + + +bool Tag::evaluate(Rule *rule, Assay *assay) { + std::string tag = MacroExpansion::expand(m_tag, assay); + assay->debug(9, "Rule tag: " + tag); + assay->ruleTags.push_back(tag); + return true; +} + +} // namespace actions +} // namespace ModSecurity diff --git a/src/actions/tag.h b/src/actions/tag.h new file mode 100644 index 00000000..f8dcde20 --- /dev/null +++ b/src/actions/tag.h @@ -0,0 +1,44 @@ +/* + * 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_TAG_H_ +#define SRC_ACTIONS_TAG_H_ + +class Assay; + +namespace ModSecurity { +class Assay; +namespace actions { + + +class Tag : public Action { + public: + explicit Tag(std::string action); + + bool evaluate(Rule *rule, Assay *assay) override; + + private: + std::string m_tag; +}; + + +} // namespace actions +} // namespace ModSecurity + +#endif // SRC_ACTIONS_TAG_H_ diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index 9fad406f..fdfdca18 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -19,6 +19,7 @@ class Driver; #include "actions/action.h" #include "actions/set_var.h" #include "actions/msg.h" +#include "actions/tag.h" #include "actions/transformations/transformation.h" #include "operators/operator.h" #include "rule.h" @@ -43,6 +44,7 @@ class Driver; using ModSecurity::actions::Action; using ModSecurity::actions::SetVar; +using ModSecurity::actions::Tag; using ModSecurity::actions::Msg; using ModSecurity::actions::transformations::Transformation; using ModSecurity::operators::Operator; @@ -189,6 +191,7 @@ using ModSecurity::Variables::Variable; %token ACTION_SEVERITY %token ACTION_SETVAR %token ACTION_MSG +%token ACTION_TAG %token TRANSFORMATION %token CONFIG_VALUE_NUMBER @@ -668,6 +671,28 @@ actions: actions->push_back(msg); $$ = actions; } + | actions COMMA ACTION_TAG + { + std::vector *a = $1; + Tag *tag = new Tag($3); + a->push_back(tag); + $$ = $1; + } + | SPACE ACTION_TAG + { + std::vector *actions = new std::vector; + Tag *tag = new Tag($2); + actions->push_back(tag); + $$ = actions; + + } + | ACTION_TAG + { + std::vector *actions = new std::vector; + Tag *tag = new Tag($1); + actions->push_back(tag); + $$ = actions; + } %% void diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index 6db2e91e..9918bf5c 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -23,10 +23,11 @@ using ModSecurity::split; %} %option noyywrap nounput batch debug noinput -ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|ctl|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|id:'[0-9]+'|initcol|log|logdata|maturity|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-Z0-9_\|\&\:\/\/\.]+|rev|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|setuid|setrsc|setsid|setenv|skip|skipAfter|status:[0-9]+|tag|ver|xmlns) +ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|ctl|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|id:'[0-9]+'|initcol|log|logdata|maturity|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-Z0-9_\|\&\:\/\/\.]+|rev|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|setuid|setrsc|setsid|setenv|skip|skipAfter|status:[0-9]+|ver|xmlns) ACTION_SEVERITY (?i:severity:[0-9]+|severity:'[0-9]+'|severity:(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)|severity:'(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)') ACTION_SETVAR (?i:setvar) ACTION_MSG (?i:msg) +ACTION_TAG (?i:tag) DIRECTIVE SecRule CONFIG_DIRECTIVE SecRequestBodyNoFilesLimit|SecRequestBodyInMemoryLimit|SecPcreMatchLimitRecursion|SecPcreMatchLimit|SecResponseBodyMimeType|SecTmpDir|SecDataDir|SecArgumentSeparator|SecCookieFormat|SecStatusEngine @@ -200,6 +201,7 @@ FREE_TEXT_NEW_LINE [^\"|\n]+ return yy::seclang_parser::make_ACTION_SETVAR(strchr(yytext, ':') + 1, *driver.loc.back()); } {ACTION_MSG}:'{FREE_TEXT}' { return yy::seclang_parser::make_ACTION_MSG(strchr(yytext, ':') + 1, *driver.loc.back()); } +{ACTION_TAG}:'{FREE_TEXT}' { return yy::seclang_parser::make_ACTION_TAG(strchr(yytext, ':') + 1, *driver.loc.back()); } ["] { return yy::seclang_parser::make_QUOTATION_MARK(*driver.loc.back()); } [,] { return yy::seclang_parser::make_COMMA(*driver.loc.back()); } diff --git a/test/test-cases/regression/action-tag.json b/test/test-cases/regression/action-tag.json new file mode 100644 index 00000000..f05d0d48 --- /dev/null +++ b/test/test-cases/regression/action-tag.json @@ -0,0 +1,122 @@ +[ + { + "enabled":1, + "version_min":300000, + "version_max":0, + "title":"Testing action :: tag 1", + "client":{ + "ip":"200.249.12.31", + "port":2313 + }, + "server":{ + "ip":"200.249.12.31", + "port":80 + }, + "request":{ + "headers":{ + "User-Agent":"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)", + "Accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8", + "Accept-Language":"en-us,en;q=0.5", + "Accept-Encoding":"gzip,deflate", + "Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7", + "Keep-Alive":"300", + "Connection":"keep-alive", + "Cookie":"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120", + "Pragma":"no-cache", + "Cache-Control":"no-cache" + }, + "uri":"\/test.pl?param1= test ¶m2=test2", + "protocol":"GET", + "http_version":1.1, + "body":"" + }, + "response":{ + "headers":{ + "Content-Type":"text\/xml; charset=utf-8\n\r", + "Content-Length":"length\n\r" + }, + "body":[ + "\n\r", + "\n\r", + " \n\r", + " \n\r", + " string<\/EnlightenResult>\n\r", + " <\/EnlightenResponse>\n\r", + " <\/soap:Body>\n\r", + "<\/soap:Envelope>\n\r" + ] + }, + "expected":{ + "audit_log":"", + "debug_log":"Rule tag: teste", + "error_log":"" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"tag:'teste',t:lowercase,t:none\"", + "SecRule TX \"@contains to_test\" \"t:lowercase,t:none\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "version_max":0, + "title":"Testing action :: tag 2", + "client":{ + "ip":"200.249.12.31", + "port":2313 + }, + "server":{ + "ip":"200.249.12.31", + "port":80 + }, + "request":{ + "headers":{ + "User-Agent":"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)", + "Accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8", + "Accept-Language":"en-us,en;q=0.5", + "Accept-Encoding":"gzip,deflate", + "Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7", + "Keep-Alive":"300", + "Connection":"keep-alive", + "Cookie":"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120", + "Pragma":"no-cache", + "Cache-Control":"no-cache" + }, + "uri":"\/test.pl?param1= test ¶m2=test2", + "protocol":"GET", + "http_version":1.1, + "body":"" + }, + "response":{ + "headers":{ + "Content-Type":"text\/xml; charset=utf-8\n\r", + "Content-Length":"length\n\r" + }, + "body":[ + "\n\r", + "\n\r", + " \n\r", + " \n\r", + " string<\/EnlightenResult>\n\r", + " <\/EnlightenResponse>\n\r", + " <\/soap:Body>\n\r", + "<\/soap:Envelope>\n\r" + ] + }, + "expected":{ + "audit_log":"", + "debug_log":"Rule tag: teste no-cache", + "error_log":"" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"tag:'teste %{REQUEST_HEADERS:Pragma}%',t:lowercase,t:none\"", + "SecRule TX \"@contains to_test\" \"t:lowercase,t:none\"" + ] + } +] \ No newline at end of file