mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
Adds support to unconditional rules
This commit is contained in:
@@ -39,6 +39,17 @@ Driver::~Driver() {
|
|||||||
delete loc.back();
|
delete loc.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Driver::addSecAction(Rule *rule) {
|
||||||
|
if (rule->phase >= ModSecurity::Phases::NUMBER_OF_PHASES) {
|
||||||
|
parserError << "Unknown phase: " << std::to_string(rule->phase);
|
||||||
|
parserError << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rules[rule->phase].push_back(rule);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int Driver::addSecRule(Rule *rule) {
|
int Driver::addSecRule(Rule *rule) {
|
||||||
if (rule->phase >= ModSecurity::Phases::NUMBER_OF_PHASES) {
|
if (rule->phase >= ModSecurity::Phases::NUMBER_OF_PHASES) {
|
||||||
|
@@ -57,6 +57,7 @@ class Driver : public RulesProperties {
|
|||||||
virtual ~Driver();
|
virtual ~Driver();
|
||||||
|
|
||||||
int addSecRule(Rule *rule);
|
int addSecRule(Rule *rule);
|
||||||
|
int addSecAction(Rule *rule);
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@@ -190,6 +190,7 @@ using ModSecurity::Variables::Variable;
|
|||||||
%token <std::string> CONFIG_DIR_DEBUG_LOG
|
%token <std::string> CONFIG_DIR_DEBUG_LOG
|
||||||
%token <std::string> CONFIG_DIR_DEBUG_LVL
|
%token <std::string> CONFIG_DIR_DEBUG_LVL
|
||||||
|
|
||||||
|
%token <std::string> CONFIG_DIR_SEC_ACTION
|
||||||
%token <std::string> CONFIG_DIR_SEC_DEFAULT_ACTION
|
%token <std::string> CONFIG_DIR_SEC_DEFAULT_ACTION
|
||||||
|
|
||||||
%token <std::string> VARIABLE
|
%token <std::string> VARIABLE
|
||||||
@@ -356,6 +357,24 @@ expression:
|
|||||||
);
|
);
|
||||||
driver.addSecRule(rule);
|
driver.addSecRule(rule);
|
||||||
}
|
}
|
||||||
|
| CONFIG_DIR_SEC_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK
|
||||||
|
{
|
||||||
|
Rule *rule = new Rule(
|
||||||
|
/* op */ NULL,
|
||||||
|
/* variables */ NULL,
|
||||||
|
/* actions */ $4
|
||||||
|
);
|
||||||
|
driver.addSecAction(rule);
|
||||||
|
}
|
||||||
|
| CONFIG_DIR_SEC_ACTION SPACE actions
|
||||||
|
{
|
||||||
|
Rule *rule = new Rule(
|
||||||
|
/* op */ NULL,
|
||||||
|
/* variables */ NULL,
|
||||||
|
/* actions */ $3
|
||||||
|
);
|
||||||
|
driver.addSecAction(rule);
|
||||||
|
}
|
||||||
| CONFIG_DIR_SEC_DEFAULT_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK
|
| CONFIG_DIR_SEC_DEFAULT_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK
|
||||||
{
|
{
|
||||||
std::vector<Action *> *actions = $4;
|
std::vector<Action *> *actions = $4;
|
||||||
|
@@ -39,6 +39,7 @@ DIRECTIVE (?i:SecRule)
|
|||||||
LOG_DATA (?i:logdata)
|
LOG_DATA (?i:logdata)
|
||||||
|
|
||||||
CONFIG_DIR_SEC_DEFAULT_ACTION (?i:SecDefaultAction)
|
CONFIG_DIR_SEC_DEFAULT_ACTION (?i:SecDefaultAction)
|
||||||
|
CONFIG_DIR_SEC_ACTION (?i:SecAction)
|
||||||
|
|
||||||
CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION (?i:SecPcreMatchLimitRecursion)
|
CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION (?i:SecPcreMatchLimitRecursion)
|
||||||
CONFIG_DIR_PCRE_MATCH_LIMIT (?i:SecPcreMatchLimit)
|
CONFIG_DIR_PCRE_MATCH_LIMIT (?i:SecPcreMatchLimit)
|
||||||
@@ -243,6 +244,7 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
|||||||
{CONFIG_VALUE_PROCESS_PARTIAL} { return yy::seclang_parser::make_CONFIG_VALUE_PROCESS_PARTIAL(yytext, *driver.loc.back()); }
|
{CONFIG_VALUE_PROCESS_PARTIAL} { return yy::seclang_parser::make_CONFIG_VALUE_PROCESS_PARTIAL(yytext, *driver.loc.back()); }
|
||||||
{CONFIG_VALUE_REJECT} { return yy::seclang_parser::make_CONFIG_VALUE_REJECT(yytext, *driver.loc.back()); }
|
{CONFIG_VALUE_REJECT} { return yy::seclang_parser::make_CONFIG_VALUE_REJECT(yytext, *driver.loc.back()); }
|
||||||
|
|
||||||
|
{CONFIG_DIR_SEC_ACTION} { return yy::seclang_parser::make_CONFIG_DIR_SEC_ACTION(yytext, *driver.loc.back()); }
|
||||||
{CONFIG_DIR_SEC_DEFAULT_ACTION} { return yy::seclang_parser::make_CONFIG_DIR_SEC_DEFAULT_ACTION(yytext, *driver.loc.back()); }
|
{CONFIG_DIR_SEC_DEFAULT_ACTION} { return yy::seclang_parser::make_CONFIG_DIR_SEC_DEFAULT_ACTION(yytext, *driver.loc.back()); }
|
||||||
|
|
||||||
<EXPECTING_OPERATOR>{
|
<EXPECTING_OPERATOR>{
|
||||||
|
71
src/rule.cc
71
src/rule.cc
@@ -56,7 +56,7 @@ Rule::~Rule() {
|
|||||||
actions_runtime_pos.pop_back();
|
actions_runtime_pos.pop_back();
|
||||||
delete a;
|
delete a;
|
||||||
}
|
}
|
||||||
while (variables->empty() == false) {
|
while (variables != NULL && variables->empty() == false) {
|
||||||
auto *a = variables->back();
|
auto *a = variables->back();
|
||||||
variables->pop_back();
|
variables->pop_back();
|
||||||
delete a;
|
delete a;
|
||||||
@@ -75,6 +75,7 @@ Rule::Rule(Operator *_op,
|
|||||||
op(_op),
|
op(_op),
|
||||||
rule_id(0),
|
rule_id(0),
|
||||||
phase(-1),
|
phase(-1),
|
||||||
|
m_unconditional(false),
|
||||||
m_referenceCount(0) {
|
m_referenceCount(0) {
|
||||||
for (Action *a : *actions) {
|
for (Action *a : *actions) {
|
||||||
if (a->action_kind == Action::ConfigurationKind) {
|
if (a->action_kind == Action::ConfigurationKind) {
|
||||||
@@ -98,13 +99,81 @@ Rule::Rule(Operator *_op,
|
|||||||
phase = ModSecurity::Phases::RequestHeadersPhase;
|
phase = ModSecurity::Phases::RequestHeadersPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (op == NULL) {
|
||||||
|
m_unconditional = true;
|
||||||
|
}
|
||||||
|
|
||||||
delete actions;
|
delete actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Rule::evaluateActions(Assay *assay) {
|
||||||
|
int none = 0;
|
||||||
|
int transformations = 0;
|
||||||
|
for (Action *a : this->actions_runtime_pre) {
|
||||||
|
None *z = dynamic_cast<None *>(a);
|
||||||
|
if (z != NULL) {
|
||||||
|
none++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assay->debug(4, "Running unconditional rule.");
|
||||||
|
|
||||||
|
if (none == 0) {
|
||||||
|
/*
|
||||||
|
for (Action *a : assay->m_rules->defaultActions[this->phase]) {
|
||||||
|
if (a->action_kind == actions::Action::RunTimeBeforeMatchAttemptKind) {
|
||||||
|
value = a->evaluate(value, assay);
|
||||||
|
assay->debug(9, "(SecDefaultAction) T (" + \
|
||||||
|
std::to_string(transformations) + ") " + \
|
||||||
|
a->name + ": \"" + value +"\"");
|
||||||
|
transformations++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Action *a : this->actions_runtime_pre) {
|
||||||
|
None *z = dynamic_cast<None *>(a);
|
||||||
|
/*
|
||||||
|
if (none == 0) {
|
||||||
|
value = a->evaluate(value, assay);
|
||||||
|
assay->debug(9, " T (" + \
|
||||||
|
std::to_string(transformations) + ") " + \
|
||||||
|
a->name + ": \"" + value +"\"");
|
||||||
|
transformations++;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (z != NULL) {
|
||||||
|
none--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Action *a : assay->m_rules->defaultActions[this->phase]) {
|
||||||
|
if (a->action_kind == actions::Action::RunTimeOnlyIfMatchKind) {
|
||||||
|
assay->debug(4, "(SecDefaultAction) Running action: " + a->action);
|
||||||
|
a->evaluate(this, assay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Action *a :
|
||||||
|
this->actions_runtime_pos) {
|
||||||
|
assay->debug(4, "Running action: " + a->action);
|
||||||
|
a->evaluate(this, assay);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Rule::evaluate(Assay *assay) {
|
bool Rule::evaluate(Assay *assay) {
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
std::vector<Variable *> *variables = this->variables;
|
std::vector<Variable *> *variables = this->variables;
|
||||||
|
|
||||||
|
if (m_unconditional == true) {
|
||||||
|
return evaluateActions(assay);
|
||||||
|
}
|
||||||
|
|
||||||
assay->debug(4, "Executing operator \"" + this->op->op \
|
assay->debug(4, "Executing operator \"" + this->op->op \
|
||||||
+ "\" with param \"" + this->op->param + "\" against " \
|
+ "\" with param \"" + this->op->param + "\" against " \
|
||||||
+ Variable::to_s(variables) + ".");
|
+ Variable::to_s(variables) + ".");
|
||||||
|
@@ -37,6 +37,7 @@ class Rule {
|
|||||||
|
|
||||||
~Rule();
|
~Rule();
|
||||||
bool evaluate(Assay *assay);
|
bool evaluate(Assay *assay);
|
||||||
|
bool evaluateActions(Assay *assay);
|
||||||
|
|
||||||
operators::Operator *op;
|
operators::Operator *op;
|
||||||
std::vector<actions::Action *> actions_conf;
|
std::vector<actions::Action *> actions_conf;
|
||||||
@@ -64,6 +65,7 @@ class Rule {
|
|||||||
std::string rev;
|
std::string rev;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_unconditional;
|
||||||
int m_referenceCount;
|
int m_referenceCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
63
test/test-cases/regression/secaction.json
Normal file
63
test/test-cases/regression/secaction.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"enabled": 1,
|
||||||
|
"version_min": 300000,
|
||||||
|
"version_max": 0,
|
||||||
|
"title": "sec action",
|
||||||
|
"client": {
|
||||||
|
"ip": "200.249.12.31",
|
||||||
|
"port": 2313
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"ip": "200.249.12.31",
|
||||||
|
"port": 80
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"headers": {
|
||||||
|
"Host": "net.tutsplus.com",
|
||||||
|
"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=r2t5uvjq435r4q7ib3vtdjq120",
|
||||||
|
"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": [
|
||||||
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
|
||||||
|
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
|
||||||
|
" <soap:Body>\n\r",
|
||||||
|
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
|
||||||
|
" <EnlightenResult>string<\/EnlightenResult>\n\r",
|
||||||
|
" <\/EnlightenResponse>\n\r",
|
||||||
|
" <\/soap:Body>\n\r",
|
||||||
|
"<\/soap:Envelope>\n\r"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected": {
|
||||||
|
"audit_log": "",
|
||||||
|
"debug_log": "Running unconditional rule.",
|
||||||
|
"error_log": ""
|
||||||
|
},
|
||||||
|
"rules": [
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule ARGS \"@contains test\" \"phase:2,id:1,t:trim\"",
|
||||||
|
"SecAction \"phase:2,nolog,pass\""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Reference in New Issue
Block a user