From 4f47651a6f68ae7aae1427c3f9070262ca0bbb85 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Wed, 5 Aug 2015 10:07:47 -0300 Subject: [PATCH] Adds variable TX and action "capture". --- src/Makefile.am | 2 + src/actions/action.cc | 13 +-- src/actions/action.h | 3 +- src/actions/audit_log.cc | 2 +- src/actions/audit_log.h | 2 +- src/actions/block.cc | 2 +- src/actions/block.h | 2 +- src/actions/capture.cc | 67 ++++++++++++++++ src/actions/capture.h | 41 ++++++++++ src/actions/chain.cc | 2 +- src/actions/chain.h | 2 +- src/actions/no_audit_log.cc | 2 +- src/actions/no_audit_log.h | 2 +- src/actions/phase.cc | 2 +- src/actions/phase.h | 2 +- src/actions/redirect.cc | 2 +- src/actions/redirect.h | 2 +- src/actions/rule_id.cc | 2 +- src/actions/rule_id.h | 2 +- src/actions/severity.cc | 2 +- src/actions/severity.h | 2 +- src/actions/status.cc | 2 +- src/actions/status.h | 2 +- src/operators/pm.cc | 3 +- src/operators/pm.h | 2 + src/operators/rx.cc | 2 + src/operators/rx.h | 3 + src/parser/seclang-scanner.ll | 2 +- src/rule.cc | 4 +- src/utils/regex.cc | 7 ++ src/utils/regex.h | 1 + src/variables/tx.cc | 51 ++++++++++++ src/variables/tx.h | 44 +++++++++++ test/test-cases/regression/variable-TX.json | 87 +++++++++++++++++++++ 34 files changed, 338 insertions(+), 30 deletions(-) create mode 100644 src/actions/capture.cc create mode 100644 src/actions/capture.h create mode 100644 src/variables/tx.cc create mode 100644 src/variables/tx.h create mode 100644 test/test-cases/regression/variable-TX.json diff --git a/src/Makefile.am b/src/Makefile.am index 82e212ca..295f509c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,6 +44,7 @@ VARIABLES = \ variables/time_sec.cc \ variables/time_wday.cc \ variables/time_year.cc \ + variables/tx.cc \ variables/variable.cc @@ -52,6 +53,7 @@ ACTIONS = \ actions/action.cc \ actions/audit_log.cc \ actions/block.cc \ + actions/capture.cc \ actions/chain.cc \ actions/no_audit_log.cc \ actions/phase.cc \ diff --git a/src/actions/action.cc b/src/actions/action.cc index e14977c3..e089c9c4 100644 --- a/src/actions/action.cc +++ b/src/actions/action.cc @@ -19,6 +19,8 @@ #include #include "modsecurity/assay.h" +#include "src/rule.h" + #include "actions/block.h" #include "actions/chain.h" #include "actions/redirect.h" @@ -26,6 +28,7 @@ #include "actions/rule_id.h" #include "actions/phase.h" #include "actions/severity.h" +#include "actions/capture.h" @@ -42,12 +45,7 @@ std::string Action::evaluate(std::string value, } -bool Action::evaluate(Assay *assay) { - return true; -} - - -bool Action::evaluate(Rule *rule) { +bool Action::evaluate(Rule *rule, Assay *assay) { return true; } @@ -84,6 +82,9 @@ Action *Action::instantiate(const std::string& name) { if (name == "chain") { return new Chain(name); } + if (name == "capture") { + return new Capture(name); + } return new Action(name); } diff --git a/src/actions/action.h b/src/actions/action.h index 7167f7db..31759b0b 100644 --- a/src/actions/action.h +++ b/src/actions/action.h @@ -80,8 +80,7 @@ class Action { virtual std::string evaluate(std::string exp, Assay *assay); - virtual bool evaluate(Assay *assay); - virtual bool evaluate(Rule *rule); + virtual bool evaluate(Rule *rule, Assay *assay); static Action *instantiate(const std::string& name); diff --git a/src/actions/audit_log.cc b/src/actions/audit_log.cc index 81ac95f0..d4b26a6d 100644 --- a/src/actions/audit_log.cc +++ b/src/actions/audit_log.cc @@ -23,7 +23,7 @@ namespace ModSecurity { namespace actions { -bool AuditLog::evaluate(Assay *assay) { +bool AuditLog::evaluate(Rule *rule, Assay *assay) { assay->save_in_auditlog = true; return true; } diff --git a/src/actions/audit_log.h b/src/actions/audit_log.h index d4b4b321..ff88a7e0 100644 --- a/src/actions/audit_log.h +++ b/src/actions/audit_log.h @@ -34,7 +34,7 @@ class AuditLog : public Action { explicit AuditLog(std::string action) : Action(action, RunTimeOnlyIfMatchKind) { } - bool evaluate(Assay *assay) override; + bool evaluate(Rule *rule, Assay *assay) override; }; } // namespace actions diff --git a/src/actions/block.cc b/src/actions/block.cc index d9d5c44d..2ff1ae30 100644 --- a/src/actions/block.cc +++ b/src/actions/block.cc @@ -30,7 +30,7 @@ Block::Block(std::string action) } -bool Block::evaluate(Assay *assay) { +bool Block::evaluate(Rule *rule, Assay *assay) { assay->actions.push_back(this); return true; } diff --git a/src/actions/block.h b/src/actions/block.h index 84267ec5..371b7447 100644 --- a/src/actions/block.h +++ b/src/actions/block.h @@ -33,7 +33,7 @@ class Block : public Action { public: explicit Block(std::string action); - bool evaluate(Assay *assay) override; + bool evaluate(Rule *rule, Assay *assay) override; void fill_intervention(ModSecurityIntervention *i) override; }; diff --git a/src/actions/capture.cc b/src/actions/capture.cc new file mode 100644 index 00000000..21f18902 --- /dev/null +++ b/src/actions/capture.cc @@ -0,0 +1,67 @@ +/* + * 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/capture.h" + +#include +#include +#include + +#include "modsecurity/assay.h" + +#include "src/rule.h" +#include "operators/operator.h" +#include "operators/pm.h" +#include "operators/rx.h" + +namespace ModSecurity { +namespace actions { + +bool Capture::evaluate(Rule *rule, Assay *assay) { + operators::Operator *op = rule->op; + std::list match; + + operators::Pm *pm = dynamic_cast(op); + operators::Rx *rx = dynamic_cast(op); + + if (pm != NULL) { + match = pm->matched; + } + + if (rx != NULL) { + match = rx->matched; + } + + if (match.empty()) { + return false; + } + + int i = 0; + while (match.empty() == false) { + std::string varName = "TX:" + std::to_string(i); + std::string *a = assay->resolve_variable_first(varName); + if (a == NULL) { + assay->store_variable(varName, match.back()); + } else { + assay->update_variable_first(varName, match.back()); + } + match.pop_back(); + } + + return true; +} + +} // namespace actions +} // namespace ModSecurity diff --git a/src/actions/capture.h b/src/actions/capture.h new file mode 100644 index 00000000..685eb333 --- /dev/null +++ b/src/actions/capture.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 "actions/action.h" + +#ifndef SRC_ACTIONS_CAPTURE_H_ +#define SRC_ACTIONS_CAPTURE_H_ + + +namespace ModSecurity { +class Rule; +namespace actions { + + +class Capture : public Action { + public: + explicit Capture(std::string action) + : Action(action, RunTimeOnlyIfMatchKind) { } + + bool evaluate(Rule *rule, Assay *assay) override; +}; + + +} // namespace actions +} // namespace ModSecurity + +#endif // SRC_ACTIONS_CAPTURE_H_ diff --git a/src/actions/chain.cc b/src/actions/chain.cc index bbb1d2ce..b44aacd4 100644 --- a/src/actions/chain.cc +++ b/src/actions/chain.cc @@ -26,7 +26,7 @@ namespace actions { -bool Chain::evaluate(Rule *rule) { +bool Chain::evaluate(Rule *rule, Assay *assay) { rule->chained = true; return true; } diff --git a/src/actions/chain.h b/src/actions/chain.h index 6b104dc9..4a590c44 100644 --- a/src/actions/chain.h +++ b/src/actions/chain.h @@ -35,7 +35,7 @@ class Chain : public Action { explicit Chain(std::string action) : Action(action, ConfigurationKind) { } - bool evaluate(Rule *rule) override; + bool evaluate(Rule *rule, Assay *assay) override; }; } // namespace actions diff --git a/src/actions/no_audit_log.cc b/src/actions/no_audit_log.cc index 030e17b1..a9483a54 100644 --- a/src/actions/no_audit_log.cc +++ b/src/actions/no_audit_log.cc @@ -23,7 +23,7 @@ namespace ModSecurity { namespace actions { -bool NoAuditLog::evaluate(Assay *assay) { +bool NoAuditLog::evaluate(Rule *rule, Assay *assay) { assay->do_not_save_in_auditlog = true; return true; } diff --git a/src/actions/no_audit_log.h b/src/actions/no_audit_log.h index e5f9e751..a49b1e7a 100644 --- a/src/actions/no_audit_log.h +++ b/src/actions/no_audit_log.h @@ -34,7 +34,7 @@ class NoAuditLog : public Action { explicit NoAuditLog(std::string action) : Action(action, RunTimeOnlyIfMatchKind) { } - bool evaluate(Assay *assay) override; + bool evaluate(Rule *rule, Assay *assay) override; }; } // namespace actions diff --git a/src/actions/phase.cc b/src/actions/phase.cc index d3d635c2..7c3f4858 100644 --- a/src/actions/phase.cc +++ b/src/actions/phase.cc @@ -41,7 +41,7 @@ Phase::Phase(std::string action) } } -bool Phase::evaluate(Rule *rule) { +bool Phase::evaluate(Rule *rule, Assay *assay) { rule->phase = this->phase; return true; } diff --git a/src/actions/phase.h b/src/actions/phase.h index 4de7f5e9..e9ad640c 100644 --- a/src/actions/phase.h +++ b/src/actions/phase.h @@ -34,7 +34,7 @@ class Phase : public Action { public: explicit Phase(std::string action); - bool evaluate(Rule *rule) override; + bool evaluate(Rule *rule, Assay *assay) override; int phase; }; diff --git a/src/actions/redirect.cc b/src/actions/redirect.cc index 7d5885c4..4f1a7675 100644 --- a/src/actions/redirect.cc +++ b/src/actions/redirect.cc @@ -34,7 +34,7 @@ Redirect::Redirect(const std::string& action) } -bool Redirect::evaluate(Assay *assay) { +bool Redirect::evaluate(Rule *rule, Assay *assay) { assay->actions.push_back(this); return true; } diff --git a/src/actions/redirect.h b/src/actions/redirect.h index 06f88814..39fbe8f8 100644 --- a/src/actions/redirect.h +++ b/src/actions/redirect.h @@ -33,7 +33,7 @@ class Redirect : public Action { explicit Redirect(const std::string &action); ~Redirect() override; - bool evaluate(Assay *assay) override; + bool evaluate(Rule *rule, Assay *assay) override; int status; std::string url; void fill_intervention(ModSecurityIntervention *i) override; diff --git a/src/actions/rule_id.cc b/src/actions/rule_id.cc index 52fe30e8..8ebe4707 100644 --- a/src/actions/rule_id.cc +++ b/src/actions/rule_id.cc @@ -37,7 +37,7 @@ RuleId::RuleId(std::string action) } -bool RuleId::evaluate(Rule *rule) { +bool RuleId::evaluate(Rule *rule, Assay *assay) { rule->rule_id = this->rule_id; return true; } diff --git a/src/actions/rule_id.h b/src/actions/rule_id.h index cab27151..d24f1a88 100644 --- a/src/actions/rule_id.h +++ b/src/actions/rule_id.h @@ -34,7 +34,7 @@ class RuleId : public Action { public: explicit RuleId(std::string action); - bool evaluate(Rule *rule) override; + bool evaluate(Rule *rule, Assay *assay) override; double rule_id; }; diff --git a/src/actions/severity.cc b/src/actions/severity.cc index 3dfde48b..3895bdec 100644 --- a/src/actions/severity.cc +++ b/src/actions/severity.cc @@ -51,7 +51,7 @@ Severity::Severity(std::string action) } -bool Severity::evaluate(Assay *assay) { +bool Severity::evaluate(Rule *rule, Assay *assay) { assay->debug(9, "This rule severity is: " + \ std::to_string(this->m_severity) + " current assay is: " + \ std::to_string(assay->highest_severity)); diff --git a/src/actions/severity.h b/src/actions/severity.h index 04e14274..0537b7bc 100644 --- a/src/actions/severity.h +++ b/src/actions/severity.h @@ -33,7 +33,7 @@ class Severity : public Action { public: explicit Severity(std::string action); - bool evaluate(Assay *assay) override; + bool evaluate(Rule *rule, Assay *assay) override; private: int m_severity; diff --git a/src/actions/status.cc b/src/actions/status.cc index 7934805a..92d42bbe 100644 --- a/src/actions/status.cc +++ b/src/actions/status.cc @@ -33,7 +33,7 @@ Status::Status(std::string action) } -bool Status::evaluate(Assay *assay) { +bool Status::evaluate(Rule *rule, Assay *assay) { assay->actions.push_back(this); return true; } diff --git a/src/actions/status.h b/src/actions/status.h index ba277bb6..aab8d0b2 100644 --- a/src/actions/status.h +++ b/src/actions/status.h @@ -31,7 +31,7 @@ class Status : public Action { public: explicit Status(std::string actions); - bool evaluate(Assay *assay) override; + bool evaluate(Rule *rule, Assay *assay) override; void fill_intervention(ModSecurityIntervention *i) override; int status; }; diff --git a/src/operators/pm.cc b/src/operators/pm.cc index 8a72509d..fb3da401 100644 --- a/src/operators/pm.cc +++ b/src/operators/pm.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include "operators/operator.h" #include "utils/acmp.h" @@ -68,7 +69,7 @@ bool Pm::evaluate(Assay *assay, const std::string &input) { rc = acmp_process_quick(&pt, &match, input.c_str(), input.length()); if (rc == 1) { - // save into tx, etc... + this->matched.push_back(std::string(match)); } return rc == 1; diff --git a/src/operators/pm.h b/src/operators/pm.h index ff3b5a29..f09bb7f9 100644 --- a/src/operators/pm.h +++ b/src/operators/pm.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_PM_H_ #include +#include #include "operators/operator.h" #include "utils/acmp.h" @@ -40,6 +41,7 @@ class Pm : public Operator { virtual bool init(const char **error); void postOrderTraversal(acmp_btree_node_t *node); + std::list matched; protected: ACMP *m_p; }; diff --git a/src/operators/rx.cc b/src/operators/rx.cc index ae7375d3..a968d6c5 100644 --- a/src/operators/rx.cc +++ b/src/operators/rx.cc @@ -16,6 +16,7 @@ #include "operators/rx.h" #include +#include #include "operators/operator.h" @@ -27,6 +28,7 @@ bool Rx::evaluate(Assay *assay, const std::string& input) { SMatch match; if (regex_search(input, &match, m_re) && match.size() >= 1) { + this->matched.push_back(match.match); return true; } diff --git a/src/operators/rx.h b/src/operators/rx.h index f10bf057..af04b10e 100644 --- a/src/operators/rx.h +++ b/src/operators/rx.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_RX_H_ #include +#include #include "operators/operator.h" #include "utils/regex.h" @@ -38,6 +39,8 @@ class Rx : public Operator { m_re(param) { } bool evaluate(Assay *assay, const std::string &input); + + std::list matched; private: Regex m_re; }; diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index 55ebec81..7751e356 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -62,7 +62,7 @@ CONFIG_SEC_REMOTE_RULES (?i:SecRemoteRules) CONFIG_SEC_REMOTE_RULES_FAIL_ACTION (?i:SecRemoteRulesFailAction) -DICT_ELEMENT [A-Za-z_]+ +DICT_ELEMENT [A-Za-z_0-9]+ 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)) diff --git a/src/rule.cc b/src/rule.cc index 4dbc8797..3d3727ed 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -74,7 +74,7 @@ Rule::Rule(Operator *_op, for (Action *a : *actions) { if (a->action_kind == Action::ConfigurationKind) { actions_conf.push_back(a); - a->evaluate(this); + a->evaluate(this, NULL); } else if (a->action_kind == Action::RunTimeBeforeMatchAttemptKind) { actions_runtime_pre.push_back(a); } else if (a->action_kind == Action::RunTimeOnlyIfMatchKind) { @@ -142,7 +142,7 @@ bool Rule::evaluate(Assay *assay) { for (Action *a : this->actions_runtime_pos) { assay->debug(4, "Running action: " + a->action); - a->evaluate(assay); + a->evaluate(this, assay); } if (this->chained && this->chainedRule == NULL) { assay->debug(4, "Rule is marked as chained but there " \ diff --git a/src/utils/regex.cc b/src/utils/regex.cc index a2624b9e..a48d6a2d 100644 --- a/src/utils/regex.cc +++ b/src/utils/regex.cc @@ -40,13 +40,20 @@ Regex::Regex(const std::string& pattern_) int regex_search(const std::string& s, SMatch *match, const Regex& regex) { + std::string m; pcrecpp::RE re(regex.pattern, pcrecpp::RE_Options(PCRE_DOTALL|PCRE_MULTILINE)); + + /** FIXME: Should be not necessary to call PartialMatch twice here. */ match->size_ = re.PartialMatch(s); + re.PartialMatch(s, &m); + match->match = m; + return match->size_; } int regex_search(const std::string& s, Regex regex) { + std::string match; pcrecpp::RE re(regex.pattern); return re.PartialMatch(s); } diff --git a/src/utils/regex.h b/src/utils/regex.h index be97c5db..0515116b 100644 --- a/src/utils/regex.h +++ b/src/utils/regex.h @@ -37,6 +37,7 @@ class SMatch { SMatch() : size_(0) { } size_t size() { return size_; } int size_; + std::string match; }; diff --git a/src/variables/tx.cc b/src/variables/tx.cc new file mode 100644 index 00000000..621d68c0 --- /dev/null +++ b/src/variables/tx.cc @@ -0,0 +1,51 @@ +/* + * 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/tx.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "modsecurity/assay.h" + +namespace ModSecurity { +namespace Variables { + +std::list> + Tx::evaluate(Assay *assay) { + std::list> resl; + std::pair pair; + + pair = std::make_pair(std::string("TX:0"), + std::string("teste")); + + resl.push_back(pair); + + return resl; +} + + +} // namespace Variables +} // namespace ModSecurity diff --git a/src/variables/tx.h b/src/variables/tx.h new file mode 100644 index 00000000..86753ef8 --- /dev/null +++ b/src/variables/tx.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 +#include +#include +#include + +#ifndef SRC_VARIABLES_TX_H_ +#define SRC_VARIABLES_TX_H_ + +#include "variables/variable.h" + +namespace ModSecurity { + +class Assay; +namespace Variables { + +class Tx : public Variable { + public: + explicit Tx(std::string _name) + : Variable(_name) { } + + std::list> + evaluate(Assay *assay) override; +}; + +} // namespace Variables +} // namespace ModSecurity + +#endif // SRC_VARIABLES_TX_H_ diff --git a/test/test-cases/regression/variable-TX.json b/test/test-cases/regression/variable-TX.json new file mode 100644 index 00000000..9fd1d82f --- /dev/null +++ b/test/test-cases/regression/variable-TX.json @@ -0,0 +1,87 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: TX:0 (1/2)", + "client":{ + "ip":"200.249.12.31", + "port":123 + }, + "server":{ + "ip":"200.249.12.11", + "port":80 + }, + "request":{ + "headers":{ + "Host":"localhost", + "User-Agent":"curl/7.38.0", + "Accept":"*/*", + "Content-Length":"27", + "Content-Type":"application/x-www-form-urlencoded" + }, + "uri":"/one/two/three?key1=value1&key2=v%20a%20l%20u%20e%202", + "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":[ + "whee test 123" + ] + }, + "expected":{ + "debug_log":"(.*) Target value: \"123\" \\(Variable\\: TX\\:0(.*)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRequestBodyAccess On", + "SecRule RESPONSE_BODY \"@rx ([0-9]+)\" \"phase:4,capture,id:105\"", + "SecRule TX \"@rx ([A-z]+)\" \"phase:4,id:106\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: TX:0 (2/2)", + "client":{ + "ip":"200.249.12.31", + "port":123 + }, + "server":{ + "ip":"200.249.12.31", + "port":80 + }, + "request":{ + "headers":{ + "Cookie":"USER_TOKEN=Yes; a=z; t=b" + }, + "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: \"USER_TOKEN\" \\(Variable: TX:0(.*)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REQUEST_HEADERS \"@rx ([A-z]+)\" \"log,pass,capture,id:14\"", + "SecRule TX:0 \"@rx ([A-z]+)\" \"id:15\"" + ] + } +] \ No newline at end of file