diff --git a/src/Makefile.am b/src/Makefile.am index 5d128028..1948b2ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,8 +45,9 @@ VARIABLES = \ variables/time_wday.cc \ variables/time_year.cc \ variables/tx.cc \ - variables/variable.cc - + variables/variable.cc \ + variables/variations/count.cc \ + variables/variations/exclusion.cc ACTIONS = \ diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index 1ada6c61..45cd9f99 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -23,6 +23,8 @@ class Driver; #include "utils/geo_lookup.h" #include "audit_log.h" +#include "variables/variations/count.h" +#include "variables/variations/exclusion.h" #include "variables/duration.h" #include "variables/env.h" #include "variables/highest_severity.h" @@ -43,6 +45,8 @@ using ModSecurity::operators::Operator; using ModSecurity::Rule; using ModSecurity::Utils::GeoLookup; +using ModSecurity::Variables::Variations::Count; +using ModSecurity::Variables::Variations::Exclusion; using ModSecurity::Variables::Duration; using ModSecurity::Variables::Env; using ModSecurity::Variables::HighestSeverity; @@ -58,6 +62,22 @@ using ModSecurity::Variables::TimeWDay; using ModSecurity::Variables::TimeYear; using ModSecurity::Variables::Variable; +#define CHECK_VARIATION_DECL \ + Variable *var = NULL; \ + bool t = false; + +#define CHECK_VARIATION(a) \ + if (var == NULL) { \ + if (name.at(0) == std::string(#a).at(0)) { \ + name.erase(0, 1); \ + t = true ; \ + } \ + } else { \ + t = false; \ + } \ + if (t) + + /** * %destructor { code } THING * @@ -168,6 +188,7 @@ using ModSecurity::Variables::Variable; %type *> actions %type *> variables +%type var %printer { yyoutput << $$; } <*>; @@ -354,174 +375,147 @@ expression: driver.remoteRulesActionOnFailed = Rules::OnFailedRemoteRulesAction::WarnOnFailedRemoteRulesAction; } + variables: - variables PIPE VARIABLE + variables PIPE var { std::vector *v = $1; - v->push_back(new Variable($3)); + v->push_back($3); $$ = $1; } - | VARIABLE + | var { std::vector *variables = new std::vector; - variables->push_back(new Variable($1)); + variables->push_back($1); $$ = variables; } - | variables PIPE RUN_TIME_VAR_DUR + +var: + VARIABLE { - std::vector *v = $1; - v->push_back(new Duration($3)); - $$ = $1; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new Variable(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new Variable(name)); } + if (!var) { var = new Variable(name); } + $$ = var; } | RUN_TIME_VAR_DUR { - std::vector *variables = new std::vector; - variables->push_back(new Duration($1)); - $$ = variables; - } - | variables PIPE RUN_TIME_VAR_ENV - { - std::vector *v = $1; - v->push_back(new Env($3)); - $$ = $1; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new Duration(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new Duration(name)); } + if (!var) { var = new Duration(name); } + $$ = var; } | RUN_TIME_VAR_ENV { - std::vector *variables = new std::vector; - variables->push_back(new Env($1)); - $$ = variables; - } - | variables PIPE RUN_TIME_VAR_BLD - { - std::vector *v = $1; - v->push_back(new ModsecBuild($3)); - $$ = $1; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new Env(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new Env(name)); } + if (!var) { var = new Env(name); } + $$ = var; } | RUN_TIME_VAR_BLD { - std::vector *variables = new std::vector; - variables->push_back(new ModsecBuild($1)); - $$ = variables; - } - | variables PIPE RUN_TIME_VAR_HSV - { - std::vector *v = $1; - v->push_back(new HighestSeverity($3)); - $$ = $1; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new ModsecBuild(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new ModsecBuild(name)); } + if (!var) { var = new ModsecBuild(name); } + $$ = var; } | RUN_TIME_VAR_HSV { - std::vector *variables = new std::vector; - variables->push_back(new HighestSeverity($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new HighestSeverity(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new HighestSeverity(name)); } + if (!var) { var = new HighestSeverity(name); } + $$ = var; } | RUN_TIME_VAR_TIME { - std::vector *variables = new std::vector; - variables->push_back(new Time($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new Time(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new Time(name)); } + if (!var) { var = new Time(name); } + $$ = var; } | RUN_TIME_VAR_TIME_DAY { - std::vector *variables = new std::vector; - variables->push_back(new TimeDay($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeDay(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeDay(name)); } + if (!var) { var = new TimeDay(name); } + $$ = var; } | RUN_TIME_VAR_TIME_EPOCH { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeEpoch($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeEpoch(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeEpoch(name)); } + if (!var) { var = new TimeEpoch(name); } + $$ = var; } | RUN_TIME_VAR_TIME_HOUR { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeHour($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeHour(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeHour(name)); } + if (!var) { var = new TimeHour(name); } + $$ = var; } | RUN_TIME_VAR_TIME_MIN { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeMin($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeMin(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeMin(name)); } + if (!var) { var = new TimeMin(name); } + $$ = var; } | RUN_TIME_VAR_TIME_MON { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeMon($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeMon(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeMon(name)); } + if (!var) { var = new TimeMon(name); } + $$ = var; } | RUN_TIME_VAR_TIME_SEC { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeSec($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeSec(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeSec(name)); } + if (!var) { var = new TimeSec(name); } + $$ = var; } | RUN_TIME_VAR_TIME_WDAY { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeWDay($1)); - $$ = variables; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeWDay(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeWDay(name)); } + if (!var) { var = new TimeWDay(name); } + $$ = var; } | RUN_TIME_VAR_TIME_YEAR { - std::vector *variables = new std::vector; - variables->push_back(new ModSecurity::Variables::TimeYear($1)); - $$ = variables; - } - | variables PIPE RUN_TIME_VAR_TIME - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::Time($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_DAY - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeDay($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_EPOCH - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeEpoch($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_HOUR - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeHour($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_MIN - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeMin($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_MON - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeMon($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_SEC - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeSec($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_WDAY - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeWDay($3)); - $$ = $1; - } - | variables PIPE RUN_TIME_VAR_TIME_YEAR - { - std::vector *v = $1; - v->push_back(new ModSecurity::Variables::TimeYear($3)); - $$ = $1; + std::string name($1); + CHECK_VARIATION_DECL + CHECK_VARIATION(&) { var = new Count(new TimeYear(name)); } + CHECK_VARIATION(!) { var = new Exclusion(new TimeYear(name)); } + if (!var) { var = new TimeYear(name); } + $$ = var; } actions: diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index 7751e356..a0e94feb 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -144,22 +144,22 @@ FREE_TEXT_NEW_LINE [^\"|\n]+ {CONFIG_DIR_DEBUG_LVL}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_DEBUG_LVL(strchr(yytext, ' ') + 1, *driver.loc.back()); } %{ /* Variables */ %} -{VARIABLE}:?{DICT_ELEMENT}? { return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_DUR} { return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_ENV}:?{DICT_ELEMENT}? { return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_BLD} { return yy::seclang_parser::make_RUN_TIME_VAR_BLD(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_HSV} { return yy::seclang_parser::make_RUN_TIME_VAR_HSV(yytext, *driver.loc.back()); } +[!|&]?{VARIABLE}:?{DICT_ELEMENT}? { return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_DUR} { return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_ENV}:?{DICT_ELEMENT}? { return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_BLD} { return yy::seclang_parser::make_RUN_TIME_VAR_BLD(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_HSV} { return yy::seclang_parser::make_RUN_TIME_VAR_HSV(yytext, *driver.loc.back()); } %{ /* Variables: TIME */ %} -{RUN_TIME_VAR_TIME} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_DAY} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_DAY(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_EPOCH} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_EPOCH(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_HOUR} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_HOUR(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_MIN} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MIN(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_MON} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MON(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_SEC} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_SEC(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_WDAY} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_WDAY(yytext, *driver.loc.back()); } -{RUN_TIME_VAR_TIME_YEAR} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_YEAR(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_DAY} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_DAY(yytext, *driver.loc.back()); } +[!|&]?[&]?{RUN_TIME_VAR_TIME_EPOCH} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_EPOCH(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_HOUR} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_HOUR(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_MIN} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MIN(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_MON} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_MON(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_SEC} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_SEC(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_WDAY} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_WDAY(yytext, *driver.loc.back()); } +[!|&]?{RUN_TIME_VAR_TIME_YEAR} { return yy::seclang_parser::make_RUN_TIME_VAR_TIME_YEAR(yytext, *driver.loc.back()); } %{ /* Geo DB loopkup */ %} {CONFIG_DIR_GEO_DB}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONFIG_DIR_GEO_DB(strchr(yytext, ' ') + 1, *driver.loc.back()); } diff --git a/src/rule.cc b/src/rule.cc index 264921e7..a1b069a1 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -27,7 +28,9 @@ #include "actions/action.h" #include "modsecurity/modsecurity.h" #include "actions/transformations/none.h" +#include "variables/variation/exclusion.h" +using ModSecurity::Variables::Variation::Exclusion; namespace ModSecurity { @@ -108,14 +111,39 @@ bool Rule::evaluate(Assay *assay) { clock_t begin = clock(); + std::list exclusions; + for (int i = 0; i < variables->size(); i++) { + Variable *variable = variables->at(i); + Exclusion *exl = dynamic_cast(variable); + + if (exl != NULL) { + std::list> z = + variable->evaluate(assay); + for (auto &y : z) { + exclusions.push_back(y.first); + } + exclusions.push_back(variable->name); + } + } + for (int i = 0; i < variables->size(); i++) { int transformations = 0; Variable *variable = variables->at(i); + Exclusion *exl = dynamic_cast(variable); + if (exl != NULL) { + continue; + } std::list> e = variable->evaluate(assay); for (auto &v : e) { + if (std::find(exclusions.begin(), exclusions.end(), + v.first) != exclusions.end()) { + assay->debug(9, "Variable: " + v.first + " is part of the" + + " exclusion list, skipping..."); + continue; + } std::string value = v.second; int none = 0; for (Action *a : this->actions_runtime_pre) { diff --git a/src/variables/variable.cc b/src/variables/variable.cc index 0619849b..c3f12464 100644 --- a/src/variables/variable.cc +++ b/src/variables/variable.cc @@ -21,6 +21,9 @@ #include #include "modsecurity/assay.h" +#include "variations/exclusion.h" + +using ModSecurity::Variables::Variations::Exclusion; namespace ModSecurity { namespace Variables { @@ -33,8 +36,18 @@ std::list> std::string Variable::to_s( std::vector *variables) { std::string ret; + std::string except(""); for (int i = 0; i < variables->size() ; i++) { std::string name = variables->at(i)->name; + Exclusion *e = dynamic_cast(variables->at(i)); + if (e != NULL) { + if (except.empty()) { + except = except + name; + } else { + except = except + "|" + name; + } + continue; + } if (i == 0) { ret = ret + name; @@ -43,6 +56,9 @@ std::string Variable::to_s( } } + if (except.empty() == false) { + ret = ret + ", except for: " + except; + } return ret; } diff --git a/src/variables/variations/count.cc b/src/variables/variations/count.cc new file mode 100644 index 00000000..4c55c4a4 --- /dev/null +++ b/src/variables/variations/count.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 "variables/variations/count.h" + +#include +#include +#include +#include +#include + +#include "modsecurity/assay.h" +#include "src/utils.h" + +namespace ModSecurity { +namespace Variables { +namespace Variations { + +std::list> + Count::evaluate(Assay *assay) { + std::list> reslIn; + std::list> reslOut; + std::pair pair; + int count = 0; + + reslIn = var->evaluate(assay); + + for (auto &a : reslIn) { + count++; + } + + std::string res = std::to_string(count); + + pair = std::make_pair(std::string(var->name), std::string(res)); + reslOut.push_back(pair); + + return reslOut; +} + + +} // namespace Variations +} // namespace Variables +} // namespace ModSecurity diff --git a/src/variables/variations/count.h b/src/variables/variations/count.h new file mode 100644 index 00000000..dfb9bebe --- /dev/null +++ b/src/variables/variations/count.h @@ -0,0 +1,49 @@ +/* + * 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_VARIABLES_VARIATIONS_COUNT_H_ +#define SRC_VARIABLES_VARIATIONS_COUNT_H_ + +#include "variables/variable.h" + +namespace ModSecurity { + +class Assay; +namespace Variables { +namespace Variations { + +class Count : public Variable { + public: + explicit Count(Variable *v) + : Variable("count(" + v->name + ")"), + var(v) { } + + std::list> + evaluate(Assay *assay) override; + + Variable *var; +}; + + +} // namespace Variations +} // namespace Variables +} // namespace ModSecurity + +#endif // SRC_VARIABLES_VARIATIONS_COUNT_H_ diff --git a/src/variables/variations/exclusion.cc b/src/variables/variations/exclusion.cc new file mode 100644 index 00000000..b7400720 --- /dev/null +++ b/src/variables/variations/exclusion.cc @@ -0,0 +1,40 @@ +/* + * 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 "variables/variations/exclusion.h" + +#include +#include +#include +#include +#include + +#include "modsecurity/assay.h" +#include "src/utils.h" + +namespace ModSecurity { +namespace Variables { +namespace Variations { + + +std::list> + Exclusion::evaluate(Assay *assay) { + return assay->resolve_variable(this->name); +} + + +} // namespace Variations +} // namespace Variables +} // namespace ModSecurity diff --git a/src/variables/variations/exclusion.h b/src/variables/variations/exclusion.h new file mode 100644 index 00000000..e99bf643 --- /dev/null +++ b/src/variables/variations/exclusion.h @@ -0,0 +1,50 @@ +/* + * 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 +#include + +#ifndef SRC_VARIABLES_VARIATIONS_EXCLUSION_H_ +#define SRC_VARIABLES_VARIATIONS_EXCLUSION_H_ + +#include "variables/variable.h" + +namespace ModSecurity { + +class Assay; +namespace Variables { +namespace Variations { + +class Exclusion : public Variable { + public: + explicit Exclusion(Variable *v) + : Variable(v->name), + var(v) { } + + std::list> + evaluate(Assay *assay) override; + + Variable *var; +}; + + +} // namespace Variations +} // namespace Variables +} // namespace ModSecurity + +#endif // SRC_VARIABLES_VARIATIONS_EXCLUSION_H_