17-Jun-2022 06:27
Hello,
I've contacted AWS support regarding the WAF and your specific rule group, and AWS suggested I reach out here for specific questions regarding the F5 managed rule. I asked the following question:
We started to get exploit attempts on our production app, and were looking at the best way to block these attempts via a WAF rule.
This was caught from our app error checking vendor Rollbar:
ActionDispatch::Http::MimeNegotiation::InvalidType: "%{#context['com.opensymphony.xwork2.dispatcher.httpservletresponse'].addheader('gig54250'" is not a valid MIME type
ActionDispatch::Http::MimeNegotiation::InvalidType: "%{#context['com.opensymphony.xwork2.dispatcher.httpservletresponse'].addheader('5rvke1gt'" is not a valid MIME type (Most recent call first)
Exploit information:
https://blog.gdssecurity.com/labs/2017/3/27/an-analysis-of-cve-2017-5638.html
support rep advised:
I understand you observed attack attempts in your application that are exploiting the Apache Struts vulnerability (CVE-2017-5638) and are looking for a way to block these attempts via AWS WAF.
Kindly note that for the Apache Struts Vulnerability there is no AWS Managed rule available, however, you can make use of a marketplace rule group - "Common Vulnerabilities & Exposures (CVE) Rules" which are under "F5 managed rule groups"
We are currently subscribed to the F5 Common Vulnerabilities & Exposures (CVE) Rules, and have all of the rules turned on "Use action defined in the rule" e.g. not set to count. I see in CloudWatch metrics there are data points that show up for F5-CVE_Managed BlockedRequests, but I'm not seeing any logs in CloudWatch for that rule group. I want to be able to see more details in CloudWatch logs that corespond with the blocks in CloudWatch metrics, and it doesn't seem that this rulegroup is sending any logs to cloudwatch and only metrics. Especialy as noted from your documetation https://support.f5.com/csp/article/K21015971
Monitoring rule groups and rules
All rules and rule groups come with CloudWatch metrics that report the number of requests that matched a rule or rule group. When you use multiple rule groups, these metrics help discern which rules are being matched
Long story long, I need to be able to see in CloudWatch logs more details of what the rule group is blocking, and a query to do see that information.
Thank you!
19-Jun-2022 02:21 - edited 19-Jun-2022 02:26
Have you checked if you enabled logging in the AWS WAF ACL that sends the logs to cloudwatch?
https://docs.aws.amazon.com/waf/latest/developerguide/logging.html
Also note that if it is important site better go with F5 virtual edition, F5 silverline for AWS or the new F5 distributed cloud as the AWS WAF is for me simply the free open source mod_security waf for unix/linux and even with the F5 rules the AWS WAF is still just stateless old generation WAF with signatures.
Still if you chose it better in the future to send the logs with Kinesis Data Firehose to a syslog or SIEM server as Cloudwatch has capacity limit and the price to increase it is not small, so better not log the default action (if no rules are matched) as this will log just the illegal requests. There are many free open souce SIEM out there:
20-Jun-2022 07:37
Hi @Nikoolayy1,
Thanks for the reply. Yes I can confirm that the AWS WAF ACL is enabled and sending logs to Cloudwatch. However the only logs not available (that I can tell) are specifically F5 Common Vulnerabilities & Exposures (CVE) Rules. The metrics for that rule group are available, just not the logs. Thank you for your other suggestions, and that is something to consider, but for now I'm trying to view the logs in Cloudwatch for this particular rule group.
Thank you!
20-Jun-2022 08:28 - edited 20-Jun-2022 08:43
Maybe check the JSON config file for AWS WAF as the Visibility config should look like the example below:
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWS-AWSBotControl-Example"
https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-rule-group-settings.html
20-Jun-2022 14:13
config file looks good
"OverrideAction": {
"None": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "F5-CVE_Managed"
}
From your last comment though I was able to find some logs in cloudwatch using:
filter terminatingRuleId = "F5-CVE_Managed"
Now that I can see these logs in Cloudwatch I can check and see if the exploits are getting blocked.
Thank you for your help!
22-Jun-2022 14:12
I was finally able to find in the log entries for the exploit attempt and it looks like that it's not matching any of the rules in the rule groups especially not by F5-CVE_Managed. Since we don't control the rules in these rule groups what can I do to make sure these attemps (Apache Struts vulnerability (CVE-2017-5638)) are blocked by the F5-CVE_Managed rule group?
23-Jun-2022 01:44 - edited 23-Jun-2022 01:46
Generate such an attack and the default action should be "Block" and see that it is blocked and I do not think you will need to overide it as I mentioned it should be "Block" by default. This is it, you have less control with the AWS WAF and more with F5 Advanced WAF or Nginx + with App Protect WAF as cloud native services are like this.
23-Jun-2022 07:10
Hi @Nikoolayy1 , that's the thing, the attacks happen daily, but are getting allowed since they aren't getting picked up by the F5 rule. Since there is no control over the rule I wonder if there is something wrong with the rule group? How would I check?
23-Jun-2022 08:21 - edited 23-Jun-2022 08:28
@will-will I think I mentioned the limitations of the AWS WAF. You overide the default action to Block just in case or write your own rule to block the attack or check with the F5 support if you can open a case but I don't know any other way and this is why I stopped trying to use the AWS WAF even with F5 rules as it is too limited.
You can still also check the version of the rules or try the F5 AWS WAF Bot protection rules (I will not even try the AWS WAF native bot rules as changing the user agent header to a known web browser I managed to bypass it when I played with it)
https://docs.aws.amazon.com/waf/latest/developerguide/waf-managed-rule-groups-versioning.html
https://aws.amazon.com/marketplace/pp/prodview-p67737yco45uq
Still outside of that you can play with nginx + app protect or the F5 distributed cloud as they are not so expensive solutions and F5 cloud has a cheap plan like 25$ that Includes WAF rules or nginx app protect has trial version and so does F5 Advanced WAF and with BIG-IQ and F5 Cloud edtion it can autoscale as a native service (you can check with the F5 sales).
https://www.f5.com/cloud/pricing
https://www.nginx.com/pricing/
This is what I can help you and if someone has better ideas they can share them.
23-Jun-2022 10:43
Thank you @Nikoolayy1 for your advice. I think I'm going to make my own rule to block in the meantime, and open a support ticket with F5. Do you know how to open a ticket with F5 support, since they direct all support to this forum? Maybe I have to go through AWS support and they can open a ticket with F5.
18-Aug-2022 09:20
Hi will-will,
As a notice since we have not seen a response from the F5 support team on the subject I have flagged this thread to them so they can look into how to address these signatures in the managed rule set. No let's take a look at the attack you are describing and overlay that with the WAF security segment.
The AON article references two vectors. The first is a command injection via the Content-Type header
Vector 1
${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} |
The second is more nuanced attempting to interact with the struts platform containers
Vector 2
${(#_='multipart/form-data').(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Struts-Exploit-Test','GDSTEST'))}} |
We need to address both of these vectors (and permutations), and this is where it is important to understand that not all WAF engines have the same processing capabiliteis. Third party solutions, such as Advanced WAF, can leverage different broader and deeper processing capabilites. These differences can have a profound impact on the capabilites and thuse the breadeth and depth of vulnerablilities yoru organizaiton is exposed to.
All rule sets on AWS WAF have the same engine to apply their logic with.
We will look at three options for WAF.
AWS Managed Rules - on AWS WAF | F5 Managed Rules on AWS WAF | F5 Adv. WAF |
We will look at three result options
Block | Flagged | Pass |
Evaluating AWS WAF Engine with Different Rule Sets - Vector 1
Rule Set | Vector | Result |
Amazon Core Rule Set (OWASP) | ${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} | Pass |
Amazon Known Bad Inputs | ${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} | Block |
F5 Managed CVE | ${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} | Pass |
F5 Managed OWASP | ${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} | Pass |
Evaluating AWS WAF Engine with Different Rule Sets - Vector 2
Rule Set | Vector | Result |
Amazon Core Rule Set (OWASP) | ${(#_='multipart/form-data').(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Struts-Exploit-Test','GDSTEST'))}} | Pass |
Amazon Known Bad Inputs | ${(#_='multipart/form-data').(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Struts-Exploit-Test','GDSTEST'))}} | Pass |
F5 Managed CVE | ${(#_='multipart/form-data').(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Struts-Exploit-Test','GDSTEST'))}} | Pass |
F5 Managed OWASP | ${(#_='multipart/form-data').(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Struts-Exploit-Test','GDSTEST'))}} | Pass |
Evaulting F5 Advanced WAF - Vector 1 and Vector 2
WAF | ||
F5 Advanced WAF | Vector 1 - ${(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} |
Block |
F5 Advanced WAF | Vector 2 - ${(#_='multipart/form-data').(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Struts-Exploit-Test','GDSTEST'))}} |
Flag |
I hope this helps.