D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
bitninja-waf
/
etc
/
crs
/
rules
/
Filename :
REQUEST-920-PROTOCOL-ENFORCEMENT.conf
back
Copy
# ------------------------------------------------------------------------ # OWASP ModSecurity Core Rule Set ver.3.0.2 # Copyright (c) 2006-2016 Trustwave and contributors. All rights reserved. # # The OWASP ModSecurity Core Rule Set 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. # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html # # -= Paranoia Level 0 (empty) =- (apply unconditionally) # SecRule TX:PARANOIA_LEVEL "@lt 1" "phase:1,id:920011,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:PARANOIA_LEVEL "@lt 1" "phase:2,id:920012,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 1 (default) =- (apply only when tx.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:" "//" host [ ":" port ] [ abs_path [ "?" query ]] # # It also outlines proper construction for CONNECT, OPTIONS and GET requests. # # -=[ References ]=- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.1 # http://capec.mitre.org/data/definitions/272.html # SecRule REQUEST_LINE "!^(?i:(?:[a-z]{3,10}\s+(?:\w{3,7}?://[\w\-\./]*(?::\d+)?)?/[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?|connect (?:\d{1,3}\.){3}\d{1,3}\.?(?::\d+)?|options \*)\s+[\w\./]+|get /[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?)$"\ "msg:'Invalid HTTP Request Line',\ severity:'WARNING',\ id:920100,\ ver:'OWASP_CRS/3.0.0',\ rev:'2',\ maturity:'9',\ accuracy:'9',\ logdata:'%{request_line}',\ phase:request,\ block,\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\ tag:'CAPEC-272',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'" # # 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 file or file name variables. # HTML entities may lead to false positives, why they are allowed on PL1. # Negative look behind assertions allow frequently used entities &_; # # -=[ Targets, characters and html entities ]=- # # 920120: PL1 : FILES_NAMES, FILES # ['\";=] but allowed: # &[aAoOuUyY]uml); &[aAeEiIoOuU]circ; &[eEiIoOuUyY]acute; # &[aAeEiIoOuU]grave; &[cC]cedil; &[aAnNoO]tilde; & ' # # 920121: PL2 : FILES_NAMES, FILES # ['\";=] : ' " ; = meta-characters # # -=[ References ]=- # https://www.owasp.org/index.php/ModSecurity_CRS_RuleID-960000 # http://www.ietf.org/rfc/rfc2183.txt # SecRule FILES_NAMES|FILES "(?<!&(?:[aAoOuUyY]uml)|&(?:[aAeEiIoOuU]circ)|&(?:[eEiIoOuUyY]acute)|&(?:[aAeEiIoOuU]grave)|&(?:[cC]cedil)|&(?:[aAnNoO]tilde)|&(?:amp)|&(?:apos));|['\"=]" \ "msg:'Attempted multipart/form-data bypass',\ severity:'CRITICAL',\ id:920120,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'9',\ accuracy:'7',\ logdata:'%{matched_var}',\ phase:request,\ block,\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\ tag:'CAPEC-272',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'" # # Verify that we've correctly processed the request body. # # As a rule of thumb, when failing to process a request body # you should reject the request (when deployed in blocking mode) # or log a high-severity alert (when deployed in detection-only mode). # # -=[ Rule Logic ]=- # Checks for the existence of the REQBODY_ERROR variable that is created # by the request body processor if it encounters errors. # # -=[ References ]=- # https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#REQBODY_ERROR # SecRule REQBODY_ERROR "!@eq 0" \ "msg:'Failed to parse request body.',\ severity:'CRITICAL',\ id:920130,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'9',\ accuracy:'9',\ logdata:'%{REQBODY_ERROR_MSG}',\ phase:request,\ block,\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\ tag:'CAPEC-272',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'" # # Strict Multipart Parsing Checks # # -=[ Rule Logic ]=- # By default be strict with what we accept in the multipart/form-data # request body. If the rule below proves to be too strict for your # environment consider changing it to detection-only. You are encouraged # _not_ to remove it altogether. # # -=[ References ]=- # https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#MULTIPART_STRICT_ERROR # SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ "msg:'Multipart request body failed strict validation:\ PE %{REQBODY_PROCESSOR_ERROR},\ BQ %{MULTIPART_BOUNDARY_QUOTED},\ BW %{MULTIPART_BOUNDARY_WHITESPACE},\ DB %{MULTIPART_DATA_BEFORE},\ DA %{MULTIPART_DATA_AFTER},\ HF %{MULTIPART_HEADER_FOLDING},\ LF %{MULTIPART_LF_LINE},\ SM %{MULTIPART_SEMICOLON_MISSING},\ IQ %{MULTIPART_INVALID_QUOTING},\ IH %{MULTIPART_INVALID_HEADER_FOLDING},\ FLE %{MULTIPART_FILE_LIMIT_EXCEEDED}',\ severity:'CRITICAL',\ id:920140,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'8',\ accuracy:'7',\ phase:request,\ block,\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\ tag:'CAPEC-272',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'" # # 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 ]=- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13 # SecRule REQUEST_HEADERS:Content-Length "!^\d+$" \ "msg:'Content-Length HTTP header is not numeric.',\ severity:'CRITICAL',\ id:920160,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'9',\ accuracy:'9',\ phase:1,\ block,\ logdata:'%{matched_var}',\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ tag:'CAPEC-272',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}'" # # Do not accept GET or HEAD requests with bodies # HTTP standard allows GET requests to have a body but this # feature is not used in real life. Attackers could try to force # a request body on an unsuspecting web applications. # # -=[ Rule Logic ]=- # This is a chained rule that first checks the Request Method. If it is a # GET or HEAD method, then it checks for the existence of a Content-Length # header. If the header exists and its payload is either not a 0 digit or not # empty, then it will match. # # -=[ References ]=- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 # SecRule REQUEST_METHOD "^(?:GET|HEAD)$" \ "msg:'GET or HEAD Request with Body Content.',\ severity:'CRITICAL',\ id:920170,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'9',\ accuracy:'9',\ phase:request,\ block,\ logdata:'%{matched_var}',\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ tag:'CAPEC-272',\ chain" SecRule REQUEST_HEADERS:Content-Length "!^0?$"\ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}'" # # Require Content-Length to be provided with every POST request. # # -=[ Rule Logic ]=- # This chained rule checks if the request method is POST, if so, it checks that a Content-Length # header is also present. # # -=[ References ]=- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5 # SecRule REQUEST_METHOD "^POST$" \ "msg:'POST request missing Content-Length Header.',\ severity:'WARNING',\ id:920180,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'9',\ accuracy:'9',\ phase:request,\ block,\ logdata:'%{matched_var}',\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ tag:'CAPEC-272',\ chain" SecRule &REQUEST_HEADERS:Content-Length "@eq 0" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}'" # # Range Header Checks # # 1. Range Header exists and begins with 0 - normal browsers don't do this. # Automated programs and bots often do not obey the HTTP RFC # # -=[ Rule Logic ]=- # This rule inspects the Range request header to see if it starts with 0. # # -=[ References ]=- # http://www.bad-behavior.ioerror.us/documentation/how-it-works/ # # 2. Per RFC 2616 - # "If the last-byte-pos value is present, it MUST be greater than or equal to the first-byte-pos in that byte-range-spec, # or the byte- range-spec is syntactically invalid." # -=[ Rule Logic ]=- # This rule compares the first and second byte ranges and flags when the first value is greater than the second. # # -=[ References ]=- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html # http://seclists.org/fulldisclosure/2011/Aug/175 # SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "(\d+)\-(\d+)\," \ "capture,\ phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'Range: Invalid Last Byte Value.',\ logdata:'%{matched_var}',\ severity:'WARNING',\ id:920190,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ chain" SecRule TX:2 "!@ge %{tx.1}" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # Broken/Malicous 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 ]=- # http://www.bad-behavior.ioerror.us/documentation/how-it-works/ # SecRule REQUEST_HEADERS:Connection "\b(keep-alive|close),\s?(keep-alive|close)\b" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'Multiple/Conflicting Connection Header Data Found.',\ logdata:'%{matched_var}',\ id:920210,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ severity:'WARNING',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # 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 and REQUEST_BODY. For REQUEST_BODY, we only want to # run the @validateUrlEncoding operator if the content-type is application/x-www-form-urlencoding. # # -=[ References ]=- # http://www.ietf.org/rfc/rfc1738.txt # SecRule REQUEST_URI "\%((?!$|\W)|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'URL Encoding Abuse Attack Attempt',\ id:920220,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ severity:'WARNING',\ chain" SecRule REQUEST_URI "@validateUrlEncoding" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" SecRule REQUEST_HEADERS:Content-Type "^(application\/x-www-form-urlencoded|text\/xml)(?:;(?:\s?charset\s?=\s?[\w\d\-]{1,18})?)??$" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'URL Encoding Abuse Attack Attempt',\ id:920240,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ severity:'WARNING',\ chain" SecRule REQUEST_BODY|XML:/* "\%((?!$|\W)|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" "chain" SecRule REQUEST_BODY|XML:/* "@validateUrlEncoding" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # Check UTF enconding # 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" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'UTF8 Encoding Abuse Attack Attempt',\ id:920250,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ severity:'WARNING',\ chain" SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "@validateUtf8Encoding" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # Disallow use of full-width unicode as decoding evasions my 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 # SecRule REQUEST_URI|REQUEST_BODY "\%u[fF]{2}[0-9a-fA-F]{2}" \ "msg:'Unicode Full/Half Width Abuse Attack Attempt',\ id:920260,\ severity:'WARNING',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ phase:request,\ t:none,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-iis',\ tag:'platform-windows',\ tag:'attack-protocol',\ block,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # 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 and Cookie # 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. # # 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" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ block,\ msg:'Invalid character in request (null character)',\ id:920270,\ severity:'CRITICAL',\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.error_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # 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" \ "msg:'Request Missing a Host Header',\ severity:'WARNING',\ phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ t:none,\ pass,\ id:920280,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_HOST',\ tag:'WASCTC/WASC-21',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/6.5.10',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var},\ skipAfter:END_HOST_CHECK" SecRule REQUEST_HEADERS:Host "^$" \ "msg:'Empty Host Header',\ severity:'WARNING',\ phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ t:none,\ pass,\ id:920290,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_HOST',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" 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 "^$" \ "msg:'Request Has an Empty Accept Header',\ chain,\ phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'8',\ t:none,\ pass,\ severity:'NOTICE',\ id:920310,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT'" SecRule REQUEST_METHOD "!^OPTIONS$" \ "chain" SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android Business Enterprise Entreprise" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" # # This rule is a sibling of rule 920310. # SecRule REQUEST_HEADERS:Accept "^$" \ "msg:'Request Has an Empty Accept Header',\ chain,\ phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'8',\ t:none,\ pass,\ severity:'NOTICE',\ id:920311,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT'" SecRule REQUEST_METHOD "!^OPTIONS$" \ "chain" SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" # # 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 "^$" \ "msg:'Empty User Agent Header',\ severity:'NOTICE',\ phase:request,\ t:none,\ pass,\ id:920330,\ rev:'1',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EMPTY_HEADER_UA',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" # # 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. # # -=[ References ]=- # http://httpwg.org/specs/rfc7231.html#header.content-type SecRule REQUEST_HEADERS:Content-Length "!^0$" \ "msg:'Request Containing Content, but Missing Content-Type header',\ chain,\ phase:request,\ rev:'3',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ t:none,\ block,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ id:920340,\ severity:'NOTICE'" SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" # 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 all digits (and possible port) # # -=[ References ]=- # http://technet.microsoft.com/en-us/magazine/2005.01.hackerbasher.aspx # SecRule REQUEST_HEADERS:Host "^[\d.:]+$" \ "msg:'Host header is a numeric IP address',\ phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ t:none,\ block,\ logdata:'%{matched_var}',\ severity:'WARNING',\ id:920350,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST',\ tag:'WASCTC/WASC-21',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/6.5.10',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/IP_HOST-%{matched_var_name}=%{matched_var}" # 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" \ "chain,\ phase:request,\ t:none,\ block,\ msg:'Too many arguments in request',\ id:920380,\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/SIZE_LIMIT'" SecRule &ARGS "@gt %{tx.max_num_args}" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" ## -- Arguments limits -- # # Limit argument name length # SecRule &TX:ARG_NAME_LENGTH "@eq 1" \ "chain,\ phase:request,\ t:none,\ block,\ msg:'Argument name too long',\ id:920360,\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/SIZE_LIMIT'" SecRule ARGS_NAMES "@gt %{tx.arg_name_length}" \ "t:none,\ t:length,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" # # Limit argument value length # SecRule &TX:ARG_LENGTH "@eq 1" \ "chain,\ phase:request,\ t:none,\ block,\ msg:'Argument value too long',\ id:920370,\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/SIZE_LIMIT'" SecRule ARGS "@gt %{tx.arg_length}" \ "t:none,\ t:length,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" # # Limit arguments total length # SecRule &TX:TOTAL_ARG_LENGTH "@eq 1" \ "chain,\ phase:request,\ t:none,\ block,\ msg:'Total arguments size exceeded',\ id:920390,\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/SIZE_LIMIT'" SecRule ARGS_COMBINED_SIZE "@gt %{tx.total_arg_length}" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" # # -- File upload limits -- # # Individual file size is limited SecRule &TX:MAX_FILE_SIZE "@eq 1" \ "chain,\ phase:request,\ t:none,\ block,\ msg:'Uploaded file size too large',\ id:920400,\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/SIZE_LIMIT'" SecRule REQUEST_HEADERS:Content-Type "@beginsWith multipart/form-data" \ "chain" SecRule REQUEST_HEADERS:Content-Length "@gt %{tx.max_file_size}" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" # # Combined file size is limited # SecRule &TX:COMBINED_FILE_SIZES "@eq 1" \ "chain,\ phase:request,\ t:none,\ block,\ msg:'Total uploaded files size too large',\ id:920410,\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/SIZE_LIMIT'" SecRule FILES_COMBINED_SIZE "@gt %{tx.combined_file_sizes}" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" # # Restrict which content-types we accept. # SecRule REQUEST_METHOD "!^(?:GET|HEAD|PROPFIND|OPTIONS)$" \ "phase:request,\ chain,\ t:none,\ block,\ msg:'Request content type is not allowed by policy',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ id:920420,\ severity:'CRITICAL',\ logdata:'%{matched_var}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/ENCODING_NOT_ALLOWED',\ tag:'WASCTC/WASC-20',\ tag:'OWASP_TOP_10/A1',\ tag:'OWASP_AppSensor/EE2',\ tag:'PCI/12.1'" SecRule REQUEST_HEADERS:Content-Type "^([^;\s]+)" \ "chain,\ capture" SecRule TX:0 "!^%{tx.allowed_request_content_type}$" \ "t:none,\ ctl:forceRequestBodyVariable=On,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/CONTENT_TYPE_NOT_ALLOWED-%{matched_var_name}=%{matched_var}" # # Restrict protocol versions. # SecRule REQUEST_PROTOCOL "!@within %{tx.allowed_http_versions}" \ "phase:request,\ t:none,\ block,\ msg:'HTTP protocol version is not allowed by policy',\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ id:920430,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/PROTOCOL_NOT_ALLOWED',\ tag:'WASCTC/WASC-21',\ tag:'OWASP_TOP_10/A6',\ tag:'PCI/6.5.10',\ logdata:'%{matched_var}',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/PROTOCOL_NOT_ALLOWED-%{matched_var_name}=%{matched_var}" # # Restrict file extension # SecRule REQUEST_BASENAME "\.(.*)$" \ "chain,\ capture,\ phase:request,\ t:none,t:urlDecodeUni,t:lowercase,\ block,\ msg:'URL file extension is restricted by policy',\ severity:'CRITICAL',\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ id:920440,\ logdata:'%{TX.0}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/EXT_RESTRICTED',\ tag:'WASCTC/WASC-15',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/6.5.10',logdata:'%{TX.0}',\ setvar:tx.extension=.%{tx.1}/" SecRule TX:EXTENSION "@within %{tx.restricted_extensions}" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/POLICY/EXT_RESTRICTED-%{matched_var_name}=%{matched_var}" # # Restricted HTTP headers # # -=[ Rule Logic ]=- # The use of certain headers is restricted. They are listed in the variable # TX.restricted_headers. # # The headers are transformed into lowercase before the match. In order to # make sure that only complete header names are matching, the names in # TX.restricted_headers are wrapped in slashes. This guarantees that the # header Range (-> /range/) is not matching the restricted header # /content-range/ for example. # # This is a chained rule, where the first rule fills a set of variables of the # form TX.header_name_<HEADER_NAME>. The second rule is then executed for all # variables of the form TX.header_name_<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. # # # -=[ References ]=- # https://access.redhat.com/security/vulnerabilities/httpoxy (Header Proxy) # SecRule REQUEST_HEADERS_NAMES "@rx ^(.*)$" \ "msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\ severity:'CRITICAL',\ phase:request,\ t:none,\ block,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ id:920450,\ capture,\ logdata:' Restricted header detected: %{matched_var}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/POLICY/HEADER_RESTRICTED',\ tag:'WASCTC/WASC-21',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/12.1',\ tag:'WASCTC/WASC-15',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/12.1',\ t:lowercase,\ setvar:'tx.header_name_%{tx.0}=/%{tx.0}/',\ chain" SecRule TX:/^HEADER_NAME_/ "@within %{tx.restricted_headers}" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/POLICY/HEADERS_RESTRICTED-%{matched_var_name}=%{matched_var}'" SecRule TX:PARANOIA_LEVEL "@lt 2" "phase:1,id:920013,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:PARANOIA_LEVEL "@lt 2" "phase:2,id:920014,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 2 =- (apply only when tx.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 34 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 34 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 "^bytes=((\d+)?\-(\d+)?\s*,?\s*){6}" \ "phase:request,\ capture,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'Range: Too many fields (6 or more)',\ logdata:'%{matched_var}',\ severity:'WARNING',\ id:920200,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ tag:'paranoia-level/2',\ chain" SecRule REQUEST_BASENAME "!@endsWith .pdf" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # This is a sibling of rule 920200 # SecRule REQUEST_BASENAME "@endsWith .pdf" \ "phase:request,\ capture,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'Range: Too many fields for pdf request (35 or more)',\ logdata:'%{matched_var}',\ severity:'WARNING',\ id:920201,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ tag:'paranoia-level/2',\ chain" SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "^bytes=((\d+)?\-(\d+)?\s*,?\s*){35}" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" SecRule ARGS "\%((?!$|\W)|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'Multiple URL Encoding Detected',\ id:920230,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ tag:'paranoia-level/2',\ severity:'WARNING',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # Missing Accept Header # # -=[ Rule Logic ]=- # This rule generates a notice if the Accept header is missing. # SecRule &REQUEST_HEADERS:Accept "@eq 0" \ "msg:'Request Missing an Accept Header',\ chain,\ phase:request,\ rev:'3',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'8',\ t:none,\ pass,\ severity:'NOTICE',\ id:920300,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT',\ tag:'WASCTC/WASC-21',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/6.5.10',\ tag:'paranoia-level/2'" SecRule REQUEST_METHOD "!^OPTIONS$" \ "chain" SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android" \ "t:none,\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" # # PL2: This is a stricter sibling of 920270. # SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 9,10,13,32-126,128-255" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ block,\ msg:'Invalid character in request (non printable characters)',\ id:920271,\ severity:'CRITICAL',\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ tag:'paranoia-level/2',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # 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" \ "msg:'Missing User Agent Header',\ severity:'NOTICE',\ phase:request,\ rev:'1',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ t:none,\ pass,\ id:920320,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_UA',\ tag:'WASCTC/WASC-21',\ tag:'OWASP_TOP_10/A7',\ tag:'PCI/6.5.10',\ tag:'paranoia-level/2',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" # # PL2: This is a stricter sibling of 920120. # SecRule FILES_NAMES|FILES "['\";=]" \ "msg:'Attempted multipart/form-data bypass',\ severity:'CRITICAL',\ id:920121,\ ver:'OWASP_CRS/3.0.0',\ rev:'1',\ maturity:'9',\ accuracy:'7',\ logdata:'%{matched_var}',\ phase:request,\ block,\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\ tag:'CAPEC-272',\ tag:'paranoia-level/2',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'" SecRule TX:PARANOIA_LEVEL "@lt 3" "phase:1,id:920015,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:PARANOIA_LEVEL "@lt 3" "phase:2,id:920016,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 3 =- (apply only when tx.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 # SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 32-36,38-126" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ block,\ msg:'Invalid character in request (outside of printable chars below ascii 127)',\ id:920272,\ severity:'CRITICAL',\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ tag:'paranoia-level/3',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" SecRule TX:PARANOIA_LEVEL "@lt 4" "phase:1,id:920017,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" SecRule TX:PARANOIA_LEVEL "@lt 4" "phase:2,id:920018,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT" # # -= Paranoia Level 4 =- (apply only when tx.paranoia_level is sufficiently high: 4 or higher) # # # This is a stricter sibling of rule 920200 # SecRule REQUEST_BASENAME "@endsWith .pdf" \ "phase:request,\ capture,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'6',\ accuracy:'8',\ t:none,\ block,\ msg:'Range: Too many fields for pdf request (6 or more)',\ logdata:'%{matched_var}',\ severity:'WARNING',\ id:920202,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\ tag:'paranoia-level/4',\ chain" SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "^bytes=((\d+)?\-(\d+)?\s*,?\s*){6}" \ "setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # This is a stricter sibling of 920270. # SecRule ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 38,44-46,48-58,61,65-90,95,97-122" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ block,\ msg:'Invalid character in request (outside of very strict set)',\ id:920273,\ severity:'CRITICAL',\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ tag:'paranoia-level/4',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # This is a stricter sibling of 920270. # SecRule REQUEST_HEADERS|!REQUEST_HEADERS:User-Agent|!REQUEST_HEADERS:Referer|!REQUEST_HEADERS:Cookie "@validateByteRange 32,34,38,42-59,61,65-90,95,97-122" \ "phase:request,\ rev:'2',\ ver:'OWASP_CRS/3.0.0',\ maturity:'9',\ accuracy:'9',\ block,\ msg:'Invalid character in request headers (outside of very strict set)',\ id:920274,\ severity:'CRITICAL',\ t:none,t:urlDecodeUni,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\ tag:'paranoia-level/4',\ setvar:'tx.msg=%{rule.msg}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # -=[ 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 esacpes. 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. # # The rule construct is overly complex due to the fact that matching the # backslash character with \b did not work. \Q\\\E does match the backslash # character though. This is thus the base of the rule. We forbid the backslash # when followed by a list of basic ascii characters - unless the backslash # is preceded by another backslash character, which is being checked via a # negative look-behind construct. If that is the case, the backslash character # is allowed. # SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "(?<!\Q\\\E)\Q\\\E[cdeghijklmpqwxyz123456789]" \ "phase:request,\ id:920460,\ rev:'1',\ accuracy:'1',\ maturity:'1',\ ver:'OWASP_CRS/3.0.0',\ block,\ log,\ severity:'CRITICAL',\ capture,\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-protocol',\ tag:'paranoia-level/4',\ t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,\ ctl:auditLogParts=+E,\ logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ setvar:'tx.msg=%{rule.msg}',\ setvar:'tx.http_violation_score=+%{tx.critical_anomaly_score}',\ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\ setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/ABNORMAL-ESCAPE-%{matched_var_name}=%{matched_var}" # # -= Paranoia Levels Finished =- # SecMarker "END-REQUEST-920-PROTOCOL-ENFORCEMENT"