DoS and NTLM Brute force protection for HTTP(s) traffic
Problem this snippet solves: This snippet has been designed to mainly protect against NTLM's Denial of Service and brute force attacks against web application that use this authentication mecanism. This irule help companies to fight against brute force attacks at the HTTP layer. You can combine this irule with another one on non-http traffic to provide a brute force protection across multiple layers. For pure HTTP application, you should prefer the Brute force protection provided by the ASM module. How to use this snippet: This irule should be installed on each Virtual Server that require NTLM protection. In a Microsoft Skype for Business deployment, you may need to protect following services : Web Services Conf Autodiscover Exchange Web Services TO BE DONE : Provide a way to unlock blocked users External links Github : https://github.com/e-XpertSolutions/f5 Related Articles DoS and NTLM Brute force protection for SIP flow Credits This irule is based on NTLM logger Code : when RULE_INIT { array set NTLMFlags { unicode 0x00000001 oem 0x00000002 req_target 0x00000004 unknown1 0x00000008 sign 0x00000010 seal 0x00000020 datagram 0x00000040 lmkey 0x00000080 netware 0x00000100 ntlm 0x00000200 unknown2 0x00000400 unknown3 0x00000800 ntlm_domain 0x00001000 ntlm_server 0x00002000 ntlm_share 0x00004000 NTLM2 0x00008000 targetinfo 0x00800000 128bit 0x20000000 keyexch 0x40000000 56bit 0x80000000 } set static::irule_name "irule-ntlm-bruteforce" set static::email_domain "domain.com" set static::user_domain "DOMAIN" set static::log_server "" set static::log_pri "local0." set static::fail_tab "NTLMfails" set static::blacklist_tab "NTLMblackhole" set static::userfail_tab "NTLMUserfails" set static::userblacklist_tab "NTLMUserblackhole" set static::max_failures 5 set static::fail_memory 300 set static::block_duration 300 } when CLIENT_ACCEPTED { if {[table lookup -subtable $static::blacklist_tab [IP::client_addr]] == 1} { log $static::log_pri "[virtual] - BLACKHOLED IPADDR [IP::client_addr]:[TCP::client_port] (Reputation=[IP::reputation [IP::client_addr]])" reject return } } when HTTP_REQUEST { if {[table lookup -subtable $static::blacklist_tab [IP::client_addr]] == 1} { log $static::log_pri "[virtual] - BLACKHOLED IPADDR [IP::client_addr]:[TCP::client_port] (Reputation=[IP::reputation [IP::client_addr]])" reject return } if {[HTTP::header Authorization] starts_with "NTLM "} { set ntlm_msg [ b64decode [split [lindex [HTTP::header Authorization] 1] ] ] binary scan $ntlm_msg a7ci protocol zero type if { $type eq 3 } { binary scan $ntlm_msg @12ssissississississii \ lmlen lmlen2 lmoff \ ntlen ntlen2 ntoff \ dlen dlen2 doff \ ulen ulen2 uoff \ hlen hlen2 hoff \ slen slen2 soff \ flags set ntlm_domain {}; binary scan $ntlm_msg @${doff}a${dlen} ntlm_domain set ntlm_user {}; binary scan $ntlm_msg @${uoff}a${ulen} ntlm_user set ntlm_host {}; binary scan $ntlm_msg @${hoff}a${hlen} ntlm_host set unicode [expr {$flags & 0x00000001}] if {$unicode} { set ntlm_domain_convert "" foreach i [ split $ntlm_domain ""] { scan $i %c c if {$c>1} { append ntlm_domain_convert $i } elseif {$c<128} { set ntlm_domain_convert $ntlm_domain_convert } else { append ntlm_domain_convert \\u[format %04.4X $c] } } set ntlm_domain $ntlm_domain_convert set ntlm_user_convert "" foreach i [ split $ntlm_user ""] { scan $i %c c if {$c>1} { append ntlm_user_convert $i } elseif {$c<128} { set ntlm_user_convert $ntlm_user_convert } else { append ntlm_user_convert \\u[format %04.4X $c] } } set ntlm_user $ntlm_user_convert set ntlm_host_convert "" foreach i [ split $ntlm_host ""] { scan $i %c c if {$c>1} { append ntlm_host_convert $i } elseif {$c<128} { set ntlm_host_convert $ntlm_host_convert } else { append ntlm_host_convert \\u[format %04.4X $c] } } set ntlm_host $ntlm_host_convert } binary scan $ntlm_msg @${ntoff}a${ntlen} ntdata binary scan $ntlm_msg @${lmoff}a${lmlen} lmdata binary scan $ntdata H* ntdata_h binary scan $lmdata H* lmdata_h set interesting 1 if { ($ntlm_domain equals $static::user_domain or [string tolower $ntlm_user] ends_with $static::email_domain) } { set attack 1 if {[table lookup -subtable $static::userblacklist_tab $ntlm_user] == 1} { # Block ntlm_user exceeding the number of failed logons in the timeout period log $static::log_pri "[virtual] - BLACKHOLED $ntlm_domain\\$ntlm_user from $ntlm_host at [IP::client_addr]:[TCP::client_port] (Reputation=[IP::reputation [IP::client_addr]])" reject return } else { log $static::log_pri "[virtual] - Login attempt by $ntlm_domain\\$ntlm_user from $ntlm_host for [HTTP::uri]." } } else { set attack 0 log $static::log_pri "[virtual] - Not a valid user - Login attempt by $ntlm_domain\\$ntlm_user from $ntlm_host for [HTTP::uri]." } return [list type $type flags [format 0x%08x $flags] \ ntlm_domain $ntlm_domain ntlm_host $ntlm_host ntlm_user $ntlm_user \ lmhash $lmdata nthash $ntdata] } } } when HTTP_RESPONSE { if {[info exists interesting] && $interesting == 1} { set client [IP::client_addr]:[TCP::client_port] set node [IP::server_addr]:[TCP::server_port] set nodeResp [HTTP::status] if { $nodeResp == 401 and ([info exists attack] and $attack == 1)} { log $static::log_pri "[virtual] - invalid credentials detected for $ntlm_user" table set -subtable $static::fail_tab -notouch -excl [IP::client_addr] 0 indef $static::fail_memory table incr -subtable $static::fail_tab [IP::client_addr] if {[table lookup -subtable $static::fail_tab [IP::client_addr]] >= $static::max_failures} { set now [clock seconds] set now_date [split [clock format $now -format {%X %x}] " "] set later [expr {$now + $static::block_duration}] set later_date [split [clock format $later -format {%X %x}] " "] log $static::log_pri "[virtual] - BLACKHOLING IPADDR - [IP::client_addr] (Reputation=[IP::reputation [IP::client_addr]]) at $now_date until $later_date" table set -subtable $static::blacklist_tab -excl [IP::client_addr] 1 indef $static::block_duration } if {[info exists ntlm_user]} { table set -subtable $static::userfail_tab -notouch -excl $ntlm_user 0 indef $static::fail_memory table incr -subtable $static::userfail_tab $ntlm_user if {[table lookup -subtable $static::userfail_tab $ntlm_user] >= $static::max_failures} { set now [clock seconds] set later [expr {$now + $static::block_duration}] log $static::log_pri "[virtual] - BLACKHOLING USER - $ntlm_user at $now_date until $later_date" table set -subtable $static::userblacklist_tab -excl $ntlm_user 1 indef $static::block_duration } } } } } Tested this on version: 11.5868Views0likes3CommentsNTLM Authenticated Proxy External Monitor
Problem this snippet solves: NTLM Authenticated Proxy External Monitor How to use this snippet: This monitor is used to monitor the availability of a web page through a NTLM authenticated proxy. The default HTTP monitor relies on receiving a 401 Authenticate message to trigger the NTLM handshake, proxies respond with a 407 Proxy Authenticate message instead, which causes the monitor to fail. Set the following variable: URI-The requested host/page to send the request to. (e.g. www.host.com/page1 or https://www.host.com/page.html) USER-Proxy Username PASS-Proxy Password RECV-Receive String to look for Code : #!/bin/sh # #Name:external_monitor_NTLM_Proxyauth #Author:Matt Elkington #Contact:melkington@integrity360.com #Date:23/01/2017 #Description:An external monitor to allow monitoring of a host through a NTLM Authenticated proxy #This is to work around the fact that the standard http monitor will only use NTLM if #it receives a 401 Authenticate message and ignores a 407 Proxy Authenticate message # #Change Log #VersionChangeDate #1.0Initial Monitor23/01/2017 # # #Port and IP address are supplied automatically a variables $1 and $2 byt the LTM: #$1 = IP (nnn.nnn.nnn.nnn notation) #$2 = port (decimal, host byte order) # #The following variables must be set in the monitor definitation: # #URI-The requested host/page to send the request to. (e.g. www.host.com/page1 or https://www.host.com/page.html) #USER-Proxy Username #PASS-Proxy Password #RECV-Receive String to look for # # remove IPv6/IPv4 compatibility prefix (LTM passes addresses in IPv6 format) NODE=`echo ${1} | sed 's/::ffff://'` PORT=${2} PIDFILE="/var/run/`basename ${0}`.${NODE}_${PORT}.pid" # kill of the last instance of this monitor if hung and log current pid if [ -f $PIDFILE ] then echo "EAV exceeded runtime needed to kill ${IP}:${PORT}" | logger -p local0.error kill -9 `cat $PIDFILE` > /dev/null 2>&1 fi echo "$$" > $PIDFILE # send request & check for expected response curl ${URI} --proxy ${NODE}:${PORT} -U ${USER}:${PASS} --proxy-ntlm -k | grep -i "${RECV}" 2>&1 > /dev/null # mark node UP if expected response was received if [ $? -eq 0 ] then # Remove the PID file rm -f $PIDFILE echo "UP" else # Remove the PID file rm -f $PIDFILE fi exit Tested this on version: 11.6664Views0likes0Comments