CVE-2023-34040 Spring Kafka Deserialization Remote Code Execution
0x01 Preface
Here is the explicit description about Spring Kafka deserialization vulnerability in Vmware security bulletin.
Reference
https://spring.io/security/cve-2023-34040
According to the description in security bulletin, we can simply attain some critical points resulting in the vulnerability.
Setting the
ErrorHandlingDeserializer
as a key and/or value in the Kafka record in configuration.Setting the boolean type properties
checkDeserExWhenKeyNull
and/orcheckDeserExWhenValueNull
to true.The users can publish a Kafka topic without any verification.
0x02 Concepts of Kafka
Before deeply diving into the vulnerability, we promptly review some relevant concepts of the Kafka service.
Producer:we call the object for publishing record Kafka topic producer
Topic:The records are classified by the Kafka service, and each classification is named Topic.
- Broker:The published messages are stored in a group of servers, we call it Kafka cluster. Each of the server is a Broker. The consumer can attain the data form Broker and consume more than one topic.
- Consumer:The object which is used to subscribe message and handle with the published message is called Kafka topi consumer. The consumption messages are topic based.
Moreover,it is necessary to review the structure of Kafka record.
Kafka Record, we also call it Message or Event consisting of Header and Body. The header data virtually equals to Metadata including the basic elements like Topic, Patition and Timestamp. They are stored as a pair of key/value. The body data usually are the relevant business data stored as key/value constructure as well.
Preparation
Zookeeper server is required before deploying Kafka service.
1.Installing Zookeeper server by docker
1 | docker run -d --name zookeeper -p 2181:2181 -t zookeeper:latest |
2.Deploying Kafka server by docker
1 | docker run -d --name kafka -p 9092:9092 \ |
3.Spring Boot project imports the affected Kafka dependencies
Affected version:
- 2.8.1 to 2.9.10
- 3.0.0 to 3.0.9
1 | <dependency> |
4.Updating the configuration in application.yaml
5.Classes for demonstration
1)Kafka Producer Class
1 | package com.example.SpringKafkaDemo.producer; |
By the way, here we use a type of design pattern in Java Language, Template Method Pattern. In this demonstration, I insert a template named kafkaTemplate
.
Highlight of the code fragment
1 | private KafkaTemplate<String, String> kafkaTemplate; |
2)Kafka Consumer Class
1 | package com.example.SpringKafkaDemo.consumer; |
3)Config Class for the Consumer
1 | package com.example.SpringKafkaDemo.config; |
In acordance with the vulnerablity description in official bulletin, we should set both the checkDeserExWhenKeyNull
and checkDeserExWhenValueNull
properties to true.
1 | factory.getContainerProperties().setCheckDeserExWhenKeyNull(true) |
Se the breakpoint at the getExceptionFromHeader
function and then have the server start.
Step into invokeIfHaveRecords
function, the record object will be deserialized.
Back to the getExceptionFromHeader
function.
This function makes the value springDeserializerExceptionKey
of record.headers()
into the the value of the variables headerName
and be delivered header
.
And then deliver the value to byteArrayToDeserializationException
function.
Step into byteArrayToDeserializationException
function.
The resolveClass
function is overrided to restrain arbitrary Java class deserialization. Actually, we can find the way of preventing Java deserialization vulnerability in many projects, like Apache Shiro, Fastjson.
Apparently, only the classorg.springframework.kafka.support.serializer.DeserializationException
can be deserialized.
Step into DeserializationException
function, it consists four arguments. One of them is cause
which is used to invoke instantial class.
Write a malicious class and make it inherit the parent class Throwable
.
Eventually, fill the value of the springDeserializerExceptionKey
key in JSON data with the generated Java serialization. The remote code execution is trigged after send the HTTP request.