From 0be821ded7f5560e7e818b730a742f38938fce65 Mon Sep 17 00:00:00 2001 From: asterite Date: Thu, 17 Aug 2017 16:44:01 +0300 Subject: [PATCH] change parsing of SetVar actions Change tokenization of SetVar expressions and use syntax analyzer (seclang-parser) to process them. More precisely: 1 SetVar expression is tokenized in two modes, quoted and not quoted, depending on whether it started with single quote (') 2 Variable name and value can consist of multiple tokens, which are assembled back in syntax analyzer. This allows to support escapes (escape single/double quote, spaces etc.) and correctly detect where the expression ends. Fixes #1529 --- src/parser/seclang-parser.yy | 73 +++++++++++++++------ src/parser/seclang-scanner.ll | 115 ++++++++++++++++++---------------- 2 files changed, 116 insertions(+), 72 deletions(-) diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index 5eb61688..40f8f913 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -649,6 +649,8 @@ using modsecurity::operators::Operator; RUN_TIME_VAR_TIME_SEC "RUN_TIME_VAR_TIME_SEC" RUN_TIME_VAR_TIME_WDAY "RUN_TIME_VAR_TIME_WDAY" RUN_TIME_VAR_TIME_YEAR "RUN_TIME_VAR_TIME_YEAR" + SETVAR_VARIABLE_PART "SETVAR_VARIABLE_PART" + SETVAR_CONTENT_PART "SETVAR_CONTENT_PART" VARIABLE "VARIABLE" DICT_ELEMENT "Dictionary element" DICT_ELEMENT_REGEXP "Dictionary element, selected by regexp" @@ -656,6 +658,10 @@ using modsecurity::operators::Operator; %type > act +%type > setvar_action +%type setvar_variable +%type setvar_content + %type > > > actions_may_quoted actions @@ -2321,25 +2327,9 @@ act: { ACTION_CONTAINER($$, new actions::SetUID($1)); } - | ACTION_SETVAR NOT VARIABLE + | ACTION_SETVAR setvar_action { - ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::unsetOperation, $3)); - } - | ACTION_SETVAR VARIABLE - { - ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::setToOneOperation, $2)); - } - | ACTION_SETVAR VARIABLE SETVAR_OPERATION_EQUALS FREE_TEXT - { - ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::setOperation, $2, $4)); - } - | ACTION_SETVAR VARIABLE SETVAR_OPERATION_EQUALS_PLUS FREE_TEXT - { - ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::sumAndSetOperation, $2, $4)); - } - | ACTION_SETVAR VARIABLE SETVAR_OPERATION_EQUALS_MINUS FREE_TEXT - { - ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::substractAndSetOperation, $2, $4)); + $$ = std::move($2); } | ACTION_SEVERITY { @@ -2487,6 +2477,53 @@ act: } ; +setvar_action: + NOT setvar_variable + { + ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::unsetOperation, $2)); + } + | setvar_variable + { + ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::setToOneOperation, $1)); + } + | setvar_variable SETVAR_OPERATION_EQUALS setvar_content + { + ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::setOperation, $1, $3)); + } + | setvar_variable SETVAR_OPERATION_EQUALS_PLUS setvar_content + { + ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::sumAndSetOperation, $1, $3)); + } + | setvar_variable SETVAR_OPERATION_EQUALS_MINUS setvar_content + { + ACTION_CONTAINER($$, new actions::SetVar(actions::SetVarOperation::substractAndSetOperation, $1, $3)); + } + ; + +setvar_variable: + SETVAR_VARIABLE_PART + { + $$ = $1; + } + | + SETVAR_VARIABLE_PART setvar_variable + { + $$ = $1 + $2; + } + ; + +setvar_content: + SETVAR_CONTENT_PART + { + $$ = $1; + } + | + SETVAR_CONTENT_PART setvar_content + { + $$ = $1 + $2; + } +; + %% void yy::seclang_parser::error (const location_type& l, const std::string& m) { diff --git a/src/parser/seclang-scanner.ll b/src/parser/seclang-scanner.ll index 89ff0c1c..dc33bfaa 100755 --- a/src/parser/seclang-scanner.ll +++ b/src/parser/seclang-scanner.ll @@ -328,7 +328,8 @@ DICT_ELEMENT ([^\"|,\n \t]|([^\\]\\\"))+ DICT_ELEMENT_WITH_PIPE [^ \t"]+ -DICT_ELEMENT_TWO [^\"\=]+ +DICT_ELEMENT_TWO [^\"\=, \t\r\n\\]* +DICT_ELEMENT_TWO_QUOTED [^\"\'\=\r\n\\]* DICT_ELEMENT_TWO2 [A-Za-z_ -\%\{\.\}\-\/]+ DIRECTIVE (?i:SecRule) DIRECTIVE_SECRULESCRIPT (?i:SecRuleScript) @@ -370,9 +371,14 @@ EQUALS_MINUS (?i:=\-) %x FINISH_ACTIONS %x LEXING_ERROR %x LEXING_ERROR_ACTION -%x SETVAR_ACTION_WAITING_VARIABLE -%x SETVAR_ACTION_WAITING_OPERATION -%x SETVAR_ACTION_WAITING_CONTENT +%x SETVAR_ACTION_NONQUOTED +%x SETVAR_ACTION_NONQUOTED_WAITING_COLLECTION_ELEM +%x SETVAR_ACTION_NONQUOTED_WAITING_OPERATION +%x SETVAR_ACTION_NONQUOTED_WAITING_CONTENT +%x SETVAR_ACTION_QUOTED +%x SETVAR_ACTION_QUOTED_WAITING_COLLECTION_ELEM +%x SETVAR_ACTION_QUOTED_WAITING_OPERATION +%x SETVAR_ACTION_QUOTED_WAITING_CONTENT %{ // Code run each time a pattern is matched. @@ -452,7 +458,8 @@ EQUALS_MINUS (?i:=\-) {ACTION_SETUID}:'{VAR_FREE_TEXT_QUOTE}' { return p::make_ACTION_SETUID(yytext, *driver.loc.back()); } {ACTION_SETUID}:{VAR_FREE_TEXT_SPACE_COMMA} { return p::make_ACTION_SETUID(yytext, *driver.loc.back()); } -{ACTION_SETVAR}: { BEGIN(SETVAR_ACTION_WAITING_VARIABLE); return p::make_ACTION_SETVAR(*driver.loc.back()); } +{ACTION_SETVAR}:' { BEGIN(SETVAR_ACTION_QUOTED); return p::make_ACTION_SETVAR(*driver.loc.back()); } +{ACTION_SETVAR}: { BEGIN(SETVAR_ACTION_NONQUOTED); return p::make_ACTION_SETVAR(*driver.loc.back()); } {ACTION_SEVERITY}:'{ACTION_SEVERITY_VALUE}' { return p::make_ACTION_SEVERITY(yytext, *driver.loc.back()); } @@ -513,61 +520,61 @@ EQUALS_MINUS (?i:=\-) . { BEGIN(LEXING_ERROR_ACTION); yyless(0); } } -{ -\'* { } -\"* { } -{NOT} { return p::make_NOT(*driver.loc.back()); } -{VARIABLE_TX}(\:[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_TX}(\:{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_TX}(\.[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_TX}(\.{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_SESSION}(\:[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_SESSION}(\:{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_SESSION}(\.[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_SESSION}(\.{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_RESOURCE}(\:[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_RESOURCE}(\:{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_RESOURCE}(\.[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_RESOURCE}(\.{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_IP}(\:[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_IP}(\:{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_IP}(\.[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_IP}(\.{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_USER}(\:[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_USER}(\:{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_USER}(\.[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_USER}(\.{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_GLOBAL}(\:[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_GLOBAL}(\:{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_GLOBAL}(\.[\']{DICT_ELEMENT_TWO}[\'])? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -{VARIABLE_GLOBAL}(\.{DICT_ELEMENT_TWO})? { BEGIN(SETVAR_ACTION_WAITING_OPERATION); return p::make_VARIABLE(yytext, *driver.loc.back()); } -. { BEGIN(LEXING_ERROR_ACTION); yyless(0); } -[ \t]*\\\n[ \t]* { driver.loc.back()->lines(1); driver.loc.back()->step(); } -[ \t]*\\\r\n[ \t]* { driver.loc.back()->lines(1); driver.loc.back()->step(); } +{ +{NOT} { return p::make_NOT(*driver.loc.back()); } +{VARIABLE_TX}|{VARIABLE_SESSION}|{VARIABLE_RESOURCE}|{VARIABLE_IP}|{VARIABLE_USER}|{VARIABLE_GLOBAL}[:\.] { BEGIN(SETVAR_ACTION_NONQUOTED_WAITING_COLLECTION_ELEM); return p::make_SETVAR_VARIABLE_PART(yytext, *driver.loc.back());} +{VARIABLE_TX}|{VARIABLE_SESSION}|{VARIABLE_RESOURCE}|{VARIABLE_IP}|{VARIABLE_USER}|{VARIABLE_GLOBAL} { BEGIN(SETVAR_ACTION_NONQUOTED_WAITING_OPERATION); return p::make_SETVAR_VARIABLE_PART(yytext, *driver.loc.back());} +.|\n { BEGIN(LEXING_ERROR_ACTION); yyless(0); } } - - - -{ -[ \t]*\n { BEGIN(INITIAL); yyless(1); } -[ \t]*\r\n { BEGIN(INITIAL); driver.loc.back()->lines(1); driver.loc.back()->step(); } -[ \t]*\n { BEGIN(EXPECTING_ACTIONS); yyless(yyleng); driver.loc.back()->lines(1); driver.loc.back()->step(); } -[ \t]*\r\n { BEGIN(EXPECTING_ACTIONS); yyless(yyleng); driver.loc.back()->lines(1); driver.loc.back()->step(); } -[ \t]*\"[ \t]* { } -[ \t]*\'[ \t]* { } -\"[ \t]*\n { BEGIN(EXPECTING_ACTIONS); yyless(1); } -\"[ \t]*\r\n { BEGIN(EXPECTING_ACTIONS); driver.loc.back()->lines(1); driver.loc.back()->step(); } -{EQUALS_PLUS} { BEGIN(SETVAR_ACTION_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS_PLUS(*driver.loc.back()); } -{EQUALS_MINUS} { BEGIN(SETVAR_ACTION_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS_MINUS(*driver.loc.back()); } -{EQUALS} { BEGIN(SETVAR_ACTION_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS(*driver.loc.back()); } -. { BEGIN(LEXING_ERROR_ACTION); yyless(0); } +{ +{DICT_ELEMENT_TWO} { return p::make_SETVAR_VARIABLE_PART(yytext, *driver.loc.back()); } +\\(.|\n) { return p::make_SETVAR_VARIABLE_PART(yytext + 1, *driver.loc.back()); } +.|\n { BEGIN(SETVAR_ACTION_NONQUOTED_WAITING_OPERATION); yyless(0); } } -{ -[^,"\n]+ { BEGIN(EXPECTING_ACTIONS); return p::make_FREE_TEXT(yytext, *driver.loc.back()); } +{ +{EQUALS_PLUS} { BEGIN(SETVAR_ACTION_NONQUOTED_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS_PLUS(*driver.loc.back()); } +{EQUALS_MINUS} { BEGIN(SETVAR_ACTION_NONQUOTED_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS_MINUS(*driver.loc.back()); } +{EQUALS} { BEGIN(SETVAR_ACTION_NONQUOTED_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS(*driver.loc.back()); } +.|\n { BEGIN(EXPECTING_ACTIONS); yyless(0);} } +{ +\\(.|\n) { return p::make_SETVAR_CONTENT_PART(yytext + 1, *driver.loc.back()); } +[^,"\n\r\t \\]+ { return p::make_SETVAR_CONTENT_PART(yytext, *driver.loc.back()); } +.|\n { BEGIN(EXPECTING_ACTIONS); yyless(0); } +} + +{ +{NOT} { return p::make_NOT(*driver.loc.back()); } +{VARIABLE_TX}|{VARIABLE_SESSION}|{VARIABLE_RESOURCE}|{VARIABLE_IP}|{VARIABLE_USER}|{VARIABLE_GLOBAL}[:\.] { BEGIN(SETVAR_ACTION_QUOTED_WAITING_COLLECTION_ELEM); return p::make_SETVAR_VARIABLE_PART(yytext, *driver.loc.back());} +{VARIABLE_TX}|{VARIABLE_SESSION}|{VARIABLE_RESOURCE}|{VARIABLE_IP}|{VARIABLE_USER}|{VARIABLE_GLOBAL} { BEGIN(SETVAR_ACTION_QUOTED_WAITING_OPERATION); return p::make_SETVAR_VARIABLE_PART(yytext, *driver.loc.back());} +.|\n { BEGIN(LEXING_ERROR_ACTION); yyless(0); } +} + +{ +{DICT_ELEMENT_TWO_QUOTED} { return p::make_SETVAR_VARIABLE_PART(yytext, *driver.loc.back()); } +\\(.|\n) { return p::make_SETVAR_VARIABLE_PART(yytext + 1, *driver.loc.back()); } +.|\n { BEGIN(SETVAR_ACTION_QUOTED_WAITING_OPERATION); yyless(0); } +} + +{ +{EQUALS_PLUS} { BEGIN(SETVAR_ACTION_QUOTED_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS_PLUS(*driver.loc.back()); } +{EQUALS_MINUS} { BEGIN(SETVAR_ACTION_QUOTED_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS_MINUS(*driver.loc.back()); } +{EQUALS} { BEGIN(SETVAR_ACTION_QUOTED_WAITING_CONTENT); return p::make_SETVAR_OPERATION_EQUALS(*driver.loc.back()); } +\' { BEGIN(EXPECTING_ACTIONS); } +.|\n { BEGIN(LEXING_ERROR_ACTION); yyless(0); } +} + +{ +\\(.|\n) { return p::make_SETVAR_CONTENT_PART(yytext + 1, *driver.loc.back()); } +[^"\'\n\r\\]* { return p::make_SETVAR_CONTENT_PART(yytext, *driver.loc.back()); } +\' { BEGIN(EXPECTING_ACTIONS); } +.|\n { BEGIN(LEXING_ERROR_ACTION); yyless(0); } +} + + { <> { BEGIN(INITIAL); yyless(0); p::make_NEW_LINE(*driver.loc.back()); } . { BEGIN(INITIAL); }