Support equals sign in XPath expressions

This commit is contained in:
Martin Vierula 2023-01-19 08:37:38 -08:00
parent dabf79eec2
commit ec1232a69b
No known key found for this signature in database
GPG Key ID: F2FC4E45883BCBA4
8 changed files with 5222 additions and 5140 deletions

View File

@ -1,6 +1,8 @@
v3.x.y - YYYY-MMM-DD (to be released)
-------------------------------------
- Support equals sign in XPath expressions
[Issue #2328 - @dennus, @martinhsv]
- Encode two special chars in error.log output
[Issue #2854 - @airween, @martinhsv]
- Add JIT support for PCRE2

View File

@ -279,6 +279,7 @@ TESTS+=test/test-cases/regression/variable-variation-count.json
TESTS+=test/test-cases/regression/variable-variation-exclusion.json
TESTS+=test/test-cases/regression/variable-WEBAPPID.json
TESTS+=test/test-cases/regression/variable-WEBSERVER_ERROR_LOG.json
TESTS+=test/test-cases/regression/variable-XML.json
TESTS+=test/test-cases/secrules-language-tests/operators/beginsWith.json
TESTS+=test/test-cases/secrules-language-tests/operators/contains.json
TESTS+=test/test-cases/secrules-language-tests/operators/containsWord.json

File diff suppressed because it is too large Load Diff

View File

@ -897,6 +897,7 @@ namespace yy {
// "RUN_TIME_VAR_TIME_YEAR"
// "VARIABLE"
// "Dictionary element"
// "Dictionary element, with equals"
// "Dictionary element, selected by regexp"
char dummy1[sizeof (std::string)];
@ -1314,7 +1315,8 @@ namespace yy {
TOK_RUN_TIME_VAR_TIME_YEAR = 596, // "RUN_TIME_VAR_TIME_YEAR"
TOK_VARIABLE = 597, // "VARIABLE"
TOK_DICT_ELEMENT = 598, // "Dictionary element"
TOK_DICT_ELEMENT_REGEXP = 599 // "Dictionary element, selected by regexp"
TOK_DICT_ELEMENT_WITH_EQUALS = 599, // "Dictionary element, with equals"
TOK_DICT_ELEMENT_REGEXP = 600 // "Dictionary element, selected by regexp"
};
/// Backward compatibility alias (Bison 3.6).
typedef token_kind_type yytokentype;
@ -1331,7 +1333,7 @@ namespace yy {
{
enum symbol_kind_type
{
YYNTOKENS = 345, ///< Number of tokens.
YYNTOKENS = 346, ///< Number of tokens.
S_YYEMPTY = -2,
S_YYEOF = 0, // "end of file"
S_YYerror = 1, // error
@ -1677,23 +1679,24 @@ namespace yy {
S_RUN_TIME_VAR_TIME_YEAR = 341, // "RUN_TIME_VAR_TIME_YEAR"
S_VARIABLE = 342, // "VARIABLE"
S_DICT_ELEMENT = 343, // "Dictionary element"
S_DICT_ELEMENT_REGEXP = 344, // "Dictionary element, selected by regexp"
S_YYACCEPT = 345, // $accept
S_input = 346, // input
S_line = 347, // line
S_audit_log = 348, // audit_log
S_actions = 349, // actions
S_actions_may_quoted = 350, // actions_may_quoted
S_op = 351, // op
S_op_before_init = 352, // op_before_init
S_expression = 353, // expression
S_variables = 354, // variables
S_variables_pre_process = 355, // variables_pre_process
S_variables_may_be_quoted = 356, // variables_may_be_quoted
S_var = 357, // var
S_act = 358, // act
S_setvar_action = 359, // setvar_action
S_run_time_string = 360 // run_time_string
S_DICT_ELEMENT_WITH_EQUALS = 344, // "Dictionary element, with equals"
S_DICT_ELEMENT_REGEXP = 345, // "Dictionary element, selected by regexp"
S_YYACCEPT = 346, // $accept
S_input = 347, // input
S_line = 348, // line
S_audit_log = 349, // audit_log
S_actions = 350, // actions
S_actions_may_quoted = 351, // actions_may_quoted
S_op = 352, // op
S_op_before_init = 353, // op_before_init
S_expression = 354, // expression
S_variables = 355, // variables
S_variables_pre_process = 356, // variables_pre_process
S_variables_may_be_quoted = 357, // variables_may_be_quoted
S_var = 358, // var
S_act = 359, // act
S_setvar_action = 360, // setvar_action
S_run_time_string = 361 // run_time_string
};
};
@ -1927,6 +1930,7 @@ namespace yy {
case symbol_kind::S_RUN_TIME_VAR_TIME_YEAR: // "RUN_TIME_VAR_TIME_YEAR"
case symbol_kind::S_VARIABLE: // "VARIABLE"
case symbol_kind::S_DICT_ELEMENT: // "Dictionary element"
case symbol_kind::S_DICT_ELEMENT_WITH_EQUALS: // "Dictionary element, with equals"
case symbol_kind::S_DICT_ELEMENT_REGEXP: // "Dictionary element, selected by regexp"
value.move< std::string > (std::move (that.value));
break;
@ -2300,6 +2304,7 @@ switch (yykind)
case symbol_kind::S_RUN_TIME_VAR_TIME_YEAR: // "RUN_TIME_VAR_TIME_YEAR"
case symbol_kind::S_VARIABLE: // "VARIABLE"
case symbol_kind::S_DICT_ELEMENT: // "Dictionary element"
case symbol_kind::S_DICT_ELEMENT_WITH_EQUALS: // "Dictionary element, with equals"
case symbol_kind::S_DICT_ELEMENT_REGEXP: // "Dictionary element, selected by regexp"
value.template destroy< std::string > ();
break;
@ -7648,6 +7653,21 @@ switch (yykind)
return symbol_type (token::TOK_DICT_ELEMENT, v, l);
}
#endif
#if 201103L <= YY_CPLUSPLUS
static
symbol_type
make_DICT_ELEMENT_WITH_EQUALS (std::string v, location_type l)
{
return symbol_type (token::TOK_DICT_ELEMENT_WITH_EQUALS, std::move (v), std::move (l));
}
#else
static
symbol_type
make_DICT_ELEMENT_WITH_EQUALS (const std::string& v, const location_type& l)
{
return symbol_type (token::TOK_DICT_ELEMENT_WITH_EQUALS, v, l);
}
#endif
#if 201103L <= YY_CPLUSPLUS
static
symbol_type
@ -7993,7 +8013,7 @@ switch (yykind)
/// Constants.
enum
{
yylast_ = 3344, ///< Last index in yytable_.
yylast_ = 3346, ///< Last index in yytable_.
yynnts_ = 16, ///< Number of nonterminal symbols.
yyfinal_ = 339 ///< Termination state number.
};
@ -8073,10 +8093,11 @@ switch (yykind)
305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
335, 336, 337, 338, 339, 340, 341, 342, 343, 344
335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
345
};
// Last valid token kind.
const int code_max = 599;
const int code_max = 600;
if (t <= 0)
return symbol_kind::S_YYEOF;
@ -8292,6 +8313,7 @@ switch (yykind)
case symbol_kind::S_RUN_TIME_VAR_TIME_YEAR: // "RUN_TIME_VAR_TIME_YEAR"
case symbol_kind::S_VARIABLE: // "VARIABLE"
case symbol_kind::S_DICT_ELEMENT: // "Dictionary element"
case symbol_kind::S_DICT_ELEMENT_WITH_EQUALS: // "Dictionary element, with equals"
case symbol_kind::S_DICT_ELEMENT_REGEXP: // "Dictionary element, selected by regexp"
value.copy< std::string > (YY_MOVE (that.value));
break;
@ -8551,6 +8573,7 @@ switch (yykind)
case symbol_kind::S_RUN_TIME_VAR_TIME_YEAR: // "RUN_TIME_VAR_TIME_YEAR"
case symbol_kind::S_VARIABLE: // "VARIABLE"
case symbol_kind::S_DICT_ELEMENT: // "Dictionary element"
case symbol_kind::S_DICT_ELEMENT_WITH_EQUALS: // "Dictionary element, with equals"
case symbol_kind::S_DICT_ELEMENT_REGEXP: // "Dictionary element, selected by regexp"
value.move< std::string > (YY_MOVE (s.value));
break;
@ -8646,7 +8669,7 @@ switch (yykind)
}
} // yy
#line 8650 "seclang-parser.hh"
#line 8673 "seclang-parser.hh"

View File

@ -680,6 +680,7 @@ using namespace modsecurity::operators;
RUN_TIME_VAR_TIME_YEAR "RUN_TIME_VAR_TIME_YEAR"
VARIABLE "VARIABLE"
DICT_ELEMENT "Dictionary element"
DICT_ELEMENT_WITH_EQUALS "Dictionary element, with equals"
DICT_ELEMENT_REGEXP "Dictionary element, selected by regexp"
;

File diff suppressed because it is too large Load Diff

View File

@ -420,6 +420,7 @@ DICT_ELEMENT ([^\"|,\n \t}=]|([^\\]\\\"))+
DICT_ELEMENT_WITH_PIPE [^ =\t"]+
DICT_ELEMENT_NO_PIPE [^ =\|\t"]+
DICT_ELEMENT_NO_MACRO ([^\"|,%{\n \t}=]|([^\\]\\\"))+
DICT_ELEMENT_WITH_EQUALS ([^\"|,\n \t}]|([^\\]\\\"))+
DIRECTIVE (?i:SecRule)
DIRECTIVE_SECRULESCRIPT (?i:SecRuleScript)
@ -1065,7 +1066,7 @@ EQUALS_MINUS (?i:=\-)
[\/]{DICT_ELEMENT_NO_PIPE}[\/][|] { BEGIN_PREVIOUS(); yyless(yyleng - 1); return p::make_DICT_ELEMENT_REGEXP(std::string(yytext, 1, yyleng-2), *driver.loc.back()); }
['][\/]{DICT_ELEMENT_WITH_PIPE}[\/]['] { BEGIN_PREVIOUS(); yyless(yyleng - 0); return p::make_DICT_ELEMENT_REGEXP(std::string(yytext, 2, yyleng-4), *driver.loc.back()); }
['][\/]{DICT_ELEMENT_WITH_PIPE}[\/]['][|] { BEGIN_PREVIOUS(); yyless(yyleng - 1); return p::make_DICT_ELEMENT_REGEXP(std::string(yytext, 2, yyleng-4), *driver.loc.back()); }
{DICT_ELEMENT} { BEGIN_PREVIOUS(); return p::make_DICT_ELEMENT(yytext, *driver.loc.back()); }
{DICT_ELEMENT_WITH_EQUALS} { BEGIN_PREVIOUS(); return p::make_DICT_ELEMENT(yytext, *driver.loc.back()); }
[\/]{DICT_ELEMENT_NO_PIPE}[\/][,] { BEGIN_PREVIOUS(); yyless(yyleng - 1); return p::make_DICT_ELEMENT_REGEXP(std::string(yytext, 1, yyleng-2), *driver.loc.back()); }
['][\/]{DICT_ELEMENT_NO_PIPE}[\/]['][,] { BEGIN_PREVIOUS(); yyless(yyleng - 1); return p::make_DICT_ELEMENT_REGEXP(std::string(yytext, 2, yyleng-4), *driver.loc.back()); }

View File

@ -0,0 +1,46 @@
[
{
"enabled":1,
"version_min":300000,
"title":"Testing XPath expression with equals sign",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?key=value&key=other_value",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule XML://bookstore/*[local-name()='some-tag'] \"bbb\" \"id:500012,phase:3,t:none,t:lowercase,log,deny,status:403\""
]
}
]