# --------------------------------------------------------------- # Core ModSecurity Rule Set ver.2.0.5 # Copyright (C) 2006-2010 Breach Security Inc. All rights reserved. # # The ModSecurity Core Rule Set is distributed under GPL version 2 # Please see the enclosed LICENCE 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 # # # 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 # SecRule REQUEST_LINE "!^(?:(?:[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]*)?)$" \ "t:none,t:lowercase,phase:2,rev:'2.0.5',pass,nolog,auditlog,msg:'Invalid HTTP Request Line',id:'960911',severity:'4',tag:'http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.1',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:'tx.%{rule.id}-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. # # -=[ References ]=- # http://www.ietf.org/rfc/rfc2183.txt # SecRule FILES_NAMES|FILES "['\";=]" "phase:2,id:'960000',rev:'2.0.5',pass,t:none,nolog,auditlog,capture,msg:'Attempted multipart/form-data bypass',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{tx.0}" # # 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+$" "phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'Content-Length HTTP header is not numeric', severity:'2',id:'960016',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',tag:'WASCTC/WASC-26',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',tag:'http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-POLICY/IP_HOST-%{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)$" "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'GET or HEAD requests with bodies', severity:'2',id:'960011',tag:'PROTOCOL_VIOLATION/EVASION',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',tag:'http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3'" SecRule REQUEST_HEADERS:Content-Length "!^0?$" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-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$" "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'POST request must have a Content-Length header',id:'960012',tag:'PROTOCOL_VIOLATION/EVASION',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'4',tag:'http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5'" SecRule &REQUEST_HEADERS:Content-Length "@eq 0" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # Deny inbound compressed content # identity The default (identity) encoding; the use of no transformation whatsoever. # This content-coding is used only in the Accept- Encoding header, and SHOULD NOT be # used in the Content-Encoding header. # # -=[ Rule Logic ]=- # This rule inspects the Content-Encoding request header to ensure that Identity # is not specified. # # -=[ References ]=- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html # SecRule REQUEST_HEADERS:Content-Encoding "!^Identity$" "phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'ModSecurity does not support content encodings',id:'960902',severity:'4',tag:'http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-POLICY/ENCODING_RESTRICTED-%{matched_var_name}=%{matched_var}" # # Expect header is an HTTP/1.1 protocol feature # Automated programs and bots often do not obey the HTTP RFC # # -=[ Rule Logic ]=- # This chained rule looks for the Expect request header, and if it is found then it # checks the HTTP protocol version supplied by the client. If it is version 1.0, the # rule matches. # # -=[ References ]=- # http://www.bad-behavior.ioerror.us/documentation/how-it-works/ # SecRule REQUEST_HEADERS:Expect "100-continue" "chain,phase:2,rev:'2.0.5',t:none,nolog,pass,auditlog,msg:'Expect Header Not Allowed.',severity:'5',id:'960021',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',tag:'http://www.bad-behavior.ioerror.us/documentation/how-it-works/'" SecRule REQUEST_PROTOCOL "@streq HTTP/1.0" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # Pragma Header requires a Cache-Control Header # Automated programs and bots often do not obey the HTTP RFC # # -=[ Rule Logic ]=- # This chained rule first checks for the existence of a Pragma request header. If it is found, # then it checks for a corresponding Cache-Control header (as the HTTP 1.1 RFC states clients should submit # one). If this is also missing, then it verifies the HTTP protocol version. If it is 1.1 then the rule # matches. # # -=[ References ]=- # http://www.bad-behavior.ioerror.us/documentation/how-it-works/ # SecRule &REQUEST_HEADERS:Pragma "@eq 1" "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'Pragma Header requires Cache-Control Header for HTTP/1.1 requests.',severity:'5',id:'960020',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',tag:'http://www.bad-behavior.ioerror.us/documentation/how-it-works/'" SecRule &REQUEST_HEADERS:Cache-Control "@eq 0" "chain" SecRule REQUEST_PROTOCOL "@streq HTTP/1.1" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" # # 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/ # SecRule REQUEST_HEADERS:Range "@contains =0-" "phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'Range: field exists and begins with 0.',severity:'5',id:'958291',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',tag:'http://www.bad-behavior.ioerror.us/documentation/how-it-works/',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-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:2,rev:'2.0.5',t:none,pass,nolog,auditlog,status:400,msg:'Multiple/Conflicting Connection Header Data Found.',id:'958295',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',tag:'http://www.bad-behavior.ioerror.us/documentation/how-it-works/',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-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})" \ "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,status:400,msg:'URL Encoding Abuse Attack Attempt',id:'950107',tag:'PROTOCOL_VIOLATION/EVASION',severity:'5'" SecRule REQUEST_URI "@validateUrlEncoding" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" SecRule REQUEST_HEADERS:Content-Type "^application\/x-www-form-urlencoded(?:;(?:\s?charset\s?=\s?[\w\d\-]{1,18})?)??$" \ "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,status:400,msg:'URL Encoding Abuse Attack Attempt',id:'950108',tag:'PROTOCOL_VIOLATION/EVASION',severity:'5'" SecRule REQUEST_BODY "\%(?!$|\W|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" "chain" SecRule REQUEST_BODY "@validateUrlEncoding" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-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 modsecurity_crs_10_config.conf file. # SecRule TX:CRS_VALIDATE_UTF8_ENCODING "@eq 1" "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'UTF8 Encoding Abuse Attack Attempt',id:'950801',tag:'PROTOCOL_VIOLATION/EVASION',tag:'WASCTC/WASC-20',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/EE2',tag:'PCI/6.5.2',severity:'5'" SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "@validateUtf8Encoding" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-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 following by 2 f characters # and then 2 hex characters. # # -=[ References ]=- # http://www.kb.cert.org/vuls/id/739224 # SecRule REQUEST_URI|REQUEST_BODY "\%u[fF]{2}[0-9a-fA-F]{2}" \ "t:none,phase:2,rev:'2.0.5',pass,nolog,auditlog,msg:'Unicode Full/Half Width Abuse Attack Attempt',id:'950116',severity:'5',setvar:'tx.msg=%{rule.msg}',tag:'http://www.kb.cert.org/vuls/id/739224',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" # # Proxy access attempt # NOTE Apache blocks such access by default if not set as a proxy. The rule is # included in case Apache proxy is misconfigured. # NOTE There are some clients (mobile devices) that will send a full URI even when connecting to # your local application and this rule allows it. # NOTE Need to have UseCononicalName On in Apache config to properly set the SERVER_NAME variable. # If you have set UseCononicalName, the you can uncomment this rule. # # -=[ Rule Logic ]=- # This chained rule first inspects the URI to see if a full domain name is specified. # If it is, then this data is compared against the Cononical SERVER_NAME. If it does # not match, then the client is making a request for an off-site location. # #SecRule REQUEST_URI_RAW ^\w+:/ "chain,phase:2,rev:'2.0.5',t:none,pass,nolog,auditlog,msg:'Proxy access attempt', severity:'2',id:'960014',tag:'PROTOCOL_VIOLATION/PROXY_ACCESS',tag:'WASCTC/WASC-14',tag:'OWASP_TOP_10/A6',tag:'PCI/6.5.10'" # SecRule MATCHED_VAR "!@beginsWith http://%{SERVER_NAME}" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/PROXY_ACCESS-%{matched_var_name}=%{matched_var}" # # Restrict type of characters sent # NOTE In order to be broad and support localized applications this rule # only validates that NULL Is not used. # # The strict policy version also validates that protocol and application # generated fields are limited to printable ASCII. # # -=[ Rule Logic ]=- # This rule uses the @validateByteRange operator to look for Nul Bytes. # If you set Paranoid Mode - it will check if your application use the range 32-126 for parameters. # # -=[ References ]=- # http://i-technica.com/whitestuff/asciichart.html # SecRule ARGS|ARGS_NAMES|REQUEST_HEADERS:Referer "@validateByteRange 1-255" \ "phase:2,rev:'2.0.5',pass,nolog,auditlog,msg:'Invalid character in request',id:'960901',tag:'PROTOCOL_VIOLATION/EVASION',tag:'WASCTC/WASC-28',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE3',tag:'PCI/6.5.2',severity:'4',t:none,t:urlDecodeUni,setvar:'tx.msg=%{rule.msg}',tag:'http://i-technica.com/whitestuff/asciichart.html',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" SecRule TX:PARANOID_MODE "@eq 1" "chain,phase:2,rev:'2.0.5',pass,nolog,auditlog,msg:'Invalid character in request',id:'960018',tag:'PROTOCOL_VIOLATION/EVASION',tag:'WASCTC/WASC-28',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE3',tag:'PCI/6.5.2',severity:'4',t:none,t:urlDecodeUni,tag:'http://i-technica.com/whitestuff/asciichart.html'" SecRule REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|!REQUEST_HEADERS:Referer \ "@validateByteRange 32-126" \ "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"