# This iRule limits IPs & UIDs extracted from a session against URIs which are configured separately in iRule datagroups # where the names are respective to their function. Rate limits are done within a set of values and then block by IP or UID after # set thresholds. There are three levels of ban timers, StdB, LongB, & HalfB though more can be added. # There are three levels of timers, HTime STime & LTime. These cover different timing lengths. # There are IPMaxReqs, UIDMaxReqs, & URIMaxReqs which all set max request values per type. # I2UCnt and U2ICnt both have their own timers in the Hydra section. # Dependencies: TIP_ALL, UIDExtract_AddHeader_ALL iRules / TC_LOGIN_URI, R8L_URI, R8L_WWW, R8L_BAD_IP, R8L_BAD_UID, R8L_GOOD_IP, R8L_GOOD_UID, XXX_LAN DataGroups # # !!!BLOCKING MODE!!! How to Disable: # Perform and Find/Replace for the string #@# and replace with nothing. This will uncomment the standard 403 blocked content page. # Alternatively you can search for this value and review the rest of the blocking options such as a 302 redirection, or simply no response at all # # 2016-10-01 Added WWW Rate Limiting ability. This focuses on a broader URI by using starts_with so you can rate limit an entire site by using / as the URI or # all sub-paths of /public if you add /public. The additional dependency is R8L_WWW for DataGroups. The new counter is WWWTime and WWWB where Time is the # tracking time and WWWB is the ban time. WWWMaxReqs is the maximum value for WWW Rate Limiter threshold before a block is initiated. when HTTP_REQUEST priority 640 { ######TroubleShooting Headers ###### log local0. "TIP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] - True-Client-IP Header value: [HTTP::header True-Client-IP]" ########################################################################### # Set user cookie as Session ID set sid [string range [HTTP::cookie TLFREPLAYID] 0 32 ] set jsid [string range [HTTP::cookie AKAMTMXSID] 0 18 ] # set jsid [string range [HTTP::cookie JSESSIONID_AUTHENTICATION] 52 75 ] set baiu_host [HTTP::host] # Set URI value set buri [HTTP::path] # 0 - NONE, 1 - LOW, 2 - MEDIUM, 3 - VERBOSE set BAIU_LOG_LVL 1 ########################################################################### # Only process matched uris & allow specific IPs/UIDs if {$tip ne ""} { if { ( [class match $tip equals R8L_GOOD_IP ] ) } { if { $BAIU_LOG_LVL >= 2 } {log local0. "WHITELIST_IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ IP Whitelisted"} return } # # This line is enabled down below in the UID section. Disabling here ensures an IP gets a Request Count. # #if { ( [class match $waf_uid equals R8L_GOOD_UID ] ) } { # #if { $BAIU_LOG_LVL >= 2 } {log local0. "WHITELIST_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ Username Whitelisted"} # #return # #} if { ( not [class match $buri equals R8L_URI ] ) and ( not [class match $buri equals XXX_LOGIN_URI ] ) and ( not [class match $buri starts_with R8L_WWW ] )} { if { $BAIU_LOG_LVL >= 3 } {log local0. "NOMATCH_URI: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ URI not limited"} return } if { [class match $tip equals R8L_BAD_IP ] } { if { $BAIU_LOG_LVL >= 2 } {log local0. "MATCH_BAD_IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ IP in BAD group"} } if { [class match $tip equals R8L_BAD_UID ] } { if { $BAIU_LOG_LVL >= 2 } {log local0. "MATCH_BAD_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ UID in BAD group"} } } ########################################################################### # /// Sword - Single IP/UID/URI Tracking/Banning - Cut Them Down! ########################################################################### # Used to set different time outs for IP, UID, & URI tracking # Ban and request times are for all but can make unique if desired # Total IP Requests allowed set IPMaxReqs 4000000 # Total UID Requests allowed set UIDMaxReqs 3000000 # Total URI Requests allowed set URIMaxReqs 100000 # Total Site Requests allowed set WWWMaxReqs 100000 # Set Rate Limit Failed Auth Multiplier set R8X 1 # Used for WWW banning # Requests within X seconds set WTime 1800 # Ban X seconds set WWWB 600 # Used for standard banning # Requests within X seconds set STime 115200 # Ban X seconds set StdB 194400 # Used for short banning # Requests within X seconds set HTime 108000 # Ban X seconds set HalfB 57600 # Used for longer duration banning # Banned events within X seconds set LTime 691200 # Total banned events set MaxBs 0 # Ban X seconds set LongB 453600 # # Build monitor table for tracking elements # #set MONITOR_TBL UID_limit_monitor # #set MONITOR_TBL IP_limit_monitor # #set MONITOR_TBL URI_limit_monitor # #set MONITOR_TBL WWW_limit_monitor ########################################################################### # This builds the Ban IP tracking value set b_ip "b_$tip" ########################################################################### # Distinctions # This builds the R8L URI tracking value if {$tip ne ""} { if { ( [class match $buri equals R8L_URI ] ) and ( not [class match $tip equals R8L_GOOD_IP ] )} { set r8luri 1 if { $BAIU_LOG_LVL >= 2 } {log local0. "R8L_URI_CALLED: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ R8L URI called"} } # This builds the Login URI tracking value if { ( [class match $buri equals XXX_LOGIN_URI ] ) and ( not [class match $tip equals R8L_GOOD_IP ] ) and ( $method == "POST" ) } { set loginuri 1 if { $BAIU_LOG_LVL >= 2 } {log local0. "LOGIN_URI_CALLED: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ LOGIN URI called"} } # This builds the R8L WWW tracking value. Using starts_with iRule function so we can add / /public or /private and cover all sub paths rather than just have a specific URI like the login page. if { ( [class match $buri starts_with R8L_WWW ] ) and ( not [class match $tip equals R8L_GOOD_IP ] ) } { set r8lwww 1 if { $BAIU_LOG_LVL >= 2 } {log local0. "R8L_WWW_CALLED: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ R8L WWW called"} } } if {$tip ne ""} { if { $r8luri == 1 } { ########################################################################### # Set Normal R8L URI Counters set URICnt [table keys -subtable "URIReqMon" -count] ########################################################################### # Begin the rate limiting by setting the unique ban values set URIbTime [table timeout -subtable URIBanZ -remaining $b_ip ] # Set IP/URI Ban count set WWWbCnt [table lookup -notouch -subtable URIbCnt $b_ip ] # Check for IP/URI ban time if { $URIbTime > 0 } { if { $URIbCnt == 1 } { # If first ban... Reset Ban counter for IP/URI for repeat failures during blocking period to create a rolling blocking scenario so block does not start until IP stops. table set -subtable URIBanZ $b_ip 1 $StdB $StdB table set -subtable URIbCnt $b_ip 1 $STime $STime if { $URIbTime <= [expr {$StdB} - 3600 ] } { if { $BAIU_LOG_LVL >= 1 } {log local0. "URI_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $StdB - Remaining time was: $URIbTime"} } } if { $URIbCnt >= 2 } { # If already banned... Reset Ban counter for IP for repeat failures during blocking period to create a rolling blocking scenario so block does not start until IP stops. table set -subtable URIBanZ $b_ip 3 $LongB $LongB table set -subtable URIbCnt $b_ip 3 $LTime $LTime if { $URIbTime <= [expr {$StdB} - 3600 ] } { if { $BAIU_LOG_LVL >= 1 } {log local0. "URI_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $StdB - Remaining time was: $URIbTime"} } } # Ensure IP is not in request counter to keep cleaner table. table delete -subtable URIReqMon $b_ip # # Log event with remaining time for IP/URI. Not useful with Rolling ban. # #if { $BAIU_LOG_LVL >= 2 } {log local0. "BANNED_URI: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $URIbTime, remaining time: [table timeout -subtable URIBanZ -remaining $b_ip ]"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # Send 403 page and reject. HTML content and 403 response. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?rs=yes" #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } ########################################################################### # Set R8L Counters for R8L URIs set URIreqCnt [table lookup -notouch -subtable URIReqMon $b_ip ] # Log Request Counters if { $BAIU_LOG_LVL >= 1 } {log local0. "BAIU_R8LURI_REQCNT: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ URIReqCnt:$URIreqCnt MonIP: $b_ip"} ########################################################################### # Check if IP exists in URI table if not create entry otherwise increment if { $URIreqCnt == "" } { # set the lifetime timeout value so request will go away after a set amount of time set URIreqCnt [ table set -subtable URIReqMon $b_ip 1 $STime $STime ] } else { # Increment URI Counter set URIreqCnt [ table incr -notouch -subtable URIReqMon $b_ip ] } ########################################################################### # Set URI table limit and let connections pass if table is full if { $URICnt >= 100000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "URI_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ URICnt=$URICnt - They shall pass"} # Delete latest IP from URIReqMon table to free up new spot. table delete -subtable URIReqMon $b_ip return } else { if { $URIbCnt >= 100000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "URI_BAN_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ URIbCnt=$URIbCnt - They shall pass"} return } } ############################################################################ # Check if too many request for a URI if { $URIreqCnt > $URIMaxReqs } { # Set the short ban time and remove httpRequests set URIbTime $StdB table delete -subtable URIReqMon $b_ip # Check IP ban levels and set ban times if { $URIbCnt == "" } { table set -subtable URIbCnt $b_ip 1 $LTime $LTime } else { set URIbCnt [table incr -notouch -subtable URIbCnt $b_ip ] # Check if we need to ban them for longer if { $URIbCnt > $MaxBs } { set URIbTime $LongB } } # Ban them for $URIbTime table set -subtable URIBanZ $b_ip 1 $URIbTime $URIbTime # #table set -subtable $URI_MONITOR_TBL "$b_ip" "UID: $waf_uid; Ban:$URIbTime secs" $URIbTime if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_URI: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_ip: $b_ip Banned for: $URIbTime"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?ws=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } # DEBUG INFO if { $BAIU_LOG_LVL >= 3 } { log local0.alert "URIreqCnt: [table lookup -notouch -subtable URIReqMon $b_ip ]" log local0.alert "URIbCnt: [table lookup -notouch -subtable URIbCnt $b_ip]" log local0.alert "URIbTime: [table lookup -notouch -subtable URIBanZ $b_ip]" # #log local0.alert "URI_limit_monitor tbl keys: [table keys -subtable $URI_MONITOR_TBL -notouch]" } return } } ########################################################################### # WWW Specific Rate Limiting if {$tip ne ""} { if { $r8lwww == 1 } { ########################################################################### # Set Normal R8L WWW Counters set WWWCnt [table keys -subtable "WWWReqMon" -count] ########################################################################### # Begin the rate limiting by setting the unique ban values set WWWbTime [table timeout -subtable WWWBanZ -remaining $b_ip ] # Set IP/WWW Ban count set WWWbCnt [table lookup -notouch -subtable WWWbCnt $b_ip ] # Check for IP/WWW ban time if { $WWWbTime > 0 } { if { $WWWbCnt == 1 } { # If first ban... Reset Ban counter for IP/WWW for repeat failures during blocking period to create a rolling blocking scenario so block does not start until IP stops. table set -subtable WWWBanZ $b_ip 1 $WWWB $WWWB table set -subtable WWWbCnt $b_ip 1 $WTime $WTime if { $URIbTime <= [expr {$StdB} - 300 ] } { if { $BAIU_LOG_LVL >= 1 } {log local0. "WWW_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $WWWB - Remaining time was: $WWWbTime"} } } if { $WWWbCnt >= 2 } { # If already banned... Reset Ban counter for IP for repeat failures during blocking period to create a rolling blocking scenario so block does not start until IP stops. table set -subtable WWWBanZ $b_ip 3 $WWWB $WWWB table set -subtable WWWbCnt $b_ip 3 $WTime $WTime if { $WWWbTime <= [expr {$WWWB} - 300 ] } { if { $BAIU_LOG_LVL >= 1 } {log local0. "WWW_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $WWWB - Remaining time was: $WWWbTime"} } } # Ensure IP is not in request counter to keep cleaner table. table delete -subtable WWWReqMon $b_ip # # Log event with remaining time for IP/URI. Not useful with Rolling ban. # #if { $BAIU_LOG_LVL >= 2 } {log local0. "BANNED_WWW: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $WWWbTime, remaining time: [table timeout -subtable WWWBanZ -remaining $b_ip ]"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # Send 403 page and reject. HTML content and 403 response. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?www=yes" #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } ########################################################################### # Set R8L Counters for R8L WWWs set WWWreqCnt [table lookup -notouch -subtable WWWReqMon $b_ip ] # Log Request Counters if { $BAIU_LOG_LVL >= 1 } {log local0. "BAIU_R8LWWW_REQCNT: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ WWWReqCnt:$WWWreqCnt MonIP: $b_ip"} ########################################################################### # Check if IP exists in WWW table if not create entry otherwise increment if { $WWWreqCnt == "" } { # set the lifetime timeout value so request will go away after a set amount of time set WWWreqCnt [ table set -subtable WWWReqMon $b_ip 1 $WTime $WTime ] } else { # Increment WWW Counter set WWWreqCnt [ table incr -notouch -subtable WWWReqMon $b_ip ] } ########################################################################### # Set WWW table limit and let connections pass if table is full if { $WWWCnt >= 100000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "WWW_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ WWWCnt=$WWWCnt - They shall pass"} # Delete latest IP from WWWReqMon table to free up new spot. table delete -subtable WWWReqMon $b_ip return } else { if { $WWWbCnt >= 100000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "WWW_BAN_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ WWWbCnt=$WWWbCnt - They shall pass"} return } } ############################################################################ # Check if too many request for a WWW if { $WWWreqCnt > $WWWMaxReqs } { # Set the short ban time and remove httpRequests set WWWbTime $WWWB table delete -subtable WWWReqMon $b_ip # Check IP ban levels and set ban times if { $WWWbCnt == "" } { table set -subtable WWWbCnt $b_ip 1 $WTime $WTime } else { set WWWbCnt [table incr -notouch -subtable WWWbCnt $b_ip ] # Check if we need to ban them for longer if { $WWWbCnt > $MaxBs } { set WWWbTime $HalfB } } # Ban them for $WWWbTime table set -subtable WWWBanZ $b_ip 1 $WWWbTime $WWWbTime # #table set -subtable $WWW_MONITOR_TBL "$b_ip" "UID: $waf_uid; Ban:$WWWbTime secs" $WWWbTime if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_WWW: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_ip: $b_ip Banned for: $WWWbTime"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?www=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } # DEBUG INFO if { $BAIU_LOG_LVL >= 3 } { log local0.alert "WWWreqCnt: [table lookup -notouch -subtable WWWReqMon $b_ip ]" log local0.alert "WWWbCnt: [table lookup -notouch -subtable WWWbCnt $b_ip]" log local0.alert "WWWbTime: [table lookup -notouch -subtable WWWBanZ $b_ip]" # #log local0.alert "WWW_limit_monitor tbl keys: [table keys -subtable $WWW_MONITOR_TBL -notouch]" } return } } } when HTTP_REQUEST_DATA priority 641 { if {$tip ne ""} { if { $loginuri == 1 } { ########################################################################### # Set Normal IP & UID Counters set IPCnt [table keys -subtable "IPReqMon" -count] set UIDCnt [table keys -subtable "UIDReqMon" -count] ########################################################################### # Begin the rate limiting by setting the unique ban values set IPbTime [table timeout -subtable IPBanZ -remaining $b_ip ] # Set IP Ban count set IPbCnt [table lookup -notouch -subtable IPbCnt $b_ip ] ########################################################################### # Check for IP ban time if { $IPbTime > 0 } { if { $IPbCnt == 1 } { # If first ban... Reset Ban counter for IP for repeat failures during blocking period to create a rolling blocking scenario so block does not start until IP stops. table set -subtable IPBanZ $b_ip 1 $StdB $StdB table set -subtable IPbCnt $b_ip 1 $STime $STime if { $IPbTime <= [expr {$StdB} - 3600 ] } { if { $BAIU_LOG_LVL >= 1 } {log local0. "IP_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $StdB - Remaining time was: $IPbTime"} } } if { $IPbCnt >= 2 } { # If already banned... Reset Ban counter for IP for repeat failures during blocking period to create a rolling blocking scenario so block does not start until IP stops. table set -subtable IPBanZ $b_ip 3 $LongB $LongB table set -subtable IPbCnt $b_ip 3 $LTime $LTime if { $IPbTime <= [expr {$StdB} - 3600 ] } { if { $BAIU_LOG_LVL >= 1 } {log local0. "IP_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $StdB - Remaining time was: $IPbTime"} } } # Ensure IP is not in request counter to keep cleaner table. table delete -subtable IPReqMon $b_ip # Clear table of tracking entry since IP &or UID are now banned. !!!Disabling UID since I want this done only at the UID level to be effective. table delete -all -subtable I2U$b_ip # #table delete -all -subtable U2I$b_uid # ## Ban UID used during IP block invocation. This can be very dangerous since it would block all UIDs used in a list which will likely have a lot of good accounts. They could never stop and ban every user. # #table set -subtable UIDBanZ $b_uid 1 $HalfB $HalfB # # if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_uid: $b_uid Banned for: $HalfB"} # # Log event with remaining time for IP. Not useful with Rolling ban. # #if { $BAIU_LOG_LVL >= 2 } {log local0. "BANNED_IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $IPbTime, remaining time: [table timeout -subtable IPBanZ -remaining $b_ip ]"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } ########################################################################### # Set IP table limit and let connections pass if table is full if { $IPCnt >= 85000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "IP_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ IPCnt=$IPCnt - They shall pass "} # Delete latest IP from IPReqMon table to free up new spot. table delete -subtable IPReqMon $b_ip table delete -all -subtable I2U$b_ip return } else { if { $IPbCnt >= 85000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "IP_BAN_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ IPbCnt=$IPbCnt - They shall pass "} return } } ########################################################################### # SetUID Nicest 1 liner. Check length 6 or more, lower case, remove e-mail, strip special characters, and reduce tracked length to 14. set uid_nicest [string range [string map {" " ""} [string map {\x21 \x20 \x22 \x20 \x23 \x20 \x24 \x20 \x25 \x20 \x27 \x20 \x28 \x20 \x29 \x20 \x2A \x20 \x2B \x20 \x2C \x20 \x2D \x20 \x2E \x20 \x2F \x20 \x3A \x20 \x3B \x20 \x3C \x20 \x3D \x20 \x3E \x20 \x3F \x20 \x5B \x20 \x5C \x20 \x5D \x20 \x5E \x20 \x5F \x20 \x60 \x20 \x7B \x20 \x7C \x20 \x7D \x20 \x7E \x20} [string map {"%20" " "} [string map {"%25" "%"} [string map {"%2525" "%"} [getfield [string map {"%40" "@"} [string trim [string tolower $waf_uid ] ] ] "@" 1 ] ] ] ] ] ] 0 13 ] # set uid_nicest [string range [string map {" " ""} [string map {\x21 \x20 \x22 \x20 \x23 \x20 \x24 \x20 \x25 \x20 \x27 \x20 \x28 \x20 \x29 \x20 \x2A \x20 \x2B \x20 \x2C \x20 \x2D \x20 \x2E \x20 \x2F \x20 \x3A \x20 \x3B \x20 \x3C \x20 \x3D \x20 \x3E \x20 \x3F \x20 \x5B \x20 \x5C \x20 \x5D \x20 \x5E \x20 \x5F \x20 \x60 \x20 \x7B \x20 \x7C \x20 \x7D \x20 \x7E \x20} [getfield [string map {"%40" "@"} [string trim [string tolower $waf_uid ] ] ] "@" 1 ] ] ] 0 13 ] # # Experimental - string map %25 %2525 to % then map %20 to space then complete all special char map to space # # Trim UID of non print chars and lower case to simplified UID # #set uid_nice [string trim [string tolower $waf_uid ] ] # #if string range less than 6 chars do not track return since it's not min user ID length. Blocking is optional. # #if { [ string length $uid_nice ] <= 5 } { # # if { $BAIU_LOG_LVL >= 2 } {log local0. "UID_2SHORT: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] UID: $uid_nicest SID: $sid~$jsid HOST: $baiu_host URI: $buri ~ UID too short" } # #return # #} # # # Remove e-mail since you can't sign in w/ email ID and then trim unused characters (not &)(Trims dot dash and underscore too! Still better for UID simplification) # #set uid_nicer [string map {"\x20" ""} [string map {\x21 \x20 \x22 \x20 \x23 \x20 \x24 \x20 \x25 \x20 \x27 \x20 \x28 \x20 \x29 \x20 \x2A \x20 \x2B \x20 \x2C \x20 \x2D \x20 \x2E \x20 \x2F \x20 \x3A \x20 \x3B \x20 \x3C \x20 \x3D \x20 \x3E \x20 \x3F \x20 \x5B \x20 \x5C \x20 \x5D \x20 \x5E \x20 \x5F \x20 \x60 \x20 \x7B \x20 \x7C \x20 \x7D \x20 \x7E \x20} [getfield [string map {"%40" "@"} $uid_nice ] "@" 1 ] ] ] # # Use only first 14 characters of UID # #set uid_nicest [string range $uid_nicer 0 13] # ## Do not track e-mail addresses with UIDs. Useful with UID Nicest 1 liner that doesn't strip e-mails when e-mails aren't considered as UIDs # #set uid_nice [string map {"%40" "@"} $waf_uid ] # #if { $uid_nice contains "@" } { # #if { $BAIU_LOG_LVL >= 2 } {log local0. "NON_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ UID is e-mail - do not track UID-Nice:$uid_nice" } # #return # #} # ## SetUID Nicest 1 liner but not using e-mail. Check length 6 or more, lower case, strip special characters, and reduce tracked length to 14. Combine with e-mail dropper above. # #set uid_nicest [string range [string map {" " ""} [string map {\x21 \x20 \x22 \x20 \x23 \x20 \x24 \x20 \x25 \x20 \x27 \x20 \x28 \x20 \x29 \x20 \x2A \x20 \x2B \x20 \x2C \x20 \x2D \x20 \x2E \x20 \x2F \x20 \x3A \x20 \x3B \x20 \x3C \x20 \x3D \x20 \x3E \x20 \x3F \x20 \x5B \x20 \x5C \x20 \x5D \x20 \x5E \x20 \x5F \x20 \x60 \x20 \x7B \x20 \x7C \x20 \x7D \x20 \x7E \x20} [string trim [string tolower $uid_nice ] ] ] ] 0 13 ] # Check after shortening tracking UID is still minimum length. If not then return or drop. my.uid is 6 but wld be myuid n then be dropped if dot is char in uid_nicest logic. if { [ string length $uid_nicest ] <= 5 } { if { $BAIU_LOG_LVL >= 2 } {log local0. "UID_2SHORT: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] UID: $uid_nicest SID: $sid~$jsid HOST: $baiu_host URI: $buri ~ UID still too short" } # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" # Send 403 page and reject. HTML content and 403 response. #HTTP::respond 403 content {blocked} noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection #event disable all return } ########################################################################### # This line builds the Ban UID value set b_uid "b_$uid_nicest" ########################################################################### # Set UID Ban Time set UIDbTime [table timeout -subtable UIDBanZ -remaining $b_uid ] # Set UID Ban count set UIDbCnt [table lookup -notouch -subtable UIDbCnt $b_uid ] # Set UID table limit and let connections pass if table is full if { $UIDCnt >= 100000} { if { $BAIU_LOG_LVL >= 1 } {log local0. "UID_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ UIDCnt=$UIDCnt - They shall pass "} # Delete latest UID from UIDReqMon table to free up new spot. table delete -subtable UIDReqMon $b_uid table delete -all -subtable I2U$b_ip table delete -all -subtable U2I$b_uid return } else { if { $UIDbCnt >= 100000 } { if { $BAIU_LOG_LVL >= 1 } {log local0. "UID_BAN_TABLE_FULL: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ UIDbCnt=$UIDbCnt - They shall pass "} return } } ########################################################################### # Check if UID is white listed. If so let them pass. You must use simplified UIDs for whitelisting # We use this one here because we still want an IP Req Count. if { ( [class match $waf_uid equals R8L_GOOD_UID ] ) } { if { $BAIU_LOG_LVL >= 2 } {log local0. "WHITELIST_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ Username Whitelisted"} return } ########################################################################### # Check for UID ban time if { $UIDbTime > 0 } { ## Reset Ban counter for UID for repeat failures during blocking period to create a rolling blocking scenario so block does not start until UID stops. # # UID rolling ban VERY helpful to block list attackers. Still can ban valid account. # #table set -subtable UIDBanZ $b_uid 1 $HalfB $HalfB # #if { $IPbTime <= [expr {$StdB} - 3600 ] } { # #if { $BAIU_LOG_LVL >= 1 } {log local0. "UID_ROLLING_BAN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_uid: $b_uid Banned for: $HalfB - - Remaining time was: $UIDbTime""} # #} # Ensure UID is not in request counter to keep cleaner table. table delete -subtable UIDReqMon $b_uid # Clear table of tracking entry since IP &or UID are now banned. !!! I use both and just IP for IPBans to be the most effective and keep the cleanest tables. table delete -all -subtable I2U$b_ip table delete -all -subtable U2I$b_uid ## Ban IP used during UID block invocation table set -subtable IPBanZ $b_ip 1 $StdB $StdB table set -subtable IPbCnt $b_ip 1 $STime $STime # #if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_ip: $b_ip Banned for: $StdB"} # Log event with remaining time for UID. Not useful with Rolling UID ban. if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ b_ip: $b_ip Banned for: $StdB, - UID Ban Time Remaining: $UIDbTime"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } ########################################################################### # Set IP & UID Request Counters for Login URI set IPreqCnt [table lookup -notouch -subtable IPReqMon $b_ip ] set UIDreqCnt [table lookup -notouch -subtable UIDReqMon $b_uid ] # Log Request Counters. Useful for investigating behavior and tracking all UIDs at the same time. # Disable if you have the All in One log at the end enabled # #if { $BAIU_LOG_LVL >= 1 } {log local0. "BAIU_LOGIN_REQCNT: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ IPReqCnt:$IPreqCnt UIDReqCnt:$UIDreqCnt MonIP: $b_ip MonUID: $b_uid "} ########################################################################### # Check if IP exists if not create entry otherwise increment if { $IPreqCnt == "" } { # set the lifetime timeout value so request will go away after a set amount of time set IPreqCnt [ table set -subtable IPReqMon $b_ip 1 $STime $STime ] } else { # Increment IP Counter set IPreqCnt [ table incr -notouch -subtable IPReqMon $b_ip ] } ########################################################################### # Check if UID exists if not create entry otherwise increment if { $UIDreqCnt == "" } { # set the lifetime timeout value so request will go away after a set amount of time set UIDreqCnt [ table set -subtable UIDReqMon $b_uid 1 $STime $STime ] } else { # Increment UID Counter set UIDreqCnt [ table incr -notouch -subtable UIDReqMon $b_uid ] } ############################################################################ # ... Sword - Single IP/UID Tracking/Banning ############################################################################ ############################################################################ # /// Hydra - Single to Many IP/UID Tracking/Banning ############################################################################ # Single IP tracking all UIDs - Set values for single IP calling to multi UIDs set I2UuReq [ table set -subtable I2U$b_ip $b_uid 1 $STime $STime ] # Single UID tracking all IPs - Set values for all IPs calling to UID set U2IuReq [ table set -subtable U2I$b_uid $b_ip 1 $STime $STime ] ############################################################################ # ... Hydra - Single to Many IP/UID Tracking/Banning ############################################################################ ############################################################################ # /// Sword - Single IP/UID Tracking/Banning ############################################################################ # Check if too many request for an IP if { $IPreqCnt > $IPMaxReqs } { # Set the short ban time and remove httpRequests set IPbTime $StdB set UIDbTime $HalfB table delete -subtable IPReqMon $b_ip # Check IP ban levels and set ban times if { $IPbCnt == "" } { table set -subtable IPbCnt $b_ip 1 $LTime $LTime table set -subtable UIDbCnt $b_uid 1 $STime $STime } else { set IPbCnt [table incr -notouch -subtable IPbCnt $b_ip ] table set -subtable UIDbCnt $b_uid 1 $STime $STime # Check if we need to ban them for longer if { $IPbCnt >= $MaxBs } { set IPbTime $LongB set UIDbTime $HalfB } } # Ban them for $IPbTime or other - UID set to half to not punish actual user but still block. If actual user then will get custom block page to call in and alert of fraud. table set -subtable IPBanZ $b_ip 1 $IPbTime $IPbTime table set -subtable UIDBanZ $b_uid 1 $UIDbTime $UIDbTime # Clean up Hydra Tables table delete -all -subtable I2U$b_ip # #table delete -all -subtable U2I$b_uid # #table set -subtable $IP_MONITOR_TBL "$b_ip" "UID: $waf_uid; Ban:$IPbTime secs" $IPbTime if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_ip: $b_ip Banned for: $IPbTime"} if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_uid: $b_uid Banned for: $UIDbTime"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } # DEBUG INFO if { $BAIU_LOG_LVL >= 3 } { log local0.alert "IPreqCnt: [table lookup -notouch -subtable IPReqMon $b_ip ]" log local0.alert "IPbCnt: [table lookup -notouch -subtable IPbCnt $b_ip]" log local0.alert "IPbTime: [table lookup -notouch -subtable IPBanZ $b_ip]" # #log local0.alert "IP_limit_monitor tbl keys: [table keys -subtable $IP_MONITOR_TBL -notouch]" } ########################################################################### # Check if too many requests for a user ID if { $UIDreqCnt > $UIDMaxReqs } { # Set the short ban time and remove httpRequests set IPbTime $StdB set UIDbTime $HalfB table delete -subtable UIDReqMon $b_uid # Check UID ban levels and set ban times if { $UIDbCnt == "" } { table set -subtable IPbCnt $b_ip 1 $STime $STime table set -subtable UIDbCnt $b_uid 1 $LTime $LTime } else { table set -subtable IPbCnt $b_ip 1 $STime $STime set UIDbCnt [table incr -notouch -subtable UIDbCnt $b_uid] # Check if we need to ban them for longer if { $UIDbCnt > $MaxBs } { set IPbTime $StdB set UIDbTime $StdB } } # Ban them for $***bTime table set -subtable IPBanZ $b_ip 1 $IPbTime $IPbTime table set -subtable UIDBanZ $b_uid 1 $UIDbTime $UIDbTime # Clean up Hydra Tables table delete -all -subtable I2U$b_ip table delete -all -subtable U2I$b_uid # #table set -subtable $UID_MONITOR_TBL "$b_uid" "UID: $waf_uid; Ban:$UIDbTime secs" $UIDbTime if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_ip: $b_ip Banned for: $IPbTime"} if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ BANNING: b_uid: $b_uid Banned for: $UIDbTime"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } # DEBUG INFO if { $BAIU_LOG_LVL >= 3 } { log local0.alert "UIDreqCnt: [table lookup -notouch -subtable UIDReqMon $b_uid ]" log local0.alert "UIDbCnt: [table lookup -notouch -subtable UIDbCnt $b_uid]" log local0.alert "UIDbTime: [table lookup -notouch -subtable UIDBanZ $b_uid]" # #log local0.alert "UID_limit_monitor tbl keys: [table keys -subtable $UID_MONITOR_TBL -notouch]" } ########################################################################### # ... Sword - Single IP/UID Tracking/Banning ########################################################################### ########################################################################### # /// Hydra - Single to Many IP/UID Tracking/Banning - - Multi-Head Attack ########################################################################### # Set Single to many IPs/UIDs Counters set I2UCnt [table keys -subtable I2U$b_ip -count ] set U2ICnt [table keys -subtable U2I$b_uid -count ] # Disable if you have the All in One log at the end enabled # #if { $BAIU_LOG_LVL >= 1 } {log local0. "HYDRA_HEAD_CNT: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ I2UCnt: $I2UCnt U2ICnt: $U2ICnt b_ip: $b_ip b_uid: $b_uid"} ############################################################################ # Check if too many unique IPs have called a single UID # Uncomment one or both logs. Last 1 is best. if { $I2UCnt >= 2000 } { set IPbTime $StdB set UIDbTime $HalfB # ############################################################################ # Begin banning ALL (foreach) unique UIDs from single IP # foreach I2U_uid [table keys -subtable I2U$b_ip ] ### Put start brace here if using foreach!!!! # ############################################################################ # # Max Request Counts for IP calling multiple UIDs # #table set -subtable IPReqMon $b_ip 5000 $STime $STime # Ban IP calling multiple UIDs !!! Disabling to use set max request counts instead. table set -subtable IPBanZ $b_ip 1 $IPbTime $IPbTime table set -subtable IPbCnt $b_ip 1 $IPbTime $IPbTime # ## Ban all UIDs the single IP used. Could ban a lot of good accounts. # #table set -subtable UIDBanZ $I2U_uid 1 $UIDbTime $UIDbTime # ## Log item when blocking all UIDs used. # #if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_IP2UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ 2Many UIDs for 1 IP Banned b_ip: $b_ip for: $IPbTime & b_uid: $I2U_uid for: $UIDbTime"} ######### Put end brace here if using foreach!!!!!!!!!! iRule will not load if you put brace in incomplete string despite comment on end # Ban UID at time of ban. table set -subtable UIDBanZ $b_uid 1 $UIDbTime $UIDbTime # Clear table of tracking entry since IP & UID are now banned. table delete -all -subtable I2U$b_ip table delete -all -subtable U2I$b_uid # Clear Request monitor for UID & IP table delete -subtable IPReqMon $b_ip table delete -subtable UIDReqMon $b_uid if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_IP2UID: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ 2Many UIDs from 1 IP Banned b_ip: $b_ip for: $IPbTime & b_uid: $b_uid for: $UIDbTime"} # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" #@# # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } ############################################################################ # Check if too many unique UIDs have been called from a single IP # Uncomment one or both logs. Second is best. if { $U2ICnt >= 2000 } { set IPbTime $StdB set UIDbTime $HalfB ############################################################################ # Begin banning ALL (foreach) unique IPs that called single UID foreach U2I_tip [table keys -subtable U2I$b_uid ] { ############################################################################ # Ban all IPs used to call single UID table set -subtable IPBanZ $U2I_tip 1 $IPbTime $IPbTime table set -subtable IPbCnt $U2I_tip 1 $IPbTime $IPbTime # Max request counts & reset timers for all IPs used to call single UID #table set -subtable IPReqMon $U2I_tip 5000 $STime $STime # ## Standard log. Use 2nd if banning all IPs used for single UID. # #if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_UID2IP: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ 2Many IPs for 1 UID - Banned b_ip: $b_ip for: $IPbTime & b_uid: $b_uid for: $UIDbTime"} # Log item when blocking all IPs used. if { $BAIU_LOG_LVL >= 1 } {log local0. "BANNED_UID2IP: IP: $U2I_tip SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ 2Many IPs for 1 UID - Last IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] - Banned b_ip: $U2I_tip for: $IPbTime & b_uid: $b_uid for: $UIDbTime"} # ## Clear table of tracking entry since IPs are now banned. !!! Disabling to use set max request counts instead. # #table delete -all -subtable I2U$U2I_tip # ## Clear Request monitor for all IPs. !!! Disabling to use set max request counts instead. # #table delete -subtable IPReqMon $U2I_tip } # Clear table of tracking entry since UID is now banned. Put outside of (foreach) so command isn't repeated unnecessarily. table delete -all -subtable U2I$b_uid # Clear Request monitor for UID table delete -subtable UIDReqMon $b_uid # Ban UID called from multiple IPs table set -subtable UIDBanZ $b_uid 1 $UIDbTime $UIDbTime # Drop packets or send to 403 and reject rest. Uncomment only one response set at a time. # HTTP::respond 302 Location "http://www.example.com/notavail/en/403.html?id=yes" # Send 403 page and reject. HTML content and 403 response. #@# HTTP::respond 403 content { blocked } noserver # Send 403 page and reject. Close TCP connection so client can't make further requests otherwise will succeed (NEEDED for 403 content page) #@# reject # Drop packets and do not respond (504 no response from server) #drop # disable events for this connection event disable all return } ########################################################################### # ... Hydra - Single to Many IP/UID Tracking - Multi-Head Attack ########################################################################### ########################################################################### # /// Torch - Request Multiplier - Burn Them Down ########################################################################### # This section defines the attributes to be used with the $R8X multiplier for faster banning # Null values to identify which page has been called. These are used in the HTTP response to determine if a failed login attempt was made. If so the request count will add 1 doubling the count making them fail faster. set lp1 0 set lp2 0 set lp3 0 set lp4 0 ########################################################################### # Set the URIs to be used. We use lp values since we track on Login Pages. if { $buri equals "/wp-login.php" } { set lp1 1 } # if { $buri equals "/loginpage-3" } { # set lp2 1 # } # if { $buri equals "/loginpage-3" } { # set lp3 1 # } # if { $buri equals "/loginpage-4" } { # set lp4 1 # } } } } when HTTP_RESPONSE priority 643 { ########################################################################### # Check to see if a tracked URI is called. We use focus on Logins so we use the Login DG. if {$tip ne ""} { if { ( not [class match $buri equals XXX_LOGIN_URI ] ) } { return } } # Check which login page was used and then determine if the login failed or not. If failure, increase request counter by $R8X value # Most auth pages will work with this one because most auth pages use a 302 redirect for successful auth and usually a 200 for failure. if { $lp1 == 1 } { if { [HTTP::status] != 302 } { table incr -notouch -subtable IPReqMon $b_ip $R8X table incr -notouch -subtable UIDReqMon $b_uid $R8X set b_log 1 # Disable if you have the All in One log at the end enabled if { $BAIU_LOG_LVL >= 1 } {log local0. "BAD_LOGIN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ Multiplying Request Count $R8X times"} } } # # Another login page # if { $lp1 == 1 } { # if { [HTTP::cookie exists "SMSESSION" ] != 1 } { # table incr -notouch -subtable IPReqMon $b_ip $R8X # table incr -notouch -subtable UIDReqMon $b_uid $R8X # set b_log 1 # # Disable if you have the All in One log at the end enabled # if { $BAIU_LOG_LVL >= 1 } {log local0. "BAD_LOGIN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ Multiplying Request Count $R8X times"} # } # } # # Another login page # if { $lp2 == 1 } { # if { [HTTP::cookie exists "guestdata" ] != 1 } { # table incr -notouch -subtable IPReqMon $b_ip $R8X # table incr -notouch -subtable UIDReqMon $b_uid $R8X # set b_log 1 # # Disable if you have the All in One log at the end enabled # if { $BAIU_LOG_LVL >= 2 } {log local0. "BAD_LOGIN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ Multiplying Request Count $R8X times"} # } # } # # This is the login page for SignInFlyout # if { $lp2 == 1 } { # if { [HTTP::cookie exists "sid" ] != 1 } { # table incr -notouch -subtable IPReqMon $b_ip $R8X # table incr -notouch -subtable UIDReqMon $b_uid $R8X # set b_log 1 # # Disable if you have the All in One log at the end enabled # if { $BAIU_LOG_LVL >= 2 } {log local0. "BAD_LOGIN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ Multiplying Request Count $R8X times"} # } # } # # This is the login page for IWS # if { $lp3 == 1 } { # if { [HTTP::cookie exists "iwsLoggedIn" ] != 1 } { # table incr -notouch -subtable IPReqMon $b_ip $R8X # table incr -notouch -subtable UIDReqMon $b_uid $R8X # set b_log 1 # # Disable if you have the All in One log at the end enabled # if { $BAIU_LOG_LVL >= 2 } {log local0. "BAD_LOGIN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri - Multiplying Request Count $R8X times"} # } # } # # This is the login page for Mobile. This is also the landing page of the sign in page but CPID cookie is always there. # if { $lp4 == 1 } { # if { [HTTP::cookie exists "cpid" ] != 1 } { # table incr -notouch -subtable IPReqMon $b_ip $R8X # table incr -notouch -subtable UIDReqMon $b_uid $R8X # set b_log 1 # # Disable if you have the All in One log at the end enabled # if { $BAIU_LOG_LVL >= 2 } {log local0. "BAD_LOGIN: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri - Multiplying Request Count $R8X times"} # } else { # # Delete Hydra entries due to successful auth. # table delete -subtable I2U$b_ip $b_uid # table delete -subtable U2I$b_uid $b_ip # } # } ########################################################################### # ... Torch - Request Multiplier - Burn Them Down ########################################################################### # This combines BAIU_LOGIN_REQCNT, HYDRA_HEAD_CNT, and BAD_LOGIN into a single log line # You will want to disable those log items when using this. # # The first if statement for IPreqCnt and UIDreqCnt ensures first time requests for an # IP and UID together are not logged. This means the first auth attempt from a single # IP using a UID for the first time during the tracking window will not be logged. # This removes all logs for the first time successful events cutting down massive amounts of logs # while still logging 2nd and further attempts i.e. where security is interested. if { not ( [class match $tip equals R8L_GOOD_IP ] || [class match $waf_uid equals R8L_GOOD_UID ] ) && ( $method == "POST" && [class match $buri equals XXX_LOGIN_URI ] ) } { if { not ( $IPreqCnt equals "" && $UIDreqCnt equals "" ) } { if { $BAIU_LOG_LVL >= 1 } {log local0. "HYDRA_HEAD_CNTZ: IP: $tip EdgeIP: [IP::client_addr] VIP: [virtual name] SID: $sid~$jsid UID: $waf_uid HOST: $baiu_host URI: $buri ~ IPreqCnt: $IPreqCnt UIDreqCnt: $UIDreqCnt I2UCnt: $I2UCnt U2ICnt: $U2ICnt BadLogin: $b_log MonIP: $b_ip MonUID: $b_uid"} } } }