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.1
Published Apr 20, 2021
Version 1.0
  • 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:

    https://community.f5.com/t5/codeshare/asm-waf-rate-limit-and-block-clients-by-source-ip-or-device-id/ta-p/291471

  • LucasP's avatar
    LucasP
    Icon for Nimbostratus rankNimbostratus

    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 !