6

During an assessment of an android application I discovered a file which contained serialized data from a standard call to ObjectOutputStream.writeObject(). A string serialized in the data is potentially under attacker control. I wonder if it is possible to create an input that breaks out of the delimiters that start and end the string such that I can write arbitrary values into the file and have them executed by the consuming application on load, possibly via a gadget chain. Does any reader know of such a technique?

  • 2
    I can't speak to Java specifically, but in programming in general, the answer is typically no. When you generate a raw data element what's inside of it can't execute because the process to encode it should know to keep delimiters out of scope. The biggest danger is if the data has an opportunity to execute or be reinterpreted latter. For example, if I put HTML into an unsanitized text field, and someone tries to read that with a browser, it will run because the browser executes HTML by design. – Nosajimiki Nov 21 '18 at 18:38
  • 1
    That said, I believe Java specifically has a bad reputation of being vulnerable to buffer overflows which can be used to push code into other parts of your stack that can execute doing things you don't expect to be possible. So, you should always make sure to enforce limiters and/or canaries on all of your user input. – Nosajimiki Nov 21 '18 at 18:42
3

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.

  • 1
    Yep, that's exactly what my subsequent research lead me to believe. Because strings are not stored inside delimiters, but with a header value indicating their length, breaking out of a serialised string by bypassing delimiters doesn't seem possible. I found this out by looking at the source code of github.com/NickstaDB/SerializationDumper – Orphid Nov 22 '18 at 18:12
  • 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? – Gewure Nov 25 '18 at 19:34
  • 1
    @Gewure I think that's a common myth that the keyword private actually enforces any security. I updated my answer to address your comment. – Mike Ounsworth Nov 26 '18 at 17:28
  • @MikeOunsworth yes, you are right, just checked it out. – Gewure Nov 26 '18 at 23:01
0

Definitely such serialised string may expose some vulnerability, not necessarily as buffer overflow. If the suspect can manipulate the serialised data directly, the concern becomes very real. If he can pass an arbitrary string to serializer, the situation requires analysis, but isn't that bad.

Special attention should be devoted to embedded emojis that may not be mapped correctly on the system (remember the Taiwan flag bug that crashed iOS devices).

  • 1
    Can you provide an example input string that illustrates how this might be achieved? I'm not looking for a successful attack against this specific application, just an example of how breaking out of the string into java binary data might be done. – Orphid Nov 21 '18 at 19:55
  • 1
    Good point bringing up deserialization issues. Hackers can input characters in such a fashion that what you put in is not what you get out. For example, adding (char)32 to an input string may deserialize to a close quote if you don't handle it properly. If you are doing something like building concatenated SQL strings from those inputs or converting it back into a serialized string later in your code, then you could have a very big problem. – Nosajimiki Nov 21 '18 at 20:59
  • No, I don't have examples of actually breaking ObjectOutputStream. But there may be other effects. The Taiwan flag crash is one. Embed LF characters in the string, the display may go nuts. Embed \u202e and on output, instead of $52, the user will see $25. Consider usual cases of synax injection, like xkcd.com/327. – Alex Cohn Nov 21 '18 at 22:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.