From 95c2fed89c0da300fdf32f91f7044618c8ddecba Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Tue, 21 Jul 2015 01:09:13 -0300 Subject: [PATCH] Adds support to severity action and HIGHEST_SEVERITY variable --- headers/modsecurity/assay.h | 1 + src/Makefile.am | 2 + src/actions/action.cc | 5 ++ src/actions/severity.cc | 66 ++++++++++++++ src/actions/severity.h | 46 ++++++++++ src/assay.cc | 1 + src/parser/seclang-parser.yy | 42 +++++++++ src/parser/seclang-scanner.ll | 7 +- src/variable_highest_severity.cc | 41 +++++++++ src/variable_highest_severity.h | 41 +++++++++ .../regression/variable-HIGHEST_SEVERITY.json | 87 +++++++++++++++++++ 11 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 src/actions/severity.cc create mode 100644 src/actions/severity.h create mode 100644 src/variable_highest_severity.cc create mode 100644 src/variable_highest_severity.h create mode 100644 test/test-cases/regression/variable-HIGHEST_SEVERITY.json diff --git a/headers/modsecurity/assay.h b/headers/modsecurity/assay.h index a7e6ca19..6ea7e66b 100644 --- a/headers/modsecurity/assay.h +++ b/headers/modsecurity/assay.h @@ -188,6 +188,7 @@ class Assay { std::string id; time_t timeStamp; std::chrono::system_clock::time_point start; + int highest_severity; private: std::ofstream myfile; diff --git a/src/Makefile.am b/src/Makefile.am index 210fdb53..c93406a4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,6 +37,7 @@ ACTIONS = \ actions/phase.cc \ actions/redirect.cc \ actions/rule_id.cc \ + actions/severity.cc \ actions/status.cc \ actions/transformations/base64_decode.cc \ actions/transformations/base64_decode_ext.cc \ @@ -100,6 +101,7 @@ libmodsecurity_la_SOURCES = \ variable_duration.cc \ variable_env.cc \ variable_modsec_build.cc \ + variable_highest_severity.cc \ operators/operator.cc \ operators/detect_sqli.cc \ operators/detect_xss.cc \ diff --git a/src/actions/action.cc b/src/actions/action.cc index 6dae6891..8605a8b2 100644 --- a/src/actions/action.cc +++ b/src/actions/action.cc @@ -24,6 +24,7 @@ #include "actions/status.h" #include "actions/rule_id.h" #include "actions/phase.h" +#include "actions/severity.h" #define IF_MATCH(a) \ @@ -58,6 +59,7 @@ Action *Action::instantiate(std::string name) { std::string block("block"); std::string phase("phase:"); std::string rule_id("id:"); + std::string severity("severity:"); if (name.compare(0, status.length(), status) == 0) { return new Status(name); @@ -74,6 +76,9 @@ Action *Action::instantiate(std::string name) { if (name.compare(0, rule_id.length(), rule_id) == 0) { return new RuleId(name); } + if (name.compare(0, severity.length(), severity) == 0) { + return new Severity(name); + } return new Action(name); } diff --git a/src/actions/severity.cc b/src/actions/severity.cc new file mode 100644 index 00000000..3dfde48b --- /dev/null +++ b/src/actions/severity.cc @@ -0,0 +1,66 @@ +/* + * 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/severity.h" + +#include +#include + +#include "actions/action.h" +#include "modsecurity/assay.h" +#include "src/utils.h" + +namespace ModSecurity { +namespace actions { + +Severity::Severity(std::string action) + : Action(action, RunTimeOnlyIfMatchKind) { + std::string a = action; + a.erase(0, 9); + if (tolower(a) == "emergency") { + this->m_severity = 0; + } else if (tolower(a) == "alert") { + this->m_severity = 1; + } else if (tolower(a) == "critical") { + this->m_severity = 2; + } else if (tolower(a) == "error") { + this->m_severity = 3; + } else if (tolower(a) == "warning") { + this->m_severity = 4; + } else if (tolower(a) == "notice") { + this->m_severity = 5; + } else if (tolower(a) == "info") { + this->m_severity = 6; + } else if (tolower(a) == "debug") { + this->m_severity = 7; + } else { + this->m_severity = std::stod(a); + } +} + + +bool Severity::evaluate(Assay *assay) { + assay->debug(9, "This rule severity is: " + \ + std::to_string(this->m_severity) + " current assay is: " + \ + std::to_string(assay->highest_severity)); + + if (assay->highest_severity > this->m_severity) { + assay->highest_severity = this->m_severity; + } + return true; +} + +} // namespace actions +} // namespace ModSecurity diff --git a/src/actions/severity.h b/src/actions/severity.h new file mode 100644 index 00000000..04e14274 --- /dev/null +++ b/src/actions/severity.h @@ -0,0 +1,46 @@ +/* + * 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_SEVERITY_H_ +#define SRC_ACTIONS_SEVERITY_H_ + +#ifdef __cplusplus +class Assay; + +namespace ModSecurity { +class Assay; + +namespace actions { + + +class Severity : public Action { + public: + explicit Severity(std::string action); + + bool evaluate(Assay *assay) override; + + private: + int m_severity; +}; + +} // namespace actions +} // namespace ModSecurity +#endif + +#endif // SRC_ACTIONS_SEVERITY_H_ diff --git a/src/assay.cc b/src/assay.cc index fb505773..0a9cbecd 100644 --- a/src/assay.cc +++ b/src/assay.cc @@ -92,6 +92,7 @@ Assay::Assay(ModSecurity *ms, Rules *rules) do_not_save_in_auditlog(false), timeStamp(std::time(NULL)), httpCodeReturned(200), + highest_severity(255), m_ARGScombinedSize(0), m_ARGScombinedSizeStr(NULL), m_namesArgs(NULL), diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index d5e81b9f..3846396c 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -18,6 +18,7 @@ class Driver; #include "variable_duration.h" #include "variable_env.h" #include "variable_modsec_build.h" +#include "variable_highest_severity.h" #include "utils/geo_lookup.h" using ModSecurity::actions::Action; @@ -27,6 +28,7 @@ using ModSecurity::Variable; using ModSecurity::VariableDuration; using ModSecurity::VariableEnv; using ModSecurity::VariableModsecBuild; +using ModSecurity::VariableHighestSeverity; using ModSecurity::Rule; using ModSecurity::Utils::GeoLookup; @@ -91,11 +93,13 @@ using ModSecurity::Utils::GeoLookup; %token RUN_TIME_VAR_DUR %token RUN_TIME_VAR_ENV %token RUN_TIME_VAR_BLD +%token RUN_TIME_VAR_HSV %token CONFIG_DIR_GEO_DB %token OPERATOR %token ACTION +%token ACTION_SEVERITY %token TRANSFORMATION %token CONFIG_VALUE_NUMBER @@ -296,7 +300,20 @@ variables: variables->push_back(new VariableModsecBuild($1)); $$ = variables; } + | variables PIPE RUN_TIME_VAR_HSV + { + std::vector *v = $1; + v->push_back(new VariableHighestSeverity($3)); + $$ = $1; + } + | RUN_TIME_VAR_HSV + { + std::vector *variables = new std::vector; + variables->push_back(new VariableHighestSeverity($1)); + $$ = variables; + } + actions: actions COMMA SPACE ACTION { @@ -350,6 +367,31 @@ actions: actions->push_back(Transformation::instantiate($1)); $$ = actions; } + | actions COMMA SPACE ACTION_SEVERITY + { + std::vector *a = $1; + a->push_back(Action::instantiate($4)); + $$ = $1; + } + | actions COMMA ACTION_SEVERITY + { + std::vector *a = $1; + a->push_back(Action::instantiate($3)); + $$ = $1; + } + | SPACE ACTION_SEVERITY + { + std::vector *actions = new std::vector; + actions->push_back(Action::instantiate($2)); + $$ = actions; + + } + | ACTION_SEVERITY + { + std::vector *actions = new std::vector; + actions->push_back(Action::instantiate($1)); + $$ = actions; + } %% diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index c0db21a2..6ccb6243 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -17,8 +17,8 @@ static yy::location loc; %} %option noyywrap nounput batch debug noinput -ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|ctl|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|initcol|log|logdata|maturity|msg|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-z0-9_\|\&\:\/\/\.]+|rev|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|severity|setuid|setrsc|setsid|setenv|setvar|skip|skipAfter|status:[0-9]+|tag|ver|xmlns|t) - +ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|ctl|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|initcol|log|logdata|maturity|msg|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-z0-9_\|\&\:\/\/\.]+|rev|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|setuid|setrsc|setsid|setenv|setvar|skip|skipAfter|status:[0-9]+|tag|ver|xmlns|t) +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)') DIRECTIVE SecRule CONFIG_DIRECTIVE SecRequestBodyLimitAction|SecRequestBodyNoFilesLimit|SecRequestBodyInMemoryLimit|SecRequestBodyLimit|SecPcreMatchLimitRecursion|SecPcreMatchLimit|SecResponseBodyMimeType|SecResponseBodyLimitAction|SecResponseBodyLimit|SecTmpDir|SecDataDir|SecArgumentSeparator|SecCookieFormat|SecStatusEngine @@ -61,6 +61,7 @@ VARIABLE (?i:FULL_REQUEST|FILES|AUTH_TYPE|ARGS_NAMES|ARGS|QUERY_STRING| RUN_TIME_VAR_DUR (?i:DURATION) RUN_TIME_VAR_ENV (?i:ENV) RUN_TIME_VAR_BLD (?i:MODSEC_BUILD) +RUN_TIME_VAR_HSV (?i:HIGHEST_SEVERITY) VARIABLENOCOLON (?i:REQBODY_ERROR|MULTIPART_STRICT_ERROR|MULTIPART_UNMATCHED_BOUNDARY|REMOTE_ADDR|REQUEST_LINE) @@ -116,6 +117,7 @@ FREE_TEXT_NEW_LINE [^\"|\n]+ {RUN_TIME_VAR_DUR} { return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, loc); } {RUN_TIME_VAR_ENV}:?{DICT_ELEMENT}? { return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, loc); } {RUN_TIME_VAR_BLD} { return yy::seclang_parser::make_RUN_TIME_VAR_BLD(yytext, loc); } +{RUN_TIME_VAR_HSV} { return yy::seclang_parser::make_RUN_TIME_VAR_HSV(yytext, loc); } %{ /* Geo DB loopkup */ %} {CONFIG_DIR_GEO_DB}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONFIG_DIR_GEO_DB(strchr(yytext, ' ') + 1, loc); } @@ -131,6 +133,7 @@ FREE_TEXT_NEW_LINE [^\"|\n]+ ["]{OPERATOR}[ ]{FREE_TEXT}["] { return yy::seclang_parser::make_OPERATOR(yytext, loc); } ["]{OPERATORNOARG}["] { return yy::seclang_parser::make_OPERATOR(yytext, loc); } {ACTION} { return yy::seclang_parser::make_ACTION(yytext, loc); } +{ACTION_SEVERITY} { return yy::seclang_parser::make_ACTION_SEVERITY(yytext, loc); } ["] { return yy::seclang_parser::make_QUOTATION_MARK(loc); } [,] { return yy::seclang_parser::make_COMMA(loc); } [|] { return yy::seclang_parser::make_PIPE(loc); } diff --git a/src/variable_highest_severity.cc b/src/variable_highest_severity.cc new file mode 100644 index 00000000..5c7be1be --- /dev/null +++ b/src/variable_highest_severity.cc @@ -0,0 +1,41 @@ +/** + * 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 "src/variable_highest_severity.h" + +#include +#include +#include +#include +#include + +#include "modsecurity/assay.h" + +namespace ModSecurity { + +std::list> + VariableHighestSeverity::evaluate(Assay *assay) { + std::list> resl; + std::pair pair; + + pair = std::make_pair(std::string("HIGHEST_SEVERITY"), + std::to_string(assay->highest_severity)); + resl.push_back(pair); + + return resl; +} + + +} // namespace ModSecurity diff --git a/src/variable_highest_severity.h b/src/variable_highest_severity.h new file mode 100644 index 00000000..aa1dbfeb --- /dev/null +++ b/src/variable_highest_severity.h @@ -0,0 +1,41 @@ +/** + * 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 +#include +#include + +#ifndef SRC_VARIABLE_HIGHEST_SEVERITY_H_ +#define SRC_VARIABLE_HIGHEST_SEVERITY_H_ + +#include "src/variable.h" + +namespace ModSecurity { + +class Assay; + +class VariableHighestSeverity : public Variable { + public: + explicit VariableHighestSeverity(std::string _name) + : Variable(_name) { } + + std::list> + evaluate(Assay *assay) override; +}; + +} // namespace ModSecurity + +#endif // SRC_VARIABLE_HIGHEST_SEVERITY_H_ diff --git a/test/test-cases/regression/variable-HIGHEST_SEVERITY.json b/test/test-cases/regression/variable-HIGHEST_SEVERITY.json new file mode 100644 index 00000000..a0583b12 --- /dev/null +++ b/test/test-cases/regression/variable-HIGHEST_SEVERITY.json @@ -0,0 +1,87 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: HIGHEST_SEVERITY (1/2)", + "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":"*/*" + }, + "uri":"/?key=value&key=other_value", + "protocol":"GET" + }, + "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: \"0\" \\(Variable: HIGHEST_SEVERITY\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REMOTE_ADDR \"@contains 200.249\" \"pass,t:trim,severity:0\"", + "SecRule HIGHEST_SEVERITY \"@lt 10\" \"pass,t:trim\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: HIGHEST_SEVERITY (2/2)", + "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":"*/*" + }, + "uri":"/?key=value&key=other_value", + "protocol":"GET" + }, + "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: \"0\" \\(Variable: HIGHEST_SEVERITY\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REMOTE_ADDR \"@contains 200.249\" \"pass,t:trim,severity:EMERGENCY\"", + "SecRule HIGHEST_SEVERITY \"@lt 10\" \"pass,t:trim\"" + ] + } +] +