From e54ef72051866ef56d53666df5693df7501c1bc0 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Tue, 6 Oct 2015 09:21:30 -0300 Subject: [PATCH] Looks for external resources in the same path of the rule --- src/operators/ip_match_from_file.cc | 3 ++- src/operators/ip_match_from_file.h | 2 +- src/operators/operator.h | 5 ++++- src/operators/pm_from_file.cc | 6 +++-- src/operators/pm_from_file.h | 2 +- src/operators/rx.cc | 1 + src/operators/validate_byte_range.cc | 3 ++- src/operators/validate_byte_range.h | 2 +- src/parser/driver.cc | 4 +++- src/parser/seclang-parser.yy | 25 ++++++++++++++++----- src/parser/seclang-scanner.ll | 11 ++++++---- src/rule.cc | 13 +++++++---- src/rule.h | 7 +++++- src/utils.cc | 33 ++++++++++++++++++++++++++++ src/utils.h | 2 ++ test/benchmark/basic_rules.conf | 2 -- test/unit/unit.cc | 2 +- 17 files changed, 96 insertions(+), 27 deletions(-) diff --git a/src/operators/ip_match_from_file.cc b/src/operators/ip_match_from_file.cc index faea0c7b..335f604c 100644 --- a/src/operators/ip_match_from_file.cc +++ b/src/operators/ip_match_from_file.cc @@ -23,7 +23,8 @@ namespace ModSecurity { namespace operators { -bool IpMatchFromFile::init(const char **error) { +bool IpMatchFromFile::init(const std::string &file, + const char **error) { std::string e(""); bool res = false; diff --git a/src/operators/ip_match_from_file.h b/src/operators/ip_match_from_file.h index 61649f54..f73c43a0 100644 --- a/src/operators/ip_match_from_file.h +++ b/src/operators/ip_match_from_file.h @@ -29,7 +29,7 @@ class IpMatchFromFile : public IpMatch { IpMatchFromFile(std::string op, std::string param, bool negation) : IpMatch(op, param, negation) { } - bool init(const char **error) override; + bool init(const std::string& file, const char **error) override; }; } // namespace operators diff --git a/src/operators/operator.h b/src/operators/operator.h index 20fabbcd..2f10e9b2 100644 --- a/src/operators/operator.h +++ b/src/operators/operator.h @@ -40,7 +40,10 @@ class Operator { std::string param; bool negation; - virtual bool init(const char **error) { return true; } + virtual bool init(const std::string &file, const char **error) { + return true; + } + virtual bool evaluate(Assay *assay); virtual bool evaluate(Assay *assay, const std::string &str); static Operator *instantiate(std::string op); diff --git a/src/operators/pm_from_file.cc b/src/operators/pm_from_file.cc index acff9b9b..2967007d 100644 --- a/src/operators/pm_from_file.cc +++ b/src/operators/pm_from_file.cc @@ -19,12 +19,13 @@ #include "operators/operator.h" #include "utils/https_client.h" +#include "src/utils.h" namespace ModSecurity { namespace operators { -bool PmFromFile::init(const char **error) { +bool PmFromFile::init(const std::string &config, const char **error) { std::istream *iss; if (param.compare(0, 8, "https://") == 0) { @@ -36,7 +37,8 @@ bool PmFromFile::init(const char **error) { } iss = new std::stringstream(client.content); } else { - iss = new std::ifstream(param, std::ios::in); + std::string resource = find_resource(param, config); + iss = new std::ifstream(resource, std::ios::in); if (((std::ifstream *)iss)->is_open() == false) { *error = std::string("Failed to open file: " + param).c_str(); diff --git a/src/operators/pm_from_file.h b/src/operators/pm_from_file.h index e39452ce..ce171f63 100644 --- a/src/operators/pm_from_file.h +++ b/src/operators/pm_from_file.h @@ -31,7 +31,7 @@ class PmFromFile : public Pm { PmFromFile(std::string op, std::string param, bool negation) : Pm(op, param, negation) { } - bool init(const char **error) override; + bool init(const std::string &file, const char **error) override; }; diff --git a/src/operators/rx.cc b/src/operators/rx.cc index 8c469e07..ebfe265f 100644 --- a/src/operators/rx.cc +++ b/src/operators/rx.cc @@ -30,6 +30,7 @@ bool Rx::evaluate(Assay *assay, const std::string& input) { SMatch match; if (regex_search(input, &match, *m_re) && match.size() >= 1) { + std::cout << "wheee" << std::endl; // this->matched.push_back(match.match); return true; } diff --git a/src/operators/validate_byte_range.cc b/src/operators/validate_byte_range.cc index 09612ed2..54516196 100644 --- a/src/operators/validate_byte_range.cc +++ b/src/operators/validate_byte_range.cc @@ -83,7 +83,8 @@ bool ValidateByteRange::getRange(const std::string &rangeRepresentation, } -bool ValidateByteRange::init(const char **error) { +bool ValidateByteRange::init(const std::string &file, + const char **error) { size_t pos = param.find_first_of(","); if (pos == std::string::npos) { diff --git a/src/operators/validate_byte_range.h b/src/operators/validate_byte_range.h index b310c20e..af274a1c 100644 --- a/src/operators/validate_byte_range.h +++ b/src/operators/validate_byte_range.h @@ -38,7 +38,7 @@ class ValidateByteRange : public Operator { bool evaluate(Assay *assay, const std::string &input) override; bool getRange(const std::string &rangeRepresentation, const char **error); - bool init(const char **error) override; + bool init(const std::string& file, const char **error) override; private: std::vector ranges; char table[32]; diff --git a/src/parser/driver.cc b/src/parser/driver.cc index 71131fdf..b555c599 100644 --- a/src/parser/driver.cc +++ b/src/parser/driver.cc @@ -90,7 +90,9 @@ int Driver::addSecRule(Rule *rule) { * by other rule */ if (rule->rule_id == 0) { - parserError << "Rules must have an ID." << std::endl; + parserError << "Rules must have an ID. File: "; + parserError << rule->m_fileName << " at line: "; + parserError << std::to_string(rule->m_lineNumber) << std::endl; return false; } for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) { diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index a497a9fd..ccd44f20 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -351,7 +351,7 @@ op: { Operator *op = Operator::instantiate($1); const char *error = NULL; - if (op->init(&error) == false) { + if (op->init(driver.ref.back(), &error) == false) { driver.error(@0, error); YYERROR; } @@ -361,7 +361,7 @@ op: { Operator *op = Operator::instantiate("\"@rx " + $1 + "\""); const char *error = NULL; - if (op->init(&error) == false) { + if (op->init(driver.ref.back(), &error) == false) { driver.error(@0, error); YYERROR; } @@ -375,7 +375,9 @@ expression: Rule *rule = new Rule( /* op */ $3, /* variables */ $2, - /* actions */ $4 + /* actions */ $4, + /* file name */ driver.ref.back(), + /* line number */ @0.end.line ); if (driver.addSecRule(rule) == false) { @@ -387,7 +389,9 @@ expression: Rule *rule = new Rule( /* op */ $3, /* variables */ $2, - /* actions */ NULL + /* actions */ NULL, + /* file name */ driver.ref.back(), + /* line number */ @0.end.line ); if (driver.addSecRule(rule) == false) { @@ -399,7 +403,9 @@ expression: Rule *rule = new Rule( /* op */ NULL, /* variables */ NULL, - /* actions */ $2 + /* actions */ $2, + /* file name */ driver.ref.back(), + /* line number */ @0.end.line ); driver.addSecAction(rule); } @@ -508,7 +514,14 @@ expression: /* Debug log: end */ | CONFIG_DIR_GEO_DB { - GeoLookup::getInstance().setDataBase($1); + std::string file = ModSecurity::find_resource($1, driver.ref.back()); + if (GeoLookup::getInstance().setDataBase(file) == false) { + std::stringstream ss; + ss << "Failed to load the GeoDB from: "; + ss << file; + driver.error(@0, ss.str()); + YYERROR; + } } /* Body limits */ | CONFIG_DIR_REQ_BODY_LIMIT diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index 23d5d9be..2e42e0da 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -98,7 +98,7 @@ CONFIG_SEC_REMOTE_RULES (?i:SecRemoteRules) CONFIG_SEC_REMOTE_RULES_FAIL_ACTION (?i:SecRemoteRulesFailAction) -DICT_ELEMENT [^ \|\t]+ +DICT_ELEMENT [^ \t]+ OPERATOR (?i:(?:@inspectFile|@fuzzyHash|@validateByteRange|@validateDTD|@validateHash|@validateSchema|@verifyCC|@verifyCPF|@verifySSN|@gsbLookup|@rsub)|(?:\!{0,1})(?:@within|@containsWord|@contains|@endsWith|@eq|@ge|@gt|@ipMatchF|@ipMatch|@ipMatchFromFile|@le|@lt|@pmf|@pm|@pmFromFile|@rbl|@rx|@streq|@strmatch|@beginsWith)) @@ -143,17 +143,20 @@ CONFIG_VALUE_PATH [0-9A-Za-z_/\.\-\*]+ AUDIT_PARTS [ABCDEFHJKIZ]+ CONFIG_VALUE_NUMBER [0-9]+ -FREE_TEXT ([^\"]|([^\\]\\\"))+ +FREE_TEXT ([^\"]|(\\\"))+ FREE_TEXT_NEW_LINE [^\"|\n]+ FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+ FREE_TEXT_SPACE [^ \t]+ FREE_TEXT_SPACE_COMMA [^, \t]+ +FREE_TEXT_SPACE_COMMA_QUOTE [^, \t\"]+ VAR_FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+ VAR_FREE_TEXT_SPACE_COMMA [^, \t\"]+ VAR_FREE_TEXT_SPACE [^ \t\"]+ +SOMETHING ["]{1}[^@]{1}([^"]|([^\\"]\\\"))*["]{1} + CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile) %x EXPECTING_OPERATOR COMMENT @@ -266,14 +269,14 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile) {CONFIG_DIR_SEC_MARKER}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONFIG_DIR_SEC_MARKER(strchr(yytext, ' ') + 1, *driver.loc.back()); } { -["][^@]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); } +{SOMETHING} { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); } ["]{OPERATOR}[ ]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); } ["]{OPERATORNOARG}[\t ]*["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); } } {ACTION} { return yy::seclang_parser::make_ACTION(yytext, *driver.loc.back()); } {ACTION_PHASE} { return yy::seclang_parser::make_ACTION_PHASE(yytext, *driver.loc.back()); } -{ACTION_SKIP_AFTER}:{FREE_TEXT} { return yy::seclang_parser::make_ACTION_SKIP_AFTER(strchr(yytext, ':') + 1, *driver.loc.back()); } +{ACTION_SKIP_AFTER}:{FREE_TEXT_SPACE_COMMA_QUOTE} { return yy::seclang_parser::make_ACTION_SKIP_AFTER(strchr(yytext, ':') + 1, *driver.loc.back()); } {ACTION_AUDIT_LOG} { return yy::seclang_parser::make_ACTION_AUDIT_LOG(yytext, *driver.loc.back()); } {ACTION_SEVERITY}:{ACTION_SEVERITY_VALUE} { return yy::seclang_parser::make_ACTION_SEVERITY(yytext + 9, *driver.loc.back()); } diff --git a/src/rule.cc b/src/rule.cc index 66aa7ba8..919d485b 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -82,12 +82,15 @@ Rule::Rule(std::string marker) m_unconditional(false), m_secmarker(true), m_marker(marker), - m_referenceCount(0) { } + m_referenceCount(0), + m_fileName(""), + m_lineNumber(0) { } Rule::Rule(Operator *_op, std::vector *_variables, - std::vector *actions) - : chained(false), + std::vector *actions, + std::string fileName, + int lineNumber): chained(false), chainedRule(NULL), variables(_variables), op(_op), @@ -96,7 +99,9 @@ Rule::Rule(Operator *_op, m_unconditional(false), m_secmarker(false), m_marker(""), - m_referenceCount(0) { + m_referenceCount(0), + m_fileName(fileName), + m_lineNumber(lineNumber) { if (actions != NULL) { for (Action *a : *actions) { if (a->action_kind == Action::ConfigurationKind) { diff --git a/src/rule.h b/src/rule.h index 25438cd5..d5f7a58d 100644 --- a/src/rule.h +++ b/src/rule.h @@ -33,7 +33,10 @@ class Rule { public: Rule(operators::Operator *_op, std::vector *_variables, - std::vector *_actions); + std::vector *_actions, + std::string fileName, + int lineNumber + ); explicit Rule(std::string marker); ~Rule(); @@ -67,6 +70,8 @@ class Rule { std::string m_marker; bool m_secmarker; + std::string m_fileName; + int m_lineNumber; private: bool m_unconditional; diff --git a/src/utils.cc b/src/utils.cc index cfdb01a0..bbe0818b 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -1040,5 +1040,38 @@ std::vector expandEnv(const std::string& var, int flags) } +std::string get_path(const std::string& file) { + size_t found; + + found = file.find_last_of("/\\"); + if (found > 0) { + return file.substr(0, found); + } + + return std::string(""); +} + + +std::string find_resource(const std::string& resource, const std::string& config) { + std::ifstream *iss = NULL; + + // Trying absolute or relative to the current dir. + iss = new std::ifstream(resource, std::ios::in); + if (iss->is_open()) { + iss->close(); + return resource; + } + + // Trying the same path of the configuration file. + std::string f = get_path(config) + "/" + resource; + iss = new std::ifstream(f, std::ios::in); + if (iss->is_open()) { + iss->close(); + return f; + } + + return std::string(""); +} + } // namespace ModSecurity diff --git a/src/utils.h b/src/utils.h index a7926fe1..979ebe9d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -48,6 +48,8 @@ namespace ModSecurity { std::string limitTo(int amount, const std::string &str); std::string toHexIfNeeded(const std::string &str); std::vector expandEnv(const std::string& var, int flags); + std::string find_resource(const std::string& file, + const std::string& param); } // namespace ModSecurity #define SRC_UTILS_H_ diff --git a/test/benchmark/basic_rules.conf b/test/benchmark/basic_rules.conf index 9a6c1141..2bdd7a07 100644 --- a/test/benchmark/basic_rules.conf +++ b/test/benchmark/basic_rules.conf @@ -1,7 +1,5 @@ include "owasp-modsecurity-crs-orig/modsecurity_crs_10_setup.conf" -#include "owasp-modsecurity-crs-orig/rules/*.conf" -#include owasp-modsecurity-crs-orig/rules/RESPONSE-51-DATA-LEAKAGES-SQL.conf include owasp-modsecurity-crs-orig/rules/REQUEST-01-COMMON-EXCEPTIONS.conf include owasp-modsecurity-crs-orig/rules/REQUEST-10-IP-REPUTATION.conf include owasp-modsecurity-crs-orig/rules/REQUEST-11-METHOD-ENFORCEMENT.conf diff --git a/test/unit/unit.cc b/test/unit/unit.cc index 15ef447d..801af38a 100644 --- a/test/unit/unit.cc +++ b/test/unit/unit.cc @@ -51,7 +51,7 @@ void perform_unit_test(UnitTest *t, ModSecurityTestResults* res) { if (t->type == "op") { Operator *op = Operator::instantiate("\"@" + t->name + \ " " + t->param + "\""); - op->init(&error); + op->init(t->filename, &error); int ret = op->evaluate(NULL, t->input); if (ret != t->ret) { t->obtained = ret;