From 21be9582d9eb1f68d319704266639bf198a9c897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ervin=20Heged=C3=BCs?= Date: Wed, 29 May 2024 22:39:42 +0200 Subject: [PATCH 1/2] Allow ';' in PathNameValue; Make XML collection less strict --- src/secrules_parsing/model/secrules.tx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/secrules_parsing/model/secrules.tx b/src/secrules_parsing/model/secrules.tx index 52aa169..1650c16 100644 --- a/src/secrules_parsing/model/secrules.tx +++ b/src/secrules_parsing/model/secrules.tx @@ -60,7 +60,7 @@ Variable: 'PERF_PHASE2' | 'PERF_PHASE3' | 'PERF_PHASE4' | 'PERF_PHASE5' | 'PERF_SREAD' | 'PERF_SWRITE' | 'QUERY_STRING' | 'REMOTE_ADDR' | 'REMOTE_HOST' | 'REMOTE_PORT' | 'REMOTE_USER' | 'REQBODY_ERROR' | 'REQBODY_ERROR_MSG' | 'REQBODY_PROCESSOR' | 'REQUEST_BASENAME' | - 'REQUEST_BODY' | 'REQUEST_BODY_LENGTH' | 'REQUEST_FILENAME' | 'REQUEST_LINE' | + 'REQUEST_BODY_LENGTH' | 'REQUEST_BODY' | 'REQUEST_FILENAME' | 'REQUEST_LINE' | 'REQUEST_METHOD' | 'REQUEST_PROTOCOL' | 'REQUEST_URI_RAW' |'REQUEST_URI' | 'RESPONSE_BODY' | 'RESPONSE_CONTENT_LENGTH' | 'RESPONSE_CONTENT_TYPE' | 'RESPONSE_PROTOCOL' | 'RESPONSE_STATUS' | 'RULE' | 'SCRIPT_BASENAME' | 'SCRIPT_FILENAME' | @@ -85,7 +85,7 @@ CollectionName: 'RULE' | 'SESSION' | 'TX') ; -SpecialCollection: 'XML' ':' XPathExpression; +SpecialCollection: 'XML' ':'? XPathExpression?; XPathExpression: /(\/\*|\/\/@\*)/; @@ -192,7 +192,7 @@ StringWithSpaces: /[A-Za-z0-9\-\/\ \._]+/; PathOrMacro: PathNameValue | MacroVar; // Filesystem Paths (could be merged with URI, tought) -PathNameValue: /[a-zA-Z0-9\-_\.\/]+/; +PathNameValue: /[a-zA-Z0-9\-_\.\/;]+/; // Macros, e.g: %{tx.critical_anomaly_score} Macro: INT | OperationMacro | ExtendedMacro | MacroVar; From f374f103a923a8c821963accb2ea8768817ab8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ervin=20Heged=C3=BCs?= Date: Thu, 19 Sep 2024 11:48:45 +0200 Subject: [PATCH 2/2] fix: move FILES to collections --- src/secrules_parsing/model/secrules.tx | 8 ++++---- tests/test_api.py | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/secrules_parsing/model/secrules.tx b/src/secrules_parsing/model/secrules.tx index 1650c16..8d7ad8e 100644 --- a/src/secrules_parsing/model/secrules.tx +++ b/src/secrules_parsing/model/secrules.tx @@ -51,11 +51,11 @@ FILES is a collection, so it doesn't belong here */ Variable: '!'? '&'? ('ARGS_COMBINED_SIZE' | 'ARGS_GET_NAMES' | 'ARGS_NAMES' | 'ARGS_POST_NAMES' | - 'AUTH_TYPE' | 'DURATION' | 'FILES_COMBINED_SIZE' | 'FILES_NAMES' | 'FILES' | - 'FULL_REQUEST' | 'FULL_REQUEST_LENGTH' | 'FILES_SIZES' | 'FILES_TMPNAMES' | + 'AUTH_TYPE' | 'DURATION' | 'FILES_COMBINED_SIZE' | 'FILES_NAMES' | + 'FULL_REQUEST' | 'FULL_REQUEST_LENGTH' | 'FILES_SIZES' | 'FILES_TMPNAMES' | 'FILES_TMP_CONTENT' | 'HIGHEST_SEVERITY' | 'INBOUND_DATA_ERROR' | 'MATCHED_VAR_NAME' | 'MODSEC_BUILD' | 'MULTIPART_CRLF_LF_LINES' | 'MULTIPART_FILENAME' | 'MULTIPART_NAME' | - 'MULTIPART_STRICT_ERROR' | 'MULTIPART_UNMATCHED_BOUNDARY' | 'OUTBOUND_DATA_ERROR' | + 'MULTIPART_STRICT_ERROR' | 'MULTIPART_UNMATCHED_BOUNDARY' | 'OUTBOUND_DATA_ERROR' | 'PATH_INFO' | 'PERF_ALL' | 'PERF_COMBINED' | 'PERF_GC' | 'PERF_LOGGING' | 'PERF_PHASE1' | 'PERF_PHASE2' | 'PERF_PHASE3' | 'PERF_PHASE4' | 'PERF_PHASE5' | 'PERF_SREAD' | 'PERF_SWRITE' | 'QUERY_STRING' | 'REMOTE_ADDR' | 'REMOTE_HOST' | 'REMOTE_PORT' | 'REMOTE_USER' | @@ -79,7 +79,7 @@ CollectionArgument: AnythingBetweenSingleQuotes | '/' SlashedRegExp '/' | Variab /* Collections */ CollectionName: - ('ARGS_GET' | 'ARGS_POST' | 'ARGS' | 'ENV' | 'GEO' | 'GLOBAL' | 'IP' | 'MATCHED_VARS_NAMES' | + ('ARGS_GET' | 'ARGS_POST' | 'ARGS' | 'ENV' | 'FILES' | 'GEO' | 'GLOBAL' | 'IP' | 'MATCHED_VARS_NAMES' | 'MATCHED_VARS' | 'MULTIPART_PART_HEADERS' | 'PERF_RULES' | 'REQUEST_COOKIES_NAMES' | 'REQUEST_COOKIES' | 'REQUEST_HEADERS_NAMES' | 'REQUEST_HEADERS' | 'RESPONSE_HEADERS_NAMES' | 'RESPONSE_HEADERS' | 'RULE' | 'SESSION' | 'TX') diff --git a/tests/test_api.py b/tests/test_api.py index 254eed2..49f3563 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -19,13 +19,14 @@ def test_model_parse() -> None: """Test that we can parse the model correctly""" rule_text = """ SecRule ARGS "@rx found" "id:1,log,noauditlog,t:lowercase,block" + SecRule FILES:pluginzip "@endsWith .zip" "id:2,phase:2,pass,t:none,ctl:ruleRemoveTargetById=944110;REQUEST_BODY,ctl:ruleRemoveTargetById=944250;REQUEST_BODY" """ parsed_rule = parser.process_from_str(rule_text) # print(ppretty(parsed_rule, depth=10)) for rule in parsed_rule.rules: assert (rule.__class__.__name__) == "SecRule" for var in rule.variables: - assert var.collection == "ARGS" + assert var.collection in ["ARGS", "FILES"] def test_operator_contains_works_with_greater_than() -> None: