NGINX Full Version

使用 ModSecurity 虚拟修补 Apache Struts CVE-2017-5638 漏洞

Many security vulnerabilities are found in libraries used by application code. When it’s impractical to quickly deploy a fix to code in a library, you may be able to use ModSecurity to intercept an exploit, “virtually patching” the affected code until you can upgrade the affected libraries.

The Apache Struts application library vulnerability (CVE-2017-5638), which led to the breach of 143 million accounts at Equifax, is an example of exploit that can be virtually patched. The signature of the vulnerability is the presence of #cmd= or #cmds= strings in the Content-Type, Content-Disposition, or Content-Length HTTP headers. (For more details, see below.)

Using ModSecurity, we can create a virtual patch with a simple rule that searches for the malicious strings in the affected HTTP headers:

SecRule REQUEST_HEADERS:Content-Type|REQUEST_HEADERS:Content-Length|REQUEST_HEADERS:Content-Disposition "@rx #cmds?=" "id:5638,auditlog,log,deny,status:403"

We define the rule with SecRule, providing three parameters:

  1. The request headers to search for, in the form of three REQUEST_HEADERS variables OR’ed together
  2. The PERL‑compatible regular expression (PCRE), as specified by @rx, that searches the specified request headers for strings including #cmd= or #cmds=
  3. The action to take

If ModSecurity is configured in active blocking mode, it drops any traffic that matches the PCRE and so triggers the rule.

Learn how to get started using NGINX and ModSecurity together with our ebook: ModSecurity 3.0 and NGINX: Quick Start Guide

Why Virtual Patch?

In a lot of cases it’s quicker to deploy a rule in ModSecurity than to patch the affected code, re‑test, and then deploy to production.

Consider the Apache Struts vulnerability as an example: because Struts is an application library and not an operating system package, updating it in an enterprise production environment can take some time. As part of upgrading to a new version of Struts, each Struts‑dependent application needs to be rebuilt and tested with the latest Struts library. A large organization might have hundreds of applications, each with its own version of the Struts application library, making it vulnerable until every single application is updated.

With the ModSecurity custom rule in place, you can then patch the production software carefully, and on a reasonable schedule, without the pressure of being vulnerable. Once all the affected software is updated, the custom rule can be decommissioned.

How the CVE-2017-5638 Exploit Works

Apache Struts CVE-2017-5638 is a remote command execution (RCE) vulnerability. This type of vulnerability allows the attacker to run arbitrary commands, such as /bin/bash or cmd.exe, on target systems. With that ability, the attacker can then search the file system and the network for sensitive data, with the same level of access as the Java application server. For example, if the Java application server is running as root, then the attacker has root privileges on the target system.

According to the official CVE, the vulnerability occurs when an attacker sends a malformed Content-Type, Content-Disposition, or Content-Length HTTP header. Apache Struts throws an exception when those HTTP headers don’t match any of the expected values. The problem occurs because the exception‑handling code attempts to print the unescaped, invalid header. (In this context, “unescaped” means that the suspect commands are not prepended with characters that prevent them from being executed – escape characters – as is normally done when printing code.)

The attacker can put an Object Graph Navigation Library  (OGNL) expression into the Content-Type header. OGNL has the ability to run system commands. When the unescaped, invalid header is printed, the OGNL expression is evaluated, and any system commands within the OGNL expression are executed.

Exploits typically are a variation on the curl command below.

curl -H "Content-Type:%{(#_='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='ls -ltr').(#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())}" www.example.com

The key syntax is in the second half of the command: one instance each of the strings #cmd= and #cmds= (highlighted above). Each of the strings is followed by the system command to run.

Summary

The preferred solution is always to patch vulnerable software right away. But patching production software can be time‑consuming, and rushing updates can be risky. Creating a virtual patch for vulnerable software with ModSecurity can buy time.

With virtual patching, you create a custom ModSecurity rule to block traffic that might exploit the security vulnerability, such as CVE-2017-5638. By doing so, you protect your site from the attack. You can then patch the production servers carefully, and on a reasonable schedule, without the fear of being victimized in the meantime.

If you’d like to learn more about ModSecurity and the NGINX WAF, please download our ebook, ModSecurity 3.0 and NGINX: Quick Start Guide.

Resources