Several months ago, the Constrast Security Team reported a Java deserialization vulnerability about Spring Kafka to VMWare Security Team. It immediately attracted my attention and I got started to analyse this bug. If you are interested in it, you could look up the details in my previous blog.
https://blog.pyn3rd.com/2023/09/15/CVE-2023-34040-Spring-Kafka-Deserialization-Remote-Code-Execution
After analyzing explicitly, I consider it a thought-provoking report. Hence, I instantly write this blog down.
Java deserialization vulnerability is on the top of the list when it comes to Java Security. I would like to talk about that with the recent Java deserialization vulnerability of Spring Kafka.
People have been likely to know the fundamental reason is unsafe serialization stream from users without verification contributes to remote code execution.
A majority of Java applications have more or less paid attention to the deserialization vulnerability, like Weblogic Server, Apache Shiro. As far as I’m conernted, overwriting the ObjectInputStream
function becomes widespread use for defending against Java deserialization attack. It could make this problem alleviated. When overwriting the ObjectInputStream
, the resolveClass
would be hooked and potentially dangerous functions revoking might be found out.
Actually, Spring Kafka also utilizes the same way to defend against Java deserialization vulnerability. Observe the Java fragment up close.
Although the defensive programming apparentlly existing, why still does the Java deserialization vulnerability take place in Spring Kafka? I guess the confusion has manifested in someone’s face in front of the screen.
- Customize ObjectInputStream & Hook resolveClass
I just supply a demonstration with an overwritten ObjectInputStream
function.Then, I attempt to deserialize the malicious deserialization stream.
Insecure attempt has been blocked successfully.
Then I mimic Spring Kafka’s code thoroughly. I replace the class DeserializationException.class
with Person.class
to make you aware that the exeception would be thrown.
Consequently, I could simply escape this verification in a way of encapsulation. After initializating CustomExceptionClass
, it could be inputted into the instance of DeserializationExeception
as an argument.
Last step is to embed the CommonCollection6
gadget in a static code block.
In conclusion, the weakness of customized ObjectInputStream
contributes to Spring Kafka deserialization vulnerability. It only verifies the top layer function in stack.
Apart from the the way to customize ObjectInputStream
function, there are some other choices for defence.
ValidatingObjectInputStream in Apache Commons IO library
The Apache Commons IO library contains utility classes, stream implementations, etc. It offers a function
ValidatingObjectInputStream
to only allow the specific classes to be deserialized, equal to a whitelist.Besides the classes in the whitelist, any class could not be deserialized! As you see, the class
org.springframework.kafka.support.serializer.DeserializationException
has been blocked, because it’s not included in the whitelist.
JEP290
JEP290 is a JDK-based detective pragramming. It provides a flexible mechanism to prevent Java applications from deserialization attack.
Developers could customize a particular class as the filter. It permits the classes to be deserialized or not. In my illustration, the class
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
would be blocked.
Unfortunately, this mechanism more or less has some shortages. I intend to talk about it next time.