On September 5, 2017, Apache Struts released the latest security bulletin announcing that the REST plug-in in Apache Struts 2.5.x and some 2.x versions is prone to a high-risk remote code execution vulnerability, which has been assigned CVE-2017-9805 (S2-052). When using an XStream handler with an instance of XStream for deserialization, the REST plug-in does not perform any type filtering, thereby causing remote code execution.
According to the official description, when the REST plug-in uses an XStream handler to handle XML data, it does not perform any filtering before converting the XML data to objects in the deserialization process, leading to remote code execution.
Users can download all source code packages from the official website (https://archive.apache.org/dist/struts/2.5/struts-2.5-all.zip) and then directly deploy struts2-rest-showcase.war onto Tomcat. I prefer manual compilation using Maven. During deployment, note that, due to the javax.imageio dependency, the version of JDK must be JDK8 or later. Some earlier versions of JDK8 do not support the deployment. Here, jdk8_102 is used as an example for vulnerability verification.
Let’s have a look at the related configurations of the REST plug-in.
As shown in the preceding figure, the XStream handler uses the default method, Content-Type:xml, to process file handles. Therefore, the REST plug-in is prone to XStream deserialization vulnerability.
In the official solution, data (collection data, map data, basic class data, and time class data) in the XML document is whitelisted, in a bid to prevent bringing in harmful operations during XStream deserialization.
Currently, the public Proof of Concept (PoC) is based on javax.imageio, which can execute commands locally. However, marshelsec provides 11 XStream deserialization libraries, most of which are based on JNDI, including CommonsConfiguration, Rome, CommonsBeanutils, ServiceLoader, ImageIO, BindingEnumeration, LazySearchEnumeration, SpringAbstractBeanFactoryPointcutAdvisor, SpringPartiallyComparableAdvisorHolder, Resin, and XBean. External request class data is used for deserialization.
The following figure shows simple verification and analysis. As shown in the PoC, the request method is PUT; the URL contains the “xml” extension; Content-Type of the request is delicious/bookmark+xml; the prefix of the requested XML is <set>.
The following figure shows the execution call stack that triggers the vulnerability.
XStreamHanler.toObject calls fromXml of XStream for deserialization.
Use a compression tool to open the JAR package. Here struts2-rest-plugin-2.5.10.1.jar is used as an example.
Extract struts-plugin.xml, modify the settings as required, and then put it back into the compressed package.
After XML resolution is stopped, a request for accessing a URL containing xml will return an HTTP 404 error, indicating that XML data cannot be resolved.
Following is the test case. In our PoC, the POST request does not contain the “xml” extension. XStream relates only to Content-Type. If Content-Type values include xml, this type of data will be handed over to XStream for handling. Therefore, the PoC works regardless of whether xml is included as a content type.
The calculator successfully pops up as expected. In addition, by comparing two different PoCs, we find that Content-Type supports a number of XML formats. A POST, PUT, GET, or even a custom request can trigger the vulnerability. Even if we change <map><entry> to <set>, the vulnerability can still be triggered. Worse still, there are as many as 11 PoCs related to XStream. It is understandably difficult to protect against this vulnerability.
Apache has released updates to fix this vulnerability. Users of the affected applications are advised to upgrade as soon as possible.
Add an XML filter to filter out requests whose Content-Type is “application/xml”. This, however, will indiscriminately cause all such requests to fail. Therefore, it can be used only as a temporary solution.
After creating this filter, conduct a PoC test. The test result proves that matched requests can be blocked.