# ---------------------------------------------------------------
# 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}"

