Block IP after a number of ASM Blocks
Problem this snippet solves:
There is no reason to let Attacker hand over all information at once.
How to use this snippet:
Add the iRule to the virtual Server and activate iRule after ASM Block in the ASM Profile.
Please let me know if you need help with this
Code :
when RULE_INIT priority 10 {
# excessive ASM Block based on https://devcentral.f5.com/s/articles/excessive-404-blacklist
# v1.0 - Joel Moses
# v1.1 - Nico Giefing
# Block all site access to source IP addresses that exceed a
# certain number of HTTP requests which were blocked at ASM/AWAF within
# a fixed period of time. Useful for blocking harvesting
# activities (or at least slowing them down significantly).
#
# Use this iRule at your own risk. If your site has a propensity
# to throw off lots of 404 errors in normal operation, you may
# inadvertently find valid users blocked.
# Set the maximum number of WAF blocks for a client IP in a
# certain period of time. The default setings are 100
# WAF Blocks in 5 minutes. Following this, the client IP
# address will be blocklisted the next 180 minutes.
set static::maxerrors 10
set static::maxperiod 300
set static::holdtime 10800
# If for any reason you need to rid yourself of a
# blocklist, you can send the VIP running this iRule
# a query string parameter in the format:
# http(s)://sitename.com/?DeleteKey=;
# where the case-sensitive key is defined below. Consider
# this a "get out of jail free" card in case something
# goes totally wrong.
set static::deletekey "DeleteAllBlocklistData"
# If set to true, log all blocklisted source IP addresses
# to the LTM log.
set static::log_offender 1
}
when CLIENT_ACCEPTED priority 10{
# Block IP if in the blocklist
# Collect the remote IP address.
set srcip [IP::remote_addr]
set dstip [IP::local_addr]
set blocklist_name "blocklist"
set countlist_name "[IP::remote_addr]"
if { [table lookup -subtable $blocklist_name $srcip] != "" } {
#log local0. "The IP $srcip has been blocked while accessing $dstip"
TCP::close
return
}
# }
}
when HTTP_REQUEST priority 10{
set uri "[HTTP::uri]"
if { ([URI::query [HTTP::uri] DeleteKey ] equals "$static::deletekey") and ([IP::addr [IP::client_addr] equals 10.0.0.0/8]) } {
log local0. "BLOCKLIST: Table manually cleared by [IP::remote_addr]."
table delete -subtable $blocklist_name -all
}
if {(([HTTP::uri] eq "/blocklist") or ([HTTP::uri] eq "/blacklist")) and ([IP::addr [IP::client_addr] equals 10.0.0.0/8]) } {
set response "BIGIP Blocklist [clock format [clock seconds]] "
set blocklist_name "blocklist"
set block_count 0
foreach key [table keys -subtable $blocklist_name] {
set remaining_sec [table lifetime -subtable $blocklist_name -remaining $key]
set remaining_min [expr {$remaining_sec/60} ]
set response "$response
The IP ${key} is blocked for the next $remaining_sec seconds, equals to $remaining_min minutes"
set block_count [expr {$block_count + 1}]
}
if {$block_count eq 0 }then {
set response "
NO BLOCKED IP
"
HTTP::respond 200 content $response "Content-Type" "text/html"
} else {
set response "$response
"
HTTP::respond 299 content $response "Content-Type" "text/html"
}
}
}
# it is needed to activte iRules in ASM/AWAF after block
# https://support.f5.com/csp/article/K22017023
when ASM_REQUEST_BLOCKING priority 1{
set x [ASM::violation_data]
# marker bit to handle header change
set activeViolation 1
#log local0. "seen a blocked request"
if { ($uri != "/favicon.ico") } then {
# If the source IP has gotten a ASM block but does not currently
# have a unique subtable entry, create a new offender.
if { ([table lookup -subtable $countlist_name "count"] == "") } then {
set count 1
table add -subtable $countlist_name "count" $count indef $static::maxperiod
#log local0. "added table count IP $countlist_name"
# If the source IP has a 404 and is a repeat offender,
# increment the count within the table.
} elseif { ([table lookup -notouch -subtable $countlist_name "count"] != "") } {
set count [table incr -notouch -subtable $countlist_name "count"]
# If the maximum number of errors has been reached,
# add the source IP to the blocklist and get rid of the
# offender's unique table (he'll get a new one after his holdtime
# is over). Respond with the error page.
if { $count >= $static::maxerrors } then {
table add -subtable $blocklist_name $srcip "blocked" indef $static::holdtime
log local0. "add ip $srcip to blocklist"
table delete -subtable $countlist_name -all
if { ($static::log_offender) } {
#log local0. "BLOCKLIST: [IP::remote_addr] is blocklisted on [virtual] for $static::holdtime seconds."
}
return
}
}
}
} Tested this on version:
14.12 Comments
- LucasP
Nimbostratus
Thank you for the iRule it is exactly what I was looking for !
One question regarding the point "activate iRule after ASM Block in the ASM Profile". is it the option "Trigger ASM iRule Events" on the ASM profile ? If yes did you set it to "normal mode" or "Compatibility Mode" ? Thanks !
Nice! You can also do this as ASM_REQUEST_DONE that is triggered even before ASM_REQUEST_BLOCKING (this way some CPU may be saved) with an if statement to check if after the request is seen by the ASM if there is a violation ( [ASM::status] equals "blocked" ) and then to check the table as I have done this for a DOS attack.
In some cases if there is a XFF (X-Forwarded-For) better use it as the client's real source ip check as I have in my irule: