298 lines
9.6 KiB
Plaintext
298 lines
9.6 KiB
Plaintext
# ------------------------------------------------------------------------
|
|
# OWASP ModSecurity Core Rule Set ver.3.2.0
|
|
# Copyright (c) 2006-2019 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.
|
|
# ------------------------------------------------------------------------
|
|
|
|
#
|
|
# Anti-Automation rules to detect Denial of Service attacks.
|
|
#
|
|
# Description of mechanics:
|
|
# When a request hits a non-static resource (TX:STATIC_EXTENSIONS), then a counter for the IP
|
|
# address is being raised (IP:DOS_COUNTER). If the counter (IP:DOS_COUNTER) hits a limit
|
|
# (TX:DOS_COUNTER_THRESHOLD), then a burst is identified (IP:DOS_BURST_COUNTER) and the
|
|
# counter (IP:DOS_COUNTER) is reset. The burst counter expires within a timeout period
|
|
# (TX:DOS_BURST_TIME_SLICE).
|
|
# If the burst counter (IP:DOS_BURST_COUNTER) is greater equal 2, then the blocking flag
|
|
# is being set (IP:DOS_BLOCK). The blocking flag (IP:DOS_BLOCK) expires within a timeout
|
|
# period (TX:DOS_BLOCK_TIMEOUT). All this counting happens in phase 5.
|
|
# There is a stricter sibling to this rule (912170) in paranoia level 2, where the
|
|
# burst counter check (IP:DOS_BURST_COUNTER) hits at greater equal 1.
|
|
#
|
|
# The blocking is done in phase 1: When the blocking flag is encountered (IP:DOS_BLOCK),
|
|
# then the request is dropped without sending a response. If this happens, then a
|
|
# counter is # raised (IP:DOS_BLOCK_COUNTER).
|
|
# When an IP address is blocked for the first time, then the blocking is reported in a
|
|
# message and a flag (IP:DOS_BLOCK_FLAG) is set. This flag expires in 60 seconds.
|
|
# When an IP address is blocked and the flag (IP:DOS_BLOCK_FLAG) is set, then the
|
|
# blocking is not being reported (to prevent a flood of alerts). When the flag
|
|
# (IP:DOS_BLOCK_FLAG) has expired and a new request is being blocked, then the
|
|
# counter (IP:DOS_BLOCK_COUNTER) is being reset to 0 and the block is being treated
|
|
# as the first block (-> alert).
|
|
# In order to be able to display the counter (IP:DOS_BLOCK_COUNTER) and resetting
|
|
# it at the same time, we copy the counter (IP:DOS_BLOCK_COUNTER) into a different
|
|
# variable (TX:DOS_BLOCK_COUNTER), which is then displayed in turn.
|
|
#
|
|
# Variables:
|
|
# IP:DOS_BLOCK Flag if an IP address should be blocked
|
|
# IP:DOS_BLOCK_COUNTER Counter of blocked requests
|
|
# IP:DOS_BLOCK_FLAG Flag keeping track of alert. Flag expires after 60 seconds.
|
|
# IP:DOS_BURST_COUNTER Burst counter
|
|
# IP:DOS_COUNTER Request counter (static resources are ignored)
|
|
# TX:DOS_BLOCK_COUNTER Copy of IP:DOS_BLOCK_COUNTER (needed for display reasons)
|
|
# TX:DOS_BLOCK_TIMEOUT Period in seconds a blocked IP will be blocked
|
|
# TX:DOS_COUNTER_THRESHOLD Limit of requests, where a burst is identified
|
|
# TX:DOS_BURST_TIME_SLICE Period in seconds when we will forget a burst
|
|
# TX:STATIC_EXTENSIONS Paths which can be ignored with regards to DoS
|
|
#
|
|
# As a precondition for these rules, please set the following three variables:
|
|
# - TX:DOS_BLOCK_TIMEOUT
|
|
# - TX:DOS_COUNTER_THRESHOLD
|
|
# - TX:DOS_BURST_TIME_SLICE
|
|
#
|
|
# And make sure that TX:STATIC_EXTENSIONS is also set.
|
|
#
|
|
|
|
#
|
|
# -= Paranoia Level 0 (empty) =- (apply unconditionally)
|
|
#
|
|
|
|
#
|
|
# Skip if variables defining DoS protection are not set
|
|
#
|
|
SecRule &TX:dos_burst_time_slice "@eq 0" \
|
|
"id:912100,\
|
|
phase:1,\
|
|
pass,\
|
|
t:none,\
|
|
nolog,\
|
|
chain,\
|
|
skipAfter:END-DOS-PROTECTION-CHECKS"
|
|
SecRule &TX:dos_counter_threshold "@eq 0" \
|
|
"chain"
|
|
SecRule &TX:dos_block_timeout "@eq 0"
|
|
|
|
SecRule &TX:dos_burst_time_slice "@eq 0" \
|
|
"id:912110,\
|
|
phase:5,\
|
|
pass,\
|
|
t:none,\
|
|
nolog,\
|
|
chain,\
|
|
skipAfter:END-DOS-PROTECTION-CHECKS"
|
|
SecRule &TX:dos_counter_threshold "@eq 0" \
|
|
"chain"
|
|
SecRule &TX:dos_block_timeout "@eq 0"
|
|
|
|
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:912011,phase:1,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:912012,phase:2,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
#
|
|
# -= Paranoia Level 1 (default) =- (apply only when tx.executing_paranoia_level is sufficiently high: 1 or higher)
|
|
#
|
|
|
|
#
|
|
# -=[ Anti-Automation / DoS Protection : Block ]=-
|
|
#
|
|
|
|
#
|
|
# Block and track # of requests and log
|
|
#
|
|
SecRule IP:DOS_BLOCK "@eq 1" \
|
|
"id:912120,\
|
|
phase:1,\
|
|
drop,\
|
|
msg:'Denial of Service (DoS) attack identified from %{tx.real_ip} (%{tx.dos_block_counter} hits since last alert)',\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
chain"
|
|
SecRule &IP:DOS_BLOCK_FLAG "@eq 0" \
|
|
"setvar:'ip.dos_block_counter=+1',\
|
|
setvar:'ip.dos_block_flag=1',\
|
|
setvar:'tx.dos_block_counter=%{ip.dos_block_counter}',\
|
|
setvar:'ip.dos_block_counter=0',\
|
|
expirevar:'ip.dos_block_flag=60'"
|
|
|
|
|
|
#
|
|
# Block and track # of requests but don't log
|
|
#
|
|
SecRule IP:DOS_BLOCK "@eq 1" \
|
|
"id:912130,\
|
|
phase:1,\
|
|
drop,\
|
|
t:none,\
|
|
nolog,\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
setvar:'ip.dos_block_counter=+1'"
|
|
|
|
|
|
#
|
|
# -=[ Anti-Automation / DoS Protection: Count requests ]=-
|
|
#
|
|
|
|
#
|
|
# Skip if we have blocked the request
|
|
#
|
|
SecRule IP:DOS_BLOCK "@eq 1" \
|
|
"id:912140,\
|
|
phase:5,\
|
|
pass,\
|
|
t:none,\
|
|
nolog,\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
skipAfter:END-DOS-PROTECTION-CHECKS"
|
|
|
|
|
|
#
|
|
# DOS Counter: Count the number of requests to non-static resources
|
|
#
|
|
SecRule REQUEST_BASENAME "@rx .*?(\.[a-z0-9]{1,10})?$" \
|
|
"id:912150,\
|
|
phase:5,\
|
|
pass,\
|
|
capture,\
|
|
t:none,t:lowercase,\
|
|
nolog,\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
setvar:'tx.extension=/%{TX.1}/',\
|
|
chain"
|
|
SecRule TX:EXTENSION "!@within %{tx.static_extensions}" \
|
|
"setvar:'ip.dos_counter=+1'"
|
|
|
|
|
|
#
|
|
# Check DOS Counter
|
|
# If the request count is greater than or equal to user settings,
|
|
# we raise the burst counter. This happens via two separate rules:
|
|
# - 912160: raise from 0 to 1
|
|
# - 912161: raise from 1 to 2
|
|
#
|
|
# This approach with two rules avoids raising the burst counter
|
|
# from 0 to 2 via two concurrent requests. We do not raise the
|
|
# burst counter beyond 2.
|
|
#
|
|
#
|
|
SecRule IP:DOS_COUNTER "@ge %{tx.dos_counter_threshold}" \
|
|
"id:912160,\
|
|
phase:5,\
|
|
pass,\
|
|
t:none,\
|
|
nolog,\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
chain"
|
|
SecRule &IP:DOS_BURST_COUNTER "@eq 0" \
|
|
"setvar:'ip.dos_burst_counter=1',\
|
|
setvar:'!ip.dos_counter',\
|
|
expirevar:'ip.dos_burst_counter=%{tx.dos_burst_time_slice}'"
|
|
|
|
|
|
SecRule IP:DOS_COUNTER "@ge %{tx.dos_counter_threshold}" \
|
|
"id:912161,\
|
|
phase:5,\
|
|
pass,\
|
|
t:none,\
|
|
nolog,\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
chain"
|
|
SecRule &IP:DOS_BURST_COUNTER "@ge 1" \
|
|
"setvar:'ip.dos_burst_counter=2',\
|
|
setvar:'!ip.dos_counter',\
|
|
expirevar:'ip.dos_burst_counter=%{tx.dos_burst_time_slice}'"
|
|
|
|
|
|
#
|
|
# Check DOS Burst Counter and set Block
|
|
# Check the burst counter - if greater than or equal to 2, then we set the IP
|
|
# block variable for a given expiry and issue an alert.
|
|
#
|
|
SecRule IP:DOS_BURST_COUNTER "@ge 2" \
|
|
"id:912170,\
|
|
phase:5,\
|
|
pass,\
|
|
t:none,\
|
|
log,\
|
|
msg:'Potential Denial of Service (DoS) Attack from %{tx.real_ip} - # of Request Bursts: %{ip.dos_burst_counter}',\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
setvar:'ip.dos_block=1',\
|
|
expirevar:'ip.dos_block=%{tx.dos_block_timeout}'"
|
|
|
|
|
|
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:912013,phase:1,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:912014,phase:2,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:912019,phase:5,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
#
|
|
# -= Paranoia Level 2 =- (apply only when tx.executing_paranoia_level is sufficiently high: 2 or higher)
|
|
#
|
|
|
|
#
|
|
# Check DOS Burst Counter and set Block
|
|
# Check the burst counter - if greater than or equal to 1, then we set the IP
|
|
# block variable for a given expiry and issue an alert.
|
|
#
|
|
# This is a stricter sibling of rule 912170.
|
|
#
|
|
SecRule IP:DOS_BURST_COUNTER "@ge 1" \
|
|
"id:912171,\
|
|
phase:5,\
|
|
pass,\
|
|
t:none,\
|
|
log,\
|
|
msg:'Potential Denial of Service (DoS) Attack from %{tx.real_ip} - # of Request Bursts: %{ip.dos_burst_counter}',\
|
|
tag:'application-multi',\
|
|
tag:'language-multi',\
|
|
tag:'platform-multi',\
|
|
tag:'attack-dos',\
|
|
tag:'paranoia-level/2',\
|
|
setvar:'ip.dos_block=1',\
|
|
expirevar:'ip.dos_block=%{tx.dos_block_timeout}'"
|
|
|
|
|
|
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:912015,phase:1,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:912016,phase:2,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
#
|
|
# -= Paranoia Level 3 =- (apply only when tx.executing_paranoia_level is sufficiently high: 3 or higher)
|
|
#
|
|
|
|
|
|
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:912017,phase:1,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:912018,phase:2,pass,nolog,skipAfter:END-REQUEST-912-DOS-PROTECTION"
|
|
#
|
|
# -= Paranoia Level 4 =- (apply only when tx.executing_paranoia_level is sufficiently high: 4 or higher)
|
|
#
|
|
|
|
|
|
|
|
#
|
|
# -= Paranoia Levels Finished =-
|
|
#
|
|
SecMarker "END-REQUEST-912-DOS-PROTECTION"
|
|
|
|
SecMarker "END-DOS-PROTECTION-CHECKS"
|