Is breaking out of a Java binary serialized string possible?

Let's look at what a serialized String actually looks like when serialized to a byte array. I grabbed sample code from this guide.

Code:

// Java code for serialization and deserialization
// of a Java object
import java.io.*;

class Demo implements java.io.Serializable
{
    public String s;

    // Default constructor
    public Demo(String s)
    {
        this.s = s;
    }
}

class Test
{
    public static void main(String[] args)
    {
        Demo object = new Demo("helloWorld");
        String filename = "file.ser";

        // Serialization
        try
        {
            //Saving of object in a file
            FileOutputStream file = new FileOutputStream(filename);
            ObjectOutputStream out = new ObjectOutputStream(file);

            // Method for serialization of object
            out.writeObject(object);

            out.close();
            file.close();

            System.out.println("Object has been serialized");
        }
        catch(IOException ex)
        {
            System.out.println("IOException is caught");
        }
    }
}

If I look at the serialized binary file file.ser I see: (in a text editor that property handles binary, uploading a screenshot because the SE editor won't handle the non-printable chars properly)

Binary of a serialized java String

If we break that down, we see:

  1. The name of the serialized object: Demo
  2. The name of the serialized member object: java/lang/String
  3. The data of this object: helloWorld

Summary:

If you are only allowing the attacker to modify the contents of the String (ie "helloWorld", then no, I don't believe it is possible to break out. However, if you are allowing the attacker to modify the entire byte stream, then they can replace the class name (ie "java/lang/string") with whatever gadget class they want and compromise your application.


UPDATE to address this comment:

isn't that where visibility comes in handy for security? e.g. if the 'injected' class is not in the package or private .. no chance of accessing it. am i right?

I would say no. I'm not an expert, but my understanding is that the deserialization code is part of the core JVM and therefore completely ignores access modifiers like protected, private. Proof of concept, consider a serializable class with a private member:

class Demo implements java.io.Serializable
{
    public String pub;
    private String priv;

    // No-args constructor
    public Demo() {
      pub = "Public data";
      priv = "Private data";
    }
}

When you serialize this and send it over the network, you need to include the private member, and the deserializer at the other end needs to be able to re-construct it:

Binary data of a serialized java object with a private member

Let's shake the myth that the java keyword private has anything to do with security. It's a way for the developer who wrote the class to say "Hey, you shouldn't be accessing this directly" to the developer using the class, but in no way prevents you from using java reflection to read / modify private members or classes nor does it prevent data in private members or classes from being serialized / deserialized.