on 07-Mar-2017 10:50
Problem this snippet solves:
F5 has updated the official KB article K43451236 on AskF5 to include an enhanced version of the iRule below that will protect your vulnerable web servers behind the BIG-IP that will mitigate Apache strut2 vulnerability, cve-2017-5638
How to use this snippet:
Add the irule to a virtual server.
Irule below contributed by LinJing.
Code :
# Contributed by LinJing when HTTP_REQUEST { if {([HTTP::header exists "Content-Type"])}{ set ctheader [string tolower [HTTP::header "Content-Type"]] if {($ctheader contains "multipart/form-data") and (($ctheader contains "'") or ($ctheader contains "ognl") or ($ctheader contains "java.lang") or ($ctheader contains "bash") or ($ctheader contains "cmd") or ($ctheader contains "org.apache")) }{ log local0. "Found Struts S2-045 attack! Rejecting a request with Content-type [HTTP::header "Content-Type"] to [HTTP::uri] from [IP::client_addr]" #if you do not want to reset the connection, then comment out the lien below reject } } }
Thank you. May I ask what the script might look like if I wanted to also look for GET or any other/multiple HTTP Method? Would it be a separate IF line for each Method or is there a 'wildcard' that can be used?
thank you
For what it might be worth. We mocked an attack with this exploit by using the PoC found on the net. When we targeted a known server that was vulnerable before we patched it, we found that our current Attack Signature database (We're on version 11.x) was already protecting against CVE-2017-5638
These are the Attack Signatures that detected the attempted exploit Code Injection Java (Accessing attributes) Java Code Injection (java packages) (Header) "/bin" execution attempt (Headers)
hth
Someone just reported that this irule causes a false positive when the Content-Type header includes a boundry string:
Content-Type: multipart/form-data; boundary=-------2c5ad0c0c449
Also note that the F5 ASM (WAF) has built-in signatures that mitigates this.
Here is a modified version which takes care of false positive mentioned above, removes the POST request checking and, adds a few more values to the white-list.
 
Inspecting Content-Type from GET requests requires a much larger white-list and increases the chance for blocking legitimate requests. It also reduces the effectiveness of this iRule and therefore this iRule is not to be trusted to provide complete protection. White-listing values may not be good for all applications.
 
The best protection is using a WAF. Check here.
 
WARNING: the iRule below can produce false-positives and block legitimate traffic. Make sure you adjust the list of Content-types for you application before relying on this iRule.
 
when HTTP_REQUEST {
switch -glob -- [string tolower [HTTP::header value "Content-Type"]] {
"" -
"multipart/form-data" -
"text/xml; charset=utf-8" -
"text/???" -
"text/javascript" -
"image/??? -
"image/jpeg" -
"text/html" -
"multipart/form-data; boundary=*" -
"application/x-javascript" -
"application/x-www-form-urlencoded" {
Allow request with empty or white listed "Content-Type" headers
}
default {
Reject request with unknown "Content-Type" headers
reject
log local0. "Rejecting a request with Content-type [HTTP::header Content-Type] to [HTTP::uri] from [IP::client_addr]"
}
}
}
FWIW, the vulnerability can be executed via GET requests, as I've seen in the Qualys report on it. I've confirmed this on some systems under my control.
Todd's comment is correct. Here is a revised version of the irule that I believe will address this:
when HTTP_REQUEST {
if { [HTTP::method] equals "POST" || [HTTP::method] equals "GET" } {
switch -glob -- [string tolower [HTTP::header value "Content-Type"]] {
"" -
"multipart/form-data; boundary=*" -
"multipart/form-data" -
"text/xml" -
"text/xml; charset=utf-8" -
"application/x-www-form-urlencoded" {
Allow request with empty or white listed "Content-Type" headers
}
default {
Reject request with unknown "Content-Type" headers
reject
}
}
}
}
Maybe white list the value is not a good idea since there are so many. Some users reported their application is broke after applying the irule. We found the values below.
application/x-java-serialized-object application/json
Agreed, white-listing only works for some applications and only if you can modify the iRule to fit that app.
Here is another iRule that can block most but NOT all attacks. This irule is based on attack signatures that be been seen.
If you decide to use this iRule please test it thoroughly against your application to make sure it does not block legitimate requests.
when HTTP_REQUEST {
if {([HTTP::header exists "Content-Type"])}{
set ctheader [string tolower [HTTP::header "Content-Type"]]
if {($ctheader contains "multipart/form-data") and (($ctheader contains "'") or ($ctheader contains "ognl") or ($ctheader contains "java.lang") or ($ctheader contains "bash") or ($ctheader contains "cmd") or ($ctheader contains "org.apache")) }{
log local0. "Found Struts S2-045 attack! Rejecting a request with Content-type [HTTP::header "Content-Type"] to [HTTP::uri] from [IP::client_addr]"
if you do not want to reset the connection, then comment out the lien below
reject
}
}
}
Here is another irule that reference a famous FW vendor's sig, Pls test:
when HTTP_REQUEST {
if {([HTTP::header exists "Content-Type"])}{
set ctheader [string tolower [HTTP::header "Content-Type"]]
if {($ctheader contains "multipart/form-data") and not($ctheader starts_with "multipart/form-data")}{
log local0. "Found Struts S2-045 attack! Rejecting a request with Content-type [HTTP::header "Content-Type"] to [HTTP::uri] from [IP::client_addr]"
if you do not want to reset the connection, then comment out the lien below
reject
}
}
}
The RCA is the function 'findText' will execute the injection code. That means, before execute the injection code, attacker need to trigger an exception.
Thus, the necessary and sufficient conditions are as below:
(refer to: https://cwiki.apache.org/confluence/display/WW/File+UploadFileUpload-AlternateLibraries)
This maybe explained why the FW vendor's sig is using starts_with like below (currently, most PoC codes are added additional characters in the beginning of Content-Type):
if {($ctheader contains "multipart/form-data") and not($ctheader starts_with "multipart/form-data")}{
I suspect that if modify the PoC string like 'haha%{}multipart/form-data' or 'multipart/form-datahaha%{}' may have same result. That means 'starts_with' may not be exact enough for block the injection. Therefore, I would prefer to choose Linjing's irule. It would be better.