Forum Discussion

melcaniac's avatar
melcaniac
Icon for Cirrus rankCirrus
Sep 20, 2010

iRule to address Microsoft Security Advisory (2416728)

Has anyone tried to address this security vulnerability with an iRule?

 

 

For more information:

 

 

Microsoft Security Advisory (2416728)

 

Vulnerability in ASP.NET Could Allow Information Disclosure

 

http://www.microsoft.com/technet/security/advisory/2416728.mspx

 

 

There is also a well written blog by Scott Guthrie (Corporate Vice President at Microsoft Corp.) on this topic.

 

http://weblogs.asp.net/scottgu/archive/2010/09/18/important-asp-net-security-vulnerability.aspx

 

 

 

In order to mitigate this, it is recommended that you change all the custom error definitions to always return the exact same page for various error conditions. In addition, the error page we send them to needs to have a random delay in it.

 

 

This seems like a perfect case for an iRule to address this issue. Handling the custom HTTP response is easy with an iRule, but including the random delay is something I am unfamiliar with and I wanted to know if anyone has attempted this already.

 

 

 

 

  • Seems like you could easily use rand() to randomize the delay but that's not how I'd do it.

     

     

    1) Have a "when HTTP_RESPONSE" event look for error codes and send a 302 to a custom error page.

     

    2) Have a "when HTTP_RESPONSE" event look for error codes and send a 200 along with the actual HTML from the LTM.

     

     

    Either way we avoid sending the user a pre-canned 404 or 500.
  • Here's what I have so far, but apparently the after TCL command is not available on the 9.x platform. Is there a sleep command or some type of delay that I can use in 9.x?

     

     

    when RULE_INIT {

     

    set ::basedelay 2000

     

    }

     

     

    when HTTP_RESPONSE {

     

    if { [HTTP::status] starts_with "5"} {

     

     

    after [$basedelay + [expr { int(10000 * rand()) }]]

     

     

    HTTP::respond 500 content {

     

     

    Temporary Failure

     

     

     

     

     

    There was an error.

     

     

     

    }

     

    }

     

    }

     

  • Yeah, but we still are not adding in the random delay which my boss really wants to do. Thanks for your assistance though!
  • Answered in the blog comments, but the error is in your math, you need two expr statements. No need to set the variable, so I'd just avoid it altogether.

     

     

    after [expr [expr { int(10000 * rand()) }] +2000]
  • I don't presently have access to test this with an F5, but I bashed this out whilst travelling. This should work on 9.x and 10.x to stop the exploit actions (which are based on repeated brute-force attempts to ASP.net script-handler calls in WebResource.axd or ScriptResource.axd).

    This is based on a previous HTTP request throttle iRule, but I've altered it to track only failed calls to ASP.net functions. This should detect HTTP failures occurring en-masse.

    when HTTP_REQUEST {
            
        set aspnet_object call 0
        set expiration_time 300
        set client_ip [IP::client_addr]
        set req_limit 1000
        set curr_time [clock seconds]
        set timekey starttime
        set reqkey reqcount
        set failed_request_count [session lookup uie $reqkey]
    
        if { ([string tolower [HTTP::uri]] starts_with "/scriptresource.axd?") || ([string tolower [HTTP::uri]] starts_with "/webresource.axd?") } {
            set aspnet_object_call 1
        }
        if { ($aspnet_object_call) && ($failed_request_count eq "") } {
            set failed_request_count 1
            session add uie $reqkey $failed_request_count $expiration_time
            session add uie $timekey [expr {$curr_time - 2}] [expr {$expiration_time + 2}]
        } elseif {($aspnet_object_call)} {
            set start_time [session lookup uie $timekey]
            if { ($failure_response) } {
               incr failed_request_count
               session add uie $reqkey $failed_request_count $expiration_time
               set failure_response 0
            }
            set elapsed_time [expr {$curr_time - $start_time}]
      
            if {$elapsed_time < 60} {
                set elapsed_time 60
            }
    
            set curr_rate [expr {$failed_request_count / ($elapsed_time/60)}]
    
            if {$curr_rate > $req_limit}{
                log local0. "ASP.net brute force detected from $client_ip."
                reject
            }
        }        
    }
    
    when HTTP_RESPONSE {
        if { ($aspnet_object_call) && (([HTTP::status] matches_glob "4[0-9][023456789]") || ([HTTP::status] matches_glob "5*")) } {
            set failure_response 1
        } elseif { ($aspnet_object_call) && ([HTTP::status] equals "200") } {
            set failure_response 0
        }
    } 

    Like I said, I don't have access to an F5 to test this, so if someone could try it'd be nice.