Adds support to SecDefaultAction configuration directive

This commit is contained in:
Felipe Zimmerle 2015-09-04 10:55:20 -03:00
parent f2ed890ea6
commit 010c18f63f
11 changed files with 428 additions and 2 deletions

View File

@ -33,6 +33,9 @@
namespace ModSecurity { namespace ModSecurity {
class Rule; class Rule;
class AuditLog; class AuditLog;
namespace actions {
class Action;
}
namespace Parser { namespace Parser {
class Driver; class Driver;
} }
@ -72,7 +75,7 @@ class RulesProperties {
} }
std::vector<Rule *> rules[7]; // ModSecurity::Phases::NUMBER_OF_PHASES std::vector<Rule *> rules[7]; // ModSecurity::Phases::NUMBER_OF_PHASES
std::vector<actions::Action *> defaultActions[7]; // ModSecurity::Phases::NUMBER_OF_PHASES
/** /**
* *

View File

@ -88,6 +88,7 @@ class Action {
Assay *assay); Assay *assay);
virtual bool evaluate(Rule *rule, Assay *assay); virtual bool evaluate(Rule *rule, Assay *assay);
virtual bool init(std::string *error) { return true; } virtual bool init(std::string *error) { return true; }
virtual bool isDisruptive() { return false; }
static Action *instantiate(const std::string& name); static Action *instantiate(const std::string& name);

View File

@ -27,7 +27,9 @@ namespace ModSecurity {
namespace actions { namespace actions {
Phase::Phase(std::string action) Phase::Phase(std::string action)
: Action(action) { : Action(action),
m_secRulesPhase(0),
phase(0) {
this->action_kind = ConfigurationKind; this->action_kind = ConfigurationKind;
std::string a = action; std::string a = action;
a.erase(0, 6); a.erase(0, 6);
@ -42,20 +44,25 @@ Phase::Phase(std::string action)
this->phase = 0; this->phase = 0;
if (tolower(a) == "request") { if (tolower(a) == "request") {
this->phase = this->phase + ModSecurity::Phases::RequestHeadersPhase; this->phase = this->phase + ModSecurity::Phases::RequestHeadersPhase;
m_secRulesPhase = 2;
} }
if (tolower(a) == "response") { if (tolower(a) == "response") {
this->phase = this->phase + ModSecurity::Phases::ResponseBodyPhase; this->phase = this->phase + ModSecurity::Phases::ResponseBodyPhase;
m_secRulesPhase = 4;
} }
if (tolower(a) == "logging") { if (tolower(a) == "logging") {
this->phase = this->phase + ModSecurity::Phases::LoggingPhase; this->phase = this->phase + ModSecurity::Phases::LoggingPhase;
m_secRulesPhase = 5;
} }
} }
if (this->phase == 0) { if (this->phase == 0) {
/* Phase 0 is something new, we want to use as ConnectionPhase */ /* Phase 0 is something new, we want to use as ConnectionPhase */
this->phase = ModSecurity::Phases::ConnectionPhase; this->phase = ModSecurity::Phases::ConnectionPhase;
m_secRulesPhase = 2;
} else { } else {
/* Otherwise we want to shift the rule to the correct phase */ /* Otherwise we want to shift the rule to the correct phase */
m_secRulesPhase = phase;
this->phase = phase + ModSecurity::Phases::RequestHeadersPhase - 1; this->phase = phase + ModSecurity::Phases::RequestHeadersPhase - 1;
} }
} }

View File

@ -36,6 +36,7 @@ class Phase : public Action {
bool evaluate(Rule *rule, Assay *assay) override; bool evaluate(Rule *rule, Assay *assay) override;
int phase; int phase;
int m_secRulesPhase;
}; };
} // namespace actions } // namespace actions

View File

@ -16,20 +16,25 @@ class Driver;
} }
} }
#include "modsecurity/modsecurity.h"
#include "actions/action.h" #include "actions/action.h"
#include "actions/audit_log.h" #include "actions/audit_log.h"
#include "actions/ctl_audit_log_parts.h" #include "actions/ctl_audit_log_parts.h"
#include "actions/set_var.h" #include "actions/set_var.h"
#include "actions/severity.h" #include "actions/severity.h"
#include "actions/msg.h" #include "actions/msg.h"
#include "actions/phase.h"
#include "actions/log_data.h" #include "actions/log_data.h"
#include "actions/rev.h" #include "actions/rev.h"
#include "actions/tag.h" #include "actions/tag.h"
#include "actions/transformations/transformation.h" #include "actions/transformations/transformation.h"
#include "actions/transformations/none.h"
#include "operators/operator.h" #include "operators/operator.h"
#include "rule.h" #include "rule.h"
#include "utils/geo_lookup.h" #include "utils/geo_lookup.h"
#include "audit_log.h" #include "audit_log.h"
#include "utils.h"
#include "variables/variations/count.h" #include "variables/variations/count.h"
#include "variables/variations/exclusion.h" #include "variables/variations/exclusion.h"
@ -47,6 +52,8 @@ class Driver;
#include "variables/time_wday.h" #include "variables/time_wday.h"
#include "variables/time_year.h" #include "variables/time_year.h"
using ModSecurity::ModSecurity;
using ModSecurity::actions::Action; using ModSecurity::actions::Action;
using ModSecurity::actions::CtlAuditLogParts; using ModSecurity::actions::CtlAuditLogParts;
using ModSecurity::actions::SetVar; using ModSecurity::actions::SetVar;
@ -54,6 +61,8 @@ using ModSecurity::actions::Severity;
using ModSecurity::actions::Tag; using ModSecurity::actions::Tag;
using ModSecurity::actions::Rev; using ModSecurity::actions::Rev;
using ModSecurity::actions::Msg; using ModSecurity::actions::Msg;
using ModSecurity::actions::Phase;
using ModSecurity::actions::transformations::None;
using ModSecurity::actions::LogData; using ModSecurity::actions::LogData;
using ModSecurity::actions::transformations::Transformation; using ModSecurity::actions::transformations::Transformation;
using ModSecurity::operators::Operator; using ModSecurity::operators::Operator;
@ -181,6 +190,8 @@ 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_DEFAULT_ACTION
%token <std::string> VARIABLE %token <std::string> VARIABLE
%token <std::string> RUN_TIME_VAR_DUR %token <std::string> RUN_TIME_VAR_DUR
%token <std::string> RUN_TIME_VAR_ENV %token <std::string> RUN_TIME_VAR_ENV
@ -345,6 +356,43 @@ expression:
); );
driver.addSecRule(rule); driver.addSecRule(rule);
} }
| CONFIG_DIR_SEC_DEFAULT_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK
{
std::vector<Action *> *actions = $4;
std::vector<Action *> checkedActions;
int definedPhase = -1;
int secRuleDefinedPhase = -1;
for (Action *a : *actions) {
Phase *phase = dynamic_cast<Phase *>(a);
if (phase != NULL) {
definedPhase = phase->phase;
secRuleDefinedPhase = phase->m_secRulesPhase;
} else if (a->action_kind == Action::RunTimeOnlyIfMatchKind ||
a->action_kind == Action::RunTimeBeforeMatchAttemptKind) {
None *none = dynamic_cast<None *>(a);
if (none != NULL) {
driver.parserError << "The transformation none is not suitable to be part of the SecDefaultActions";
YYERROR;
}
checkedActions.push_back(a);
} else {
driver.parserError << "The action '" << a->action << "' is not suitable to be part of the SecDefaultActions";
YYERROR;
}
}
if (definedPhase == -1) {
definedPhase = ModSecurity::ModSecurity::Phases::RequestHeadersPhase;
}
if (!driver.defaultActions[definedPhase].empty()) {
driver.parserError << "SecDefaultActions can only be placed once per phase and configuration context. Phase " << secRuleDefinedPhase << " was informed already.";
YYERROR;
}
for (Action *a : checkedActions) {
driver.defaultActions[definedPhase].push_back(a);
}
}
| CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_OFF | CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_OFF
{ {
driver.secRuleEngine = ModSecurity::Rules::DisabledRuleEngine; driver.secRuleEngine = ModSecurity::Rules::DisabledRuleEngine;

View File

@ -38,6 +38,8 @@ ACTION_CTL_AUDIT_LOG_PARTS (?i:ctl:auditLogParts)
DIRECTIVE (?i:SecRule) DIRECTIVE (?i:SecRule)
LOG_DATA (?i:logdata) LOG_DATA (?i:logdata)
CONFIG_DIR_SEC_DEFAULT_ACTION (?i:SecDefaultAction)
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)
CONGIG_DIR_RESPONSE_BODY_MP (?i:SecResponseBodyMimeType) CONGIG_DIR_RESPONSE_BODY_MP (?i:SecResponseBodyMimeType)
@ -241,6 +243,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_DEFAULT_ACTION} { return yy::seclang_parser::make_CONFIG_DIR_SEC_DEFAULT_ACTION(yytext, *driver.loc.back()); }
<EXPECTING_OPERATOR>{ <EXPECTING_OPERATOR>{
["][^@]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); } ["][^@]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); }

View File

@ -152,6 +152,22 @@ bool Rule::evaluate(Assay *assay) {
none++; none++;
} }
} }
// Check for transformations on the SecDefaultAction
// Notice that first we make sure that won't be a t:none
// on the target 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) { for (Action *a : this->actions_runtime_pre) {
None *z = dynamic_cast<None *>(a); None *z = dynamic_cast<None *>(a);
if (none == 0) { if (none == 0) {
@ -206,6 +222,12 @@ bool Rule::evaluate(Assay *assay) {
assay->delete_variable("MATCHED_VARS_NAMES:" + v.first); assay->delete_variable("MATCHED_VARS_NAMES:" + v.first);
} }
if (this->chained && chainResult == true || !this->chained) { if (this->chained && chainResult == true || !this->chained) {
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 : for (Action *a :
this->actions_runtime_pos) { this->actions_runtime_pos) {
assay->debug(4, "Running action: " + a->action); assay->debug(4, "Running action: " + a->action);

View File

@ -208,6 +208,20 @@ int Rules::merge(Driver *from) {
this->requestBodyLimitAction = from->requestBodyLimitAction; this->requestBodyLimitAction = from->requestBodyLimitAction;
this->responseBodyLimitAction = from->responseBodyLimitAction; this->responseBodyLimitAction = from->responseBodyLimitAction;
/*
*
* default Actions is something per configuration context, there is
* need to merge anything.
*
*/
for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) {
std::vector<Action *> actions = from->defaultActions[i];
this->defaultActions[i].clear();
for (int j = 0; j < actions.size(); j++) {
Action *action = actions[j];
this->defaultActions[i].push_back(action);
}
}
if (from->audit_log != NULL && this->audit_log != NULL) { if (from->audit_log != NULL && this->audit_log != NULL) {
this->audit_log->refCountDecreaseAndCheck(); this->audit_log->refCountDecreaseAndCheck();

View File

@ -49,6 +49,33 @@
namespace ModSecurity { namespace ModSecurity {
std::string phase_name(int x) {
switch(x) {
case ModSecurity::Phases::ConnectionPhase:
return "Connection Phase";
break;
case ModSecurity::Phases::UriPhase:
return "URI Phase";
break;
case ModSecurity::Phases::RequestHeadersPhase:
return "Request Headers";
break;
case ModSecurity::Phases::RequestBodyPhase:
return "Request Headers";
break;
case ModSecurity::Phases::ResponseHeadersPhase:
return "Response Headers";
break;
case ModSecurity::Phases::ResponseBodyPhase:
return "Reponse Body";
break;
case ModSecurity::Phases::LoggingPhase:
return "Logging";
break;
}
return "Phase '" + std::to_string(x) + "' is not known.";
}
std::vector<std::string> split(std::string str, char delimiter) { std::vector<std::string> split(std::string str, char delimiter) {
std::vector<std::string> internal; std::vector<std::string> internal;

View File

@ -44,6 +44,7 @@ namespace ModSecurity {
std::string string_to_hex(const std::string& input); std::string string_to_hex(const std::string& input);
int urldecode_uni_nonstrict_inplace_ex(Assay *assay, unsigned char *input, int urldecode_uni_nonstrict_inplace_ex(Assay *assay, unsigned char *input,
int64_t input_len, int *changed); int64_t input_len, int *changed);
std::string phase_name(int x);
} // namespace ModSecurity } // namespace ModSecurity
#define SRC_UTILS_H_ #define SRC_UTILS_H_

View File

@ -0,0 +1,299 @@
[
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: supporting transformation",
"client":{
"ip":"200.249.12.31",
"port":2313
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"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=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
"Pragma":"no-cache",
"Cache-Control":"no-cache"
},
"uri":"\/test.pl?param1= test &param2=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":"lowercase: \"300\"",
"error_log":""
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,t:lowercase\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"phase:2,id:1,msg:'This is a test, %{REQUEST_HEADERS:Accept}%'\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: supporting transformation + t:none",
"client":{
"ip":"200.249.12.31",
"port":2313
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"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=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
"Pragma":"no-cache",
"Cache-Control":"no-cache"
},
"uri":"\/test.pl?param1= test &param2=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":" Target value: \"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120\" ",
"error_log":""
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,t:lowercase\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:none,phase:2,id:1,msg:'This is a test, %{REQUEST_HEADERS:Accept}%'\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: t:none",
"expected":{
"parser_error":"The transformation none is not suitable to be part of the SecDefaultActions"
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,t:none\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:none,phase:2,id:1,msg:'This is a test, %{REQUEST_HEADERS:Accept}%'\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: simple test",
"client":{
"ip":"200.249.12.31",
"port":2313
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"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=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
"Pragma":"no-cache",
"Cache-Control":"no-cache"
},
"uri":"\/test.pl?param1= test &param2=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":"Saving msg: This is a test, text\/html,application",
"error_log":""
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,log,auditlog,pass\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"id:1,t:lowercase,t:none,msg:'This is a test, %{REQUEST_HEADERS:Accept}%'\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: action not suitable",
"expected":{
"parser_error":"The action 'id:1' is not suitable to be part of the SecDefaultActions"
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,id:1,log,auditlog,pass,tag:'teste'\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"id:1,tag:'teste',t:lowercase,t:none,msg:'This is a test, %{REQUEST_HEADERS:Accept}%'\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: twice",
"expected":{
"parser_error":"SecDefaultActions can only be placed once per phase and configuration context. Phase 2 was informed already."
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,log,auditlog,pass,tag:'teste'\"",
"SecDefaultAction \"phase:2,log,auditlog,pass,tag:'teste'\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"id:1,tag:'teste',t:lowercase,t:none,msg:'This is a test, %{REQUEST_HEADERS:Accept}%'\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"version_max":0,
"title":"Testing action :: SecDefaultAction: status + redirect",
"client":{
"ip":"200.249.12.31",
"port":2313
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"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=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
"Pragma":"no-cache",
"Cache-Control":"no-cache"
},
"uri":"\/test.pl?param1= test &param2=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":"Request was relevant to be saved.",
"http_code": 500
},
"rules":[
"SecRuleEngine On",
"SecDebugLog \/tmp\/modsec_debug.log",
"SecDebugLogLevel 9",
"SecDefaultAction \"phase:2,log,auditlog,status:500\"",
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"phase:2,id:1,redirect:http://www.google.com\"",
"SecRule TX \"@contains to_test\" \"id:2,t:lowercase,t:none\""
]
}
]