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.1Nice! 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:
- LucasPNimbostratus
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 !