View file File name : REQUEST-920-PROTOCOL-ENFORCEMENT.conf Content :# ------------------------------------------------------------------------ # OWASP CRS ver.4.7.0-dev # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. # Copyright (c) 2021-2024 CRS project. All rights reserved. # # The OWASP CRS is distributed under # Apache Software License (ASL) version 2 # Please see the enclosed LICENSE file for full details. # ------------------------------------------------------------------------ # # Some protocol violations are common in application layer attacks. # Validating HTTP requests eliminates a large number of application layer attacks. # # The purpose of this rules file is to enforce HTTP RFC requirements that state how # the client is supposed to interact with the server. # https://www.rfc-editor.org/rfc/rfc9110.html # # -= Paranoia Level 0 (empty) =- (apply unconditionally) # SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 1" "id:920011,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 1" "id:920012,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 1 (default) =- (apply only when tx.detection_paranoia_level is sufficiently high: 1 or higher) # # # Validate request line against the format specified in the HTTP RFC # # -=[ Rule Logic ]=- # # Uses rule negation against the regex for positive security. The regex specifies the proper # construction of URI request lines such as: # # "http" "://" authority path-abempty [ "?" query ] # # It also outlines proper construction for CONNECT, OPTIONS and GET requests. # # Regular expression generated from regex-assembly/920100.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920100 # # -=[ References ]=- # https://www.rfc-editor.org/rfc/rfc9110.html#section-4.2.1 # http://capec.mitre.org/data/definitions/272.html # SecRule REQUEST_LINE "!@rx (?i)^(?:get /[^#\?]*(?:\?[^\s\x0b#]*)?(?:#[^\s\x0b]*)?|(?:connect (?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}\.?(?::[0-9]+)?|[\--9A-Z_a-z]+:[0-9]+)|options \*|[a-z]{3,10}[\s\x0b]+(?:[0-9A-Z_a-z]{3,7}?://[\--9A-Z_a-z]*(?::[0-9]+)?)?/[^#\?]*(?:\?[^\s\x0b#]*)?(?:#[^\s\x0b]*)?)[\s\x0b]+[\.-9A-Z_a-z]+)$" \ "id:920100,\ phase:1,\ block,\ t:none,\ msg:'Invalid HTTP Request Line',\ logdata:'%{request_line}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # Identify multipart/form-data name evasion attempts # # There are possible impedance mismatches between how # ModSecurity interprets multipart file names and how # a destination app server such as PHP might parse the # Content-Disposition data: # # filename-parm := "filename" "=" value # # -=[ Rule Logic ]=- # These rules check for the existence of the ' " ; = meta-characters in # either the "name" (FILES) and "filename" (FILES_NAMES) variables. # HTML entities may lead to false positives, which is why # frequently used ones, such as "ä", are allowed at PL1. # # -=[ Targets, characters and html entities ]=- # # 920120: PL1 : FILES_NAMES, FILES # Disallow ['\";=\\], except for frequently used HTML entities (see 920120.ra). # # 920121: PL2 : FILES_NAMES, FILES # Disallow ['\";=\\] # # -=[ References ]=- # http://www.ietf.org/rfc/rfc2183.txt # # This rule used to use negative look-behind. # See https://github.com/coreruleset/coreruleset/wiki/Technical-Decisions-and-Best-Practices#avoiding-negative-look-behind-in-regular-expressions # for an explanation of why it now uses `!@rx` instead to avoid look-around. # # Regular expression generated from regex-assembly/920120.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920120 # SecRule FILES|FILES_NAMES "!@rx (?i)^(?:&(?:(?:[acegilnorsuz]acut|[aeiou]grav|[aino]tild)e|[c-elnr-tz]caron|(?:[cgklnr-t]cedi|[aeiouy]um)l|[aceg-josuwy]circ|[au]ring|a(?:mp|pos)|nbsp|oslash);|[^\"';=\x5c])*$" \ "id:920120,\ phase:2,\ block,\ t:none,t:urlDecodeUni,\ msg:'Attempted multipart/form-data bypass',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Accept only digits in content length # # -=[ Rule Logic ]=- # This rule uses ModSecurity's rule negation against the regex meaning if the Content-Length header # is NOT all digits, then it will match. # # -=[ References ]=- # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6 # SecRule REQUEST_HEADERS:Content-Length "!@rx ^\d+$" \ "id:920160,\ phase:1,\ block,\ t:none,\ msg:'Content-Length HTTP header is not numeric',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Do not accept GET or HEAD requests with bodies # In RCF-9110, "A client SHOULD NOT generate content in a HEAD/GET request # unless it is made directly to an origin server that has previously indicated" # # -=[ Rule Logic ]=- # The chained rule matches when: # 1) If the request method is GET or HEAD # AND # 2) Header: Content-Length exists and non-zero # # -=[ References ]=- # https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.1 # https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.2 # SecRule REQUEST_METHOD "@rx ^(?:GET|HEAD)$" \ "id:920170,\ phase:1,\ block,\ t:none,\ msg:'GET or HEAD Request with Body Content',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule REQUEST_HEADERS:Content-Length "!@rx ^0?$" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # This is a sibling of rule 920170 # SecRule REQUEST_METHOD "@rx ^(?:GET|HEAD)$" \ "id:920171,\ phase:1,\ block,\ t:none,\ msg:'GET or HEAD Request with Transfer-Encoding',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule &REQUEST_HEADERS:Transfer-Encoding "!@eq 0" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Require Content-Length or Transfer-Encoding to be provided with # every POST request if the protocol version is not HTTP/2 or HTTP/3. # # In case of HTTP/2, see the RFC7540 8.1 p52: # HTTP/2 does not use the Transfer-Encoding: chunked anymore, because # the underlying transport protocol is already using data frames with # known length. # # In case of HTTP/3, see the RFC9114 4.1: # Transfer codings (see Section 7 of [HTTP/1.1]) are not defined for # HTTP/3; the Transfer-Encoding header field MUST NOT be used. # # -=[ Rule Logic ]=- # This chained rule checks if the protocol is not HTTP/2 or HTTP/3, # then checks request method is POST, if so, it checks that a # Content-Length or Transfer-Encoding headers are also present. # SecRule REQUEST_PROTOCOL "!@within HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0" \ "id:920180,\ phase:1,\ block,\ t:none,\ msg:'POST without Content-Length or Transfer-Encoding headers',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule REQUEST_METHOD "@streq POST" \ "chain" SecRule &REQUEST_HEADERS:Content-Length "@eq 0" \ "chain" SecRule &REQUEST_HEADERS:Transfer-Encoding "@eq 0" \ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # As per RFC7230 3.3.2: A sender MUST NOT send a Content-Length # header field in any message that contains a Transfer-Encoding header # field. # # Related to 920170, 920171 and 920180. # SecRule &REQUEST_HEADERS:Transfer-Encoding "!@eq 0" \ "id:920181,\ phase:1,\ block,\ t:none,\ msg:'Content-Length and Transfer-Encoding headers present',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule &REQUEST_HEADERS:Content-Length "!@eq 0" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # Range Header Check # # RFC7233 2.1 p6: # "A byte-range-spec is invalid if the last-byte-pos value is present # and less than the first-byte-pos." # # -=[ Rule Logic ]=- # This rule compares the first and second byte ranges and flags # when the first value is greater than the second. # # -=[ References ]=- # https://datatracker.ietf.org/doc/html/rfc7233 # https://seclists.org/fulldisclosure/2011/Aug/175 # SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx (\d+)-(\d+)" \ "id:920190,\ phase:1,\ block,\ capture,\ t:none,\ msg:'Range: Invalid Last Byte Value',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule TX:2 "@lt %{tx.1}" \ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # Broken/Malicious clients often have duplicate or conflicting headers # Automated programs and bots often do not obey the HTTP RFC # # -=[ Rule Logic ]=- # This rule inspects the Connection header and looks for duplicates of the # keep-alive and close options. # # -=[ References ]=- # https://datatracker.ietf.org/doc/html/rfc7233 # SecRule REQUEST_HEADERS:Connection "@rx \b(?:keep-alive|close),\s?(?:keep-alive|close)\b" \ "id:920210,\ phase:1,\ block,\ t:none,\ msg:'Multiple/Conflicting Connection Header Data Found',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # Check URL encodings # # -=[ Rule Logic ]=- # There are two different chained rules. We need to separate them as we are inspecting two # different variables - REQUEST_URI_RAW and REQUEST_BODY. For REQUEST_BODY, we only want to # run the @validateUrlEncoding operator if the content-type is application/x-www-form-urlencoding. # # We exclude the last path segment from validation because it could be a file name, which could # easily contain a '%' character that is not part of a URI encoded sequence. # # -=[ References ]=- # http://www.ietf.org/rfc/rfc1738.txt # # -=[ Example payload ]=- # http://localhost/?s=a%20b%20c%'/ # reason: %'/ is not a valid url encoding # # Regular expression generated from regex-assembly/920220-chain1.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920220-chain1 # SecRule REQUEST_URI_RAW "@rx \x25" \ "id:920220,\ phase:1,\ block,\ t:none,t:urlDecodeUni,\ msg:'URL Encoding Abuse Attack Attempt',\ logdata:'%{REQUEST_URI_RAW}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267/72',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule REQUEST_URI_RAW "@rx ^(.*)/(?:[^\?]+)?(\?.*)?$" \ "capture,\ chain" SecRule TX:1|TX:2 "@validateUrlEncoding" \ "t:none,t:urlDecodeUni,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # Validate URI encoding of the last path segment, only if it does not look like a file name. # A file name could easily contain a '%' character that is not part of a URI encoded sequence. # # Regular expression generated from regex-assembly/920221.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920221 # SecRule REQUEST_BASENAME "!@rx ^.*%.*\.[^\s\x0b\.]+$" \ "id:920221,\ phase:1,\ block,\ capture,\ t:none,t:urlDecodeUni,\ msg:'URL Encoding Abuse Attack Attempt',\ logdata:'%{REQUEST_BASENAME}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267/72',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule TX:0 "@validateUrlEncoding" \ "t:none,t:urlDecodeUni,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Check UTF encoding # We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise # it will result in false positives. # # -=[ Rule Logic ]=- # This chained rule first checks to see if the admin has set the TX:CRS_VALIDATE_UTF8_ENCODING # variable in the crs-setup.conf file. # SecRule TX:CRS_VALIDATE_UTF8_ENCODING "@eq 1" \ "id:920250,\ phase:2,\ block,\ t:none,\ msg:'UTF8 Encoding Abuse Attack Attempt',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "@validateUtf8Encoding" \ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # Disallow use of full-width unicode as decoding evasions may be possible. # # -=[ Rule Logic ]=- # This rule looks for full-width encoding by looking for %u followed by 2 'f' # characters and then 2 hex characters. It is a vulnerability that affected # IIS circa 2007. # The rule will trigger on %uXXXX formatted chars that are full or half # width, as explained above. This %uXXXX format is passed as a raw parameter # and is (seemingly only) accepted by IIS (5.0, 6.0, 7.0, and 8.0). Other # webservers will only process unicode chars presented as hex UTF-8 bytes. # # -=[ References ]=- # http://www.kb.cert.org/vuls/id/739224 # https://www.checkpoint.com/defense/advisories/public/2007/cpai-2007-201.html # https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/719 # # Regular expression generated from regex-assembly/920260.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920260 # SecRule REQUEST_URI|REQUEST_BODY "@rx (?i)%uff[0-9a-f]{2}" \ "id:920260,\ phase:2,\ block,\ t:none,\ msg:'Unicode Full/Half Width Abuse Attack Attempt',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-iis',\ tag:'platform-windows',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267/72',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # # Restrict type of characters sent # # This is a rule with multiple stricter siblings that grows more # restrictive in higher paranoia levels. # # -=[ Rule Logic ]=- # This rule uses the @validateByteRange operator to restrict the request # payloads. # # -=[ Targets and ASCII Ranges ]=- # # 920270: PL1 : REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES # ASCII 1-255 : Full ASCII range without null character # # 920271: PL2 : REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES # ASCII 9,10,13,32-126,128-255 : Full visible ASCII range, tab, newline # # 920272: PL3 : REQUEST_URI, REQUEST_HEADERS, ARGS, ARGS_NAMES and REQUEST_BODY # ASCII 32-36,38-126 : Visible lower ASCII range without percent symbol # # 920273: PL4 : ARGS, ARGS_NAMES and REQUEST_BODY # ASCII 38,44-46,48-58,61,65-90,95,97-122 # A-Z a-z 0-9 = - _ . , : & # # 920274: PL4 : REQUEST_HEADERS without User-Agent, Referer, Cookie # and Structured Header booleans # ASCII 32,34,38,42-59,61,65-90,95,97-122 # A-Z a-z 0-9 = - _ . , : & " * + / SPACE # # REQUEST_URI and REQUEST_HEADERS User-Agent, Referer and Cookie are very hard # to restrict beyond the limits in 920272. Structured Header booleans are # validated separately in 920275. # # 920274 generally has few positives. However, it would detect rare attacks # on Accept request headers and friends. SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 1-255" \ "id:920270,\ phase:2,\ block,\ t:none,t:urlDecodeUni,\ msg:'Invalid character in request (null character)',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Do not accept requests without common headers. # All normal web browsers include Host, User-Agent and Accept headers. # Implies either an attacker or a legitimate automation client. # # # Missing/Empty Host Header # # -=[ Rule Logic ]=- # These rules will first check to see if a Host header is present. # The second check is to see if a Host header exists but is empty. # SecRule &REQUEST_HEADERS:Host "@eq 0" \ "id:920280,\ phase:1,\ pass,\ t:none,\ msg:'Request Missing a Host Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}',\ skipAfter:END-HOST-CHECK" SecRule REQUEST_HEADERS:Host "@rx ^$" \ "id:920290,\ phase:1,\ block,\ t:none,\ msg:'Empty Host Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" SecMarker "END-HOST-CHECK" # # Empty Accept Header # # -=[ Rule Logic ]=- # This rule checks if an Accept header exists, but has an empty value. # This is only allowed in combination with the OPTIONS method. # Additionally, there are some clients sending empty Accept headers. # They are covered in another chained rule checking the User-Agent. # This technique demands a separate rule to detect an empty # Accept header if there is no user agent. This is checked via # the separate rule 920311. # # Exclude some common broken clients sending empty Accept header: # "Business/6.6.1.2 CFNetwork/758.5.3 Darwin/15.6.0" (CRS issue #515) # "Entreprise/6.5.0.177 CFNetwork/758.4.3 Darwin/15.5.0" (CRS issue #366) # # -=[ References ]=- # https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/366 # SecRule REQUEST_HEADERS:Accept "@rx ^$" \ "id:920310,\ phase:1,\ pass,\ t:none,\ msg:'Request Has an Empty Accept Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'NOTICE',\ chain" SecRule REQUEST_METHOD "!@rx ^OPTIONS$" \ "chain" SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android Business Enterprise Entreprise" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'" # # This rule is a sibling of rule 920310. # SecRule REQUEST_HEADERS:Accept "@rx ^$" \ "id:920311,\ phase:1,\ pass,\ t:none,\ msg:'Request Has an Empty Accept Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'NOTICE',\ chain" SecRule REQUEST_METHOD "!@rx ^OPTIONS$" \ "chain" SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'" # # Empty User-Agent Header # # -=[ Rule Logic ]=- # This rules will check to see if the User-Agent header is empty. # # Note that there is a second rule, 920320, which will check for # the existence of the User-Agent header. # SecRule REQUEST_HEADERS:User-Agent "@rx ^$" \ "id:920330,\ phase:1,\ pass,\ t:none,\ msg:'Empty User Agent Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'NOTICE',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'" # # Missing Content-Type Header with Request Body # # -=[ Rule Logic ]=- # This rule will first check to see if the value of the Content-Length header is # non-equal to 0. The chained rule is then checking the existence of the # Content-Type header. The RFCs do not state there must be a # Content-Type header. However, a request missing a Content-Header is a # strong indication of a non-compliant browser. # # Also, omitting the CT header allows to bypass the Request Body Processor # unless you set the optional tx.enforce_bodyproc_urlencoded variable. # # Note: in default settings, this behavior only provides a NOTICE and will # not cause a request to be blocked. However, in paranoia level 2 or # higher, we run sibling 920341, which DOES block these requests. # # -=[ References ]=- # http://httpwg.org/specs/rfc7231.html#header.content-type SecRule REQUEST_HEADERS:Content-Length "!@rx ^0$" \ "id:920340,\ phase:1,\ pass,\ t:none,\ msg:'Request Containing Content, but Missing Content-Type header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'NOTICE',\ chain" SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'" # Check that the host header is not an IP address # This is not an HTTP RFC violation but it is indicative of automated client access. # Many web-based worms propagate by scanning IP address blocks. # # -=[ Rule Logic ]=- # This rule triggers if the Host header contains an IPv4 or IPv6 address, optionally # extended with a port number. In the case of IPv6 we covering the address with square # brackets and the address without square brackets. # # The regex consists of three main parts and said optional group: # # * IPv4 address # * IPv6 address with square brackets # * IPv6 address without square brackets # * optional colon and port number # # Please note that the regex does not test the validity of the IP addresses. # It just tries to detect a potential IP address. # # -=[ References ]=- # https://technet.microsoft.com/en-us/magazine/2005.01.hackerbasher.aspx # SecRule REQUEST_HEADERS:Host "@rx (?:^([\d.]+|\[[\da-f:]+\]|[\da-f:]+)(:[\d]+)?$)" \ "id:920350,\ phase:1,\ block,\ t:none,\ msg:'Host header is a numeric IP address',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'" # In most cases, you should expect a certain volume of each a request on your # website. For example, a request with 400 arguments, can be suspicious. # This file creates limitations on the request. # # TODO Look at the rules in this file, and define the sizes you'd like to enforce. # Note that most of the rules are commented out by default. # Uncomment the rules you need # # # Maximum number of arguments in request limited # SecRule &TX:MAX_NUM_ARGS "@eq 1" \ "id:920380,\ phase:2,\ block,\ t:none,\ msg:'Too many arguments in request',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule &ARGS "@gt %{tx.max_num_args}" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" ## -- Arguments limits -- # # Limit argument name length # SecRule &TX:ARG_NAME_LENGTH "@eq 1" \ "id:920360,\ phase:2,\ block,\ t:none,\ msg:'Argument name too long',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule ARGS_NAMES "@gt %{tx.arg_name_length}" \ "t:none,t:length,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Limit argument value length # # This rule is also triggered by an Apache Struts Remote Code Execution exploit: # [ Apache Struts vulnerability CVE-2017-9791 - Exploit tested: https://www.exploit-db.com/exploits/42324 ] # SecRule &TX:ARG_LENGTH "@eq 1" \ "id:920370,\ phase:2,\ block,\ t:none,\ msg:'Argument value too long',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule ARGS "@gt %{tx.arg_length}" \ "t:none,t:length,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Limit arguments total length # SecRule &TX:TOTAL_ARG_LENGTH "@eq 1" \ "id:920390,\ phase:2,\ block,\ t:none,\ msg:'Total arguments size exceeded',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule ARGS_COMBINED_SIZE "@gt %{tx.total_arg_length}" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # -- File upload limits -- # # Individual file size is limited SecRule &TX:MAX_FILE_SIZE "@eq 1" \ "id:920400,\ phase:1,\ block,\ t:none,\ msg:'Uploaded file size too large',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule REQUEST_HEADERS:Content-Type "@rx ^(?i)multipart/form-data" \ "chain" SecRule REQUEST_HEADERS:Content-Length "@gt %{tx.max_file_size}" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Combined file size is limited # SecRule &TX:COMBINED_FILE_SIZES "@eq 1" \ "id:920410,\ phase:2,\ block,\ t:none,\ msg:'Total uploaded files size too large',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule FILES_COMBINED_SIZE "@gt %{tx.combined_file_sizes}" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restrict which content-types we accept. # # Restrict Content-Type header to established patterns. # # This provides generic allow list protection against vulnerabilities like # Apache Struts Content-Type arbitrary command execution (CVE-2017-5638). # # Examples of allowed patterns: # - text/plain # - text/plain; charset="UTF-8" # - multipart/form-data; boundary=----WebKitFormBoundary12345 # - application/soap+xml; charset=utf-8; action="urn:localhost-hwh#getQuestions" # - application/*+json SecRule REQUEST_HEADERS:Content-Type "!@rx ^[\w/.+*-]+(?:\s?;\s?(?:action|boundary|charset|component|start(?:-info)?|type|version)\s?=\s?['\"\w.()+,/:=?<>@#*-]+)*$" \ "id:920470,\ phase:1,\ block,\ t:none,t:lowercase,\ msg:'Illegal Content-Type header',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # In case Content-Type header can be parsed, check the mime-type against # the policy defined in the 'allowed_request_content_type' variable. # To change your policy, edit crs-setup.conf and activate rule 900220. SecRule REQUEST_HEADERS:Content-Type "@rx ^[^;\s]+" \ "id:920420,\ phase:1,\ block,\ capture,\ t:none,\ msg:'Request content type is not allowed by policy',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.content_type=|%{tx.0}|',\ chain" SecRule TX:content_type "!@within %{tx.allowed_request_content_type}" \ "t:lowercase,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restrict charset parameter within the content-type header # SecRule REQUEST_HEADERS:Content-Type "@rx charset\s*=\s*[\"']?([^;\"'\s]+)" \ "id:920480,\ phase:1,\ block,\ capture,\ t:none,\ msg:'Request content type charset is not allowed by policy',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.content_type_charset=|%{tx.1}|',\ chain" SecRule TX:content_type_charset "!@within %{tx.allowed_request_content_type_charset}" \ "t:lowercase,\ ctl:forceRequestBodyVariable=On,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restrict charset parameter inside content type header to occur max once. # SecRule REQUEST_HEADERS:Content-Type "@rx charset.*?charset" \ "id:920530,\ phase:1,\ block,\ t:none,t:lowercase,\ msg:'Multiple charsets detected in content type header',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restrict protocol versions. # SecRule REQUEST_PROTOCOL "!@within %{tx.allowed_http_versions}" \ "id:920430,\ phase:1,\ block,\ t:none,\ msg:'HTTP protocol version is not allowed by policy',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restrict file extension # SecRule REQUEST_BASENAME "@rx \.([^.]+)$" \ "id:920440,\ phase:1,\ block,\ capture,\ t:none,t:urlDecodeUni,\ msg:'URL file extension is restricted by policy',\ logdata:'%{TX.0}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.extension=.%{tx.1}/',\ chain" SecRule TX:EXTENSION "@within %{tx.restricted_extensions}" \ "t:none,t:lowercase,\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Backup or "working" file extension # example: index.php~, /index.php~/foo/ # SecRule REQUEST_FILENAME "@rx \.[^.~]+~(?:/.*|)$" \ "id:920500,\ phase:1,\ block,\ t:none,t:urlDecodeUni,\ msg:'Attempt to access a backup or working file',\ logdata:'%{TX.0}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restricted HTTP headers # # -=[ Rule Logic ]=- # The use of certain headers is restricted. They are listed in two variables: # - TX.restricted_headers_basic: Known security risks, always forbidden (rule # 920450) # - TX.restricted_headers_extended: Possible false positives, possible security # risks, may be forbidden (rule 920451) # # The headers are transformed into lowercase before the match. In order to make # sure that only complete header names match, the names in the # TX.restricted_headers_* variables are wrapped in slashes. This guarantees that # the Range header (which becomes /range/) will not match the restricted # /content-range/ header, for example. # # This is a chained rule, where the first rule fills a set of variables of the # form TX.header_name_<RULE_ID>_<HEADER_NAME>. The second rule is then executed # for all variables of the form TX.header_name_<RULE_ID>_<HEADER_NAME>. # # As a consequence of the construction of the rule, the alert message and the # alert data will not display the original header name Content-Range, but # /content-range/ instead. # # This rule has a stricter sibling, 920451, which matches against the variable # TX.restricted_headers_extended. It handles deprecated headers that are still # in use (so false positives are possible, hence unsuitable for blocking in a # default paranoia level 1 installation) and headers with possible security # risks. # # -=[ References ]=- # https://access.redhat.com/security/vulnerabilities/httpoxy (Header Proxy) # https://www.sidechannel.blog/en/http-method-override-what-it-is-and-how-a-pentester-can-use-it # SecRule REQUEST_HEADERS_NAMES "@rx ^.*$" \ "id:920450,\ phase:1,\ block,\ capture,\ t:none,t:lowercase,\ msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\ logdata:'Restricted header detected: %{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.header_name_920450_%{tx.0}=/%{tx.0}/',\ chain" SecRule TX:/^header_name_920450_/ "@within %{tx.restricted_headers_basic}" \ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Rule against CVE-2022-21907 # This rule blocks Accept-Encoding headers longer than 100 characters. # The length of 100 is a heuristic based on the length of values from # the RFC (https://datatracker.ietf.org/doc/rfc9110/) # and the respective values assigned by IANA # (https://www.iana.org/assignments/http-parameters/http-parameters.xml#content-coding). # Concatenating all valid values for Accept-Encoding (without q=0.5) resulted in a value of 93: # aes128gcm, br, compress, deflate, exi, gzip, identity, pack200-gzip, x-compress, x-gzip, zstd # # This rule has a stricter sibling: 920521 # SecRule REQUEST_HEADERS:Accept-Encoding "@gt 100" \ "id:920520,\ phase:1,\ block,\ t:none,t:lowercase,t:length,\ msg:'Accept-Encoding header exceeded sensible length',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Restrict response charsets that we allow. # The following rules make sure that the response will be in an ASCII-compatible charset that # phase 4 rules can properly understand and block. # # # Some servers rely on the request Accept header to determine what charset to respond with. # This rule restricts these to familiar charsets. # # Regular expression generated from regex-assembly/920600.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920600 # SecRule REQUEST_HEADERS:Accept "!@rx ^(?:(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)/(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)|\*)(?:[\s\x0b]*;[\s\x0b]*(?:charset[\s\x0b]*=[\s\x0b]*\"?(?:iso-8859-15?|utf-8|windows-1252)\b\"?|(?:[^\s\x0b-\"\(\),/:-\?\[-\]c\{\}]|c(?:[^!\"\(\),/:-\?\[-\]h\{\}]|h(?:[^!\"\(\),/:-\?\[-\]a\{\}]|a(?:[^!\"\(\),/:-\?\[-\]r\{\}]|r(?:[^!\"\(\),/:-\?\[-\]s\{\}]|s(?:[^!\"\(\),/:-\?\[-\]e\{\}]|e[^!\"\(\),/:-\?\[-\]t\{\}]))))))[^!\"\(\),/:-\?\[-\]\{\}]*[\s\x0b]*=[\s\x0b]*[^!\(\),/:-\?\[-\]\{\}]+);?)*(?:[\s\x0b]*,[\s\x0b]*(?:(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)/(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)|\*)(?:[\s\x0b]*;[\s\x0b]*(?:charset[\s\x0b]*=[\s\x0b]*\"?(?:iso-8859-15?|utf-8|windows-1252)\b\"?|(?:[^\s\x0b-\"\(\),/:-\?\[-\]c\{\}]|c(?:[^!\"\(\),/:-\?\[-\]h\{\}]|h(?:[^!\"\(\),/:-\?\[-\]a\{\}]|a(?:[^!\"\(\),/:-\?\[-\]r\{\}]|r(?:[^!\"\(\),/:-\?\[-\]s\{\}]|s(?:[^!\"\(\),/:-\?\[-\]e\{\}]|e[^!\"\(\),/:-\?\[-\]t\{\}]))))))[^!\"\(\),/:-\?\[-\]\{\}]*[\s\x0b]*=[\s\x0b]*[^!\(\),/:-\?\[-\]\{\}]+);?)*)*$" \ "id:920600,\ phase:1,\ block,\ t:none,t:lowercase,\ msg:'Illegal Accept header: charset parameter',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Unicode character bypass check for non JSON requests # See reported bypass in issue: # https://github.com/coreruleset/coreruleset/issues/2512 # SecRule REQBODY_PROCESSOR "!@streq JSON" \ "id:920540,\ phase:2,\ block,\ t:none,\ msg:'Possible Unicode character bypass detected',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267/72',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@rx (?i)\x5cu[0-9a-f]{4}" \ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # Disallow any raw URL fragments. The '#' character should be omitted or URL-encoded. # CRS rules generally do not check REQUEST_URI_RAW, but some servers accept the fragment as part of the URL path/query. # This creates false negative evasions. # SecRule REQUEST_URI_RAW "@contains #" \ "id:920610,\ phase:1,\ block,\ t:none,\ msg:'Raw (unencoded) fragment in request URI',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" # # The following rule (920620) checks for the presence of 2 or more request Content-Type headers. # Content-Type confusion poses a significant security risk to a web application. It occurs when # the server and client have different interpretations of the Content-Type header, leading to # miscommunication, potential exploitation and WAF bypass. # # Using Apache, when multiple Content-Type request headers are received, the server combines them # into a single header with the values separated by commas. For example, if a client sends multiple # Content-Type headers with values "application/json" and "text/plain", Apache will combine them # into a single header like this: "Content-Type: application/json, text/plain". # # On the other hand, Nginx handles multiple Content-Type headers differently. It preserves each # header as a separate entity without combining them. So, if a client sends multiple Content-Type # headers, Nginx will keep them separate, maintaining the original values. # SecRule &REQUEST_HEADERS:Content-Type "@gt 1" \ "id:920620,\ phase:1,\ block,\ t:none,\ msg:'Multiple Content-Type Request Headers',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/1',\ tag:'OWASP_CRS',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 2" "id:920013,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 2" "id:920014,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 2 =- (apply only when tx.detection_paranoia_level is sufficiently high: 2 or higher) # # # -=[ Rule Logic ]=- # # Check the number of range fields in the Range request header. # # An excessive number of Range request headers can be used to DoS a server. # The original CVE proposed an arbitrary upper limit of 5 range fields. # # Several clients are known to request PDF fields with up to 62 range # fields. Therefore the standard rule does not cover PDF files. This is # performed in two separate (stricter) siblings of this rule. # # 920200: PL2: Limit of 5 range header fields for all filenames outside of PDFs # 920201: PL2: Limit of 62 range header fields for PDFs # 920202: PL4: Limit of 5 range header fields for PDFs # # -=[ References ]=- # https://httpd.apache.org/security/CVE-2011-3192.txt SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx ^bytes=(?:(?:\d+)?-(?:\d+)?\s*,?\s*){6}" \ "id:920200,\ phase:1,\ block,\ t:none,\ msg:'Range: Too many fields (6 or more)',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule REQUEST_BASENAME "!@endsWith .pdf" \ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'" # # This is a sibling of rule 920200 # SecRule REQUEST_BASENAME "@endsWith .pdf" \ "id:920201,\ phase:1,\ block,\ t:none,t:urlDecodeUni,\ msg:'Range: Too many fields for pdf request (63 or more)',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx ^bytes=(?:(?:\d+)?-(?:\d+)?\s*,?\s*){63}" \ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'" SecRule ARGS "@rx %[0-9a-fA-F]{2}" \ "id:920230,\ phase:2,\ block,\ t:none,\ msg:'Multiple URL Encoding Detected',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267/120',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'" # # PL2: This is a stricter sibling of 920270. # SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 9,10,13,32-126,128-255" \ "id:920271,\ phase:2,\ block,\ t:none,t:urlDecodeUni,\ msg:'Invalid character in request (non printable characters)',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'" # # Missing User-Agent Header # # -=[ Rule Logic ]=- # This rules will check to see if there is a User-Agent header or not. # SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \ "id:920320,\ phase:1,\ pass,\ t:none,\ msg:'Missing User Agent Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'NOTICE',\ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.notice_anomaly_score}'" # # PL2: This is a stricter sibling of 920120. # SecRule FILES_NAMES|FILES "@rx ['\";=\x5c]" \ "id:920121,\ phase:2,\ block,\ t:none,t:urlDecodeUni,\ msg:'Attempted multipart/form-data bypass',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'" # # PL2: Block on Missing Content-Type Header with Request Body # This is a stricter sibling of rule 920340. # # -=[ References ]=- # http://httpwg.org/specs/rfc7231.html#header.content-type SecRule REQUEST_HEADERS:Content-Length "!@rx ^0$" \ "id:920341,\ phase:1,\ block,\ t:none,\ msg:'Request Containing Content Requires Content-Type header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'" # # PL2: This is a stricter sibling of 920450. # SecRule REQUEST_HEADERS_NAMES "@rx ^.*$" \ "id:920451,\ phase:1,\ block,\ capture,\ t:none,t:lowercase,\ msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\ logdata:'Restricted header detected: %{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.header_name_920451_%{tx.0}=/%{tx.0}/',\ chain" SecRule TX:/^header_name_920451_/ "@within %{tx.restricted_headers_extended}" \ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'" # # Check URL encodings # # See comment on rule 920220. # SecRule REQUEST_HEADERS:Content-Type "@rx ^(?i)application/x-www-form-urlencoded" \ "id:920240,\ phase:2,\ block,\ t:none,\ msg:'URL Encoding Abuse Attack Attempt',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/2',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153/267/72',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule REQUEST_BODY "@rx \x25" \ "chain" SecRule REQUEST_BODY "@validateUrlEncoding" \ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 3" "id:920015,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 3" "id:920016,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 3 =- (apply only when tx.detection_paranoia_level is sufficiently high: 3 or higher) # # # PL 3: This is a stricter sibling of 920270. Ascii range: Printable characters in the low range # # This rule is also triggered by the following exploit(s): # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] # SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 32-36,38-126" \ "id:920272,\ phase:2,\ block,\ t:none,t:urlDecodeUni,\ msg:'Invalid character in request (outside of printable chars below ascii 127)',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/3',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'" # # Missing Accept Header # # This rule has been moved to PL3 # # -=[ Rule Logic ]=- # This rule generates a notice if the Accept header is missing. # RFC 7231 does not enforce the use of the Accept header. # It is just typical browser behavior to send and it can indicate a malicious client. # # Notice: The rule tries to avoid known false positives by ignoring # OPTIONS requests, CONNECT requests, and requests coming from known # offending User-Agents via two chained rules. # As ModSecurity only reports the match of the last matching rule, # the alert is misleading. # SecRule &REQUEST_HEADERS:Accept "@eq 0" \ "id:920300,\ phase:1,\ pass,\ t:none,\ msg:'Request Missing an Accept Header',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/3',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ tag:'PCI/6.5.10',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'NOTICE',\ chain" SecRule REQUEST_METHOD "!@rx ^(?:OPTIONS|CONNECT)$" \ "chain" SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.notice_anomaly_score}'" # # PL3: The little known x-up-devcap-post-charset request header can be used to submit # a request with a different encoding as an alternative to the charset parameter in # the Content-Type header. This can be used to circumvent charset restrictions on # the Content-Type header in ASP.NET. # Note that this only works in combination with a User-Agent prefix. # # This rule is based on a blog post by Soroush Dalili at # https://soroush.me/blog/2019/05/x-up-devcap-post-charset-header-in-aspnet-to-bypass-wafs-again/ # SecRule &REQUEST_HEADERS:x-up-devcap-post-charset "@ge 1" \ "id:920490,\ phase:1,\ block,\ t:none,\ msg:'Request header x-up-devcap-post-charset detected in combination with prefix \'UP\' to User-Agent',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'language-aspnet',\ tag:'platform-windows',\ tag:'attack-protocol',\ tag:'paranoia-level/3',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule REQUEST_HEADERS:User-Agent "@rx ^(?i)up" \ "t:none,\ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'" # # Cache-Control Request Header allow list # # -=[ Rule Logic ]=- # This rule aims to strictly allow list the Cache-Control request header # values and to blocks all violations. This should be useful to intercept # "bad bot" and tools that impersonate a real browser but with wrong request # header setup. # # The regular expression used on this rule tries to match multiple directives # in a single value, for example: "max-stale=1, max-age=2". This leads us to # use a regular expression that accepts a trailing comma to keep compatibility # with all regex engines and not PCRE only. For example: "max-stale=1, max-age=2, " # # Moreover, this regular expression allows duplicate directives sequence like: # "max-stale, max-stale=1, no-cache, no-cache". # # Standard Cache-Control directives that can be used by the client: # - max-age=<seconds> # - max-stale[=<seconds>] # - min-fresh=<seconds> # - no-cache # - no-store # - no-transform # - only-if-cached # # References: # - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control # - https://regex101.com/r/CZ0Hxu/22 # SecRule &REQUEST_HEADERS:Cache-Control "@gt 0" \ "id:920510,\ phase:1,\ block,\ t:none,\ msg:'Invalid Cache-Control request header',\ logdata:'Invalid Cache-Control value in request found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'header-allowlist',\ tag:'paranoia-level/3',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ chain" SecRule REQUEST_HEADERS:Cache-Control "!@rx ^(?:(?:max-age=[0-9]+|min-fresh=[0-9]+|no-cache|no-store|no-transform|only-if-cached|max-stale(?:=[0-9]+)?)(?:\s*\,\s*|$)){1,7}$" \ "setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'" # # This rule checks for valid Accept-Encoding headers # # This rule has a less strict sibling: 920520 # # Regular expression generated from regex-assembly/920521.ra. # To update the regular expression run the following shell script # (consult https://coreruleset.org/docs/development/regex_assembly/ for details): # crs-toolchain regex update 920521 # SecRule REQUEST_HEADERS:Accept-Encoding "!@rx br|compress|deflate|(?:pack200-)?gzip|identity|\*|^$|aes128gcm|exi|zstd|x-(?:compress|gzip)" \ "id:920521,\ phase:1,\ block,\ t:none,t:lowercase,\ msg:'Illegal Accept-Encoding header',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/3',\ tag:'OWASP_CRS',\ tag:'capec/1000/255/153',\ tag:'PCI/12.1',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 4" "id:920017,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 4" "id:920018,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.7.0-dev',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 4 =- (apply only when tx.detection_paranoia_level is sufficiently high: 4 or higher) # # # This is a stricter sibling of rule 920200 # SecRule REQUEST_BASENAME "@endsWith .pdf" \ "id:920202,\ phase:1,\ block,\ t:none,t:urlDecodeUni,\ msg:'Range: Too many fields for pdf request (6 or more)',\ logdata:'%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/4',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'WARNING',\ chain" SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx ^bytes=(?:(?:\d+)?-(?:\d+)?\s*,?\s*){6}" \ "setvar:'tx.inbound_anomaly_score_pl4=+%{tx.warning_anomaly_score}'" # # This is a stricter sibling of 920270. # # This rule is also triggered by the following exploit(s): # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] # SecRule ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 38,44-46,48-58,61,65-90,95,97-122" \ "id:920273,\ phase:2,\ block,\ t:none,t:urlDecodeUni,\ msg:'Invalid character in request (outside of very strict set)',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/4',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'" # # This is a stricter sibling of 920270. # SecRule REQUEST_HEADERS|!REQUEST_HEADERS:User-Agent|!REQUEST_HEADERS:Referer|!REQUEST_HEADERS:Cookie|!REQUEST_HEADERS:Sec-Fetch-User|!REQUEST_HEADERS:Sec-CH-UA|!REQUEST_HEADERS:Sec-CH-UA-Mobile "@validateByteRange 32,34,38,42-59,61,65-90,95,97-122" \ "id:920274,\ phase:1,\ block,\ t:none,t:urlDecodeUni,\ msg:'Invalid character in request headers (outside of very strict set)',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/4',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'" # # This is a stricter sibling of 920270. # The headers of this rule are Structured Header booleans, for which only `?0`, # and `?1` are inconspicuous. # Structured Header boolean: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-header-structure-19#section-3.3.6 # Sec-Fetch-User: https://www.w3.org/TR/fetch-metadata/#http-headerdef-sec-fetch-user # Sec-CH-UA-Mobile: https://wicg.github.io/ua-client-hints/#sec-ch-ua-mobile # SecRule REQUEST_HEADERS:Sec-Fetch-User|REQUEST_HEADERS:Sec-CH-UA-Mobile "!@rx ^(?:\?[01])?$" \ "id:920275,\ phase:1,\ block,\ t:none,t:urlDecodeUni,\ msg:'Invalid character in request headers (outside of very strict set)',\ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/4',\ tag:'OWASP_CRS',\ tag:'capec/1000/210/272',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'" # -=[ Abnormal Character Escapes ]=- # # [ Rule Logic ] # Consider the following payload: arg=cat+/e\tc/pa\ssw\d # Here, \s and \d were only used to obfuscate the string passwd and a lot of # parsers will silently ignore the non-necessary escapes. The case with \t is # a bit different though, as \t is a natural escape for the TAB character, # so we will avoid this (and \n, \r, etc.). # # This rule aims to detect non-necessary, abnormal escapes. You could say it is # a nice way to forbid the backslash character where it is not needed. # # This is a new rule at paranoia level 4. We expect quite a few false positives # for this rule and we will later evaluate if the rule makes any sense at all. # The rule is redundant with 920273 and 920274 in PL4. But if the rule proofs # to be useful and false positives remain at a reasonable level, then it might # be shifted to PL3 in a future release, where it would be the only rule # covering the backslash escape. # # We forbid backslashes followed by a list of basic ascii characters - unless # the backslash is preceded by another backslash. # # This rule is also triggered by the following exploit(s): # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] # SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@rx (?:^|[^\x5c])\x5c[cdeghijklmpqwxyz123456789]" \ "id:920460,\ phase:2,\ block,\ capture,\ t:none,t:htmlEntityDecode,t:lowercase,\ msg:'Abnormal character escapes in request',\ logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/4',\ tag:'OWASP_CRS',\ tag:'capec/1000/153/267',\ ver:'OWASP_CRS/4.7.0-dev',\ severity:'CRITICAL',\ setvar:'tx.http_violation_score=+%{tx.critical_anomaly_score}',\ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'" # # -= Paranoia Levels Finished =- # SecMarker "END-REQUEST-920-PROTOCOL-ENFORCEMENT"