Using ModSecurity to Virtually Patch Apache Struts CVE-2017-5638

Faisal Memon Thumbnail
Faisal Memon
Published January 22, 2018

[Editor – The NGINX ModSecurity WAF module for NGINX Plus officially went End-of-Sale as of April 1, 2022 and is transitioning to End-of-Life effective March 31, 2024. For more details, see F5 NGINX ModSecurity WAF Is Transitioning to End-of-Life<.htmla> on our blog.]

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('').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())).(,#ros)).(#ros.flush())}"

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.


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 NGINX ModSecurity WAF, please download our eBook, ModSecurity 3.0 and NGINX: Quick Start Guide.


[The NGINX ModSecurity WAF module for NGINX Plus officially went End-of-Sale as of April 1, 2022 and is transitioning to End-of-Life effective March 31, 2024. For more details, see F5 NGINX ModSecurity WAF Is Transitioning to End-of-Life<.htmla> on our blog.]

"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous links will redirect to similar NGINX content on"