Документация и PoC-код для CVE-2022-24125 и CVE-2022-24126.
Новое обновление игры, 1.15.1, было выпущено для Dark Souls III 25.08.2022, вместе с восстановлением онлайн-сервисов. Это обновление исправило как CVE-2022-24125, так и CVE-2022-24126, а также множество других потенциальных уязвимостей безопасности в P2P-сети игры (чтения/записи за пределами границ). Кроме того, были исправлены все известные эксплойты, позволяющие повредить сохранения других игроков. Также были пропатчены многие распространённые мелкие читы (например, «проклятый нож»), которые часто встречались в онлайн-мультиплеере.
Этот репозиторий содержит код доказательства концепции и документацию для самой последней RCE-уязвимости, затрагивающей игры FROM SOFTWARE, CVE-2022-24126. Хотя теоретически это возможно и в других играх, основное внимание уделяется Dark Souls III, поскольку именно на этой игре проводилось моё исследование. На данный момент код доказательства концепции существует только для Dark Souls III; подтверждено наличие уязвимости в:
Уязвимый код также присутствует в Sekiro (авторство: LukeYui), хотя способа его запуска нет. Наличие в Demon's Souls не подтверждено, но весьма вероятно. Хотя закрытое сетевое тестирование было затронуто этой проблемой, релизная версия Elden Ring — нет. Фактически, огромный список сетевых вылетов, чтений/записей за пределами границ и эксплойтов, позволявших игрокам изменять данные игры других участников в Dark Souls III, был исправлен в Elden Ring. Благодарность LukeYui за составление этого списка и FROM SOFTWARE за быструю реакцию! Я рад сообщить, что Elden Ring — несомненно самый безопасный проект FROM SOFTWARE с точки зрения ущерба, который могут нанести хакеры.
Вопреки распространённому мнению, это НЕ эксплойт одноранговой (P2P) сети. Он связан с матчмейкинг-сервером и поэтому гораздо серьёзнее, поскольку из-за другой уязвимости матчмейкинг-сервера (CVE-2022-24125) вам не нужно участвовать в каких-либо действиях в мультиплеере, чтобы стать уязвимым.
Учитывая, что в месяцы, предшествовавшие отключению серверов, в игру в среднем одновременно играло около 20 000 человек, было очевидно, что проблему необходимо исправить немедленно, особенно с учётом возможности её наличия в Elden Ring. Поскольку FROM SOFTWARE не предприняла никаких действий в течение более чем 40 дней после моего первоначального отчёта с видео доказательствами концепции и подробной документацией по эксплойту (на которой основана большая часть этого readme), я решил публично продемонстрировать существование эксплойта безвредным способом, надеясь привлечь внимание и добиться его устранения разработчиками, — и это сработало.
Некорректная проверка границ стекового буфера и поля размера данных при разборе матчмейкинг-данных NRSessionSearchResult позволяет атакующему выполнить произвольный код. Переполнение стека позволяет перезаписать младшие два байта vftable_ptr объекта DLMemoryInputStream, используемого внутри потоковым ридером, перенаправляя выполнение на тщательно выбранный соседний код. Умелое использование структуры объекта DLMemoryInputStream и поля размера данных затем позволяет добиться перенаправления произвольного кода, при этом RCX указывает на адрес нашего пакета. Далее серия перенаправлений кода через виртуальные вызовы с различными смещениями (которые теперь будут переходить по адресам, записанным нами в буфер пакета) может быть использована для достижения выполнения произвольного кода.
Векторы распространения — это то, что делает данную RCE особенно серьёзной (помимо того, что это уже RCE). Эксплойт передаётся через push-запросы матчмейкинга, содержащие информацию NRSessionSearchResult. Это означает, что атакующий может нацелиться на любого, кто присоединяется к его онлайн-сессии. В частности, для DS3:
PushRequestSummonSign)PushRequestAllowBreakInTarget)PushRequestVisit)PushRequestAcceptQuickMatch)Это уже довольно плохо, но настоящий потенциал открывается запросом RequestSendMessageToPlayers:
message RequestSendMessageToPlayers {
repeated uint32 player_ids = 1;
required bytes push_message = 2;
}
Хост использует этот запрос для прямой отправки push-сообщения PushRequestAllowBreakInTarget вторгшимся духам, чтобы они могли получить координаты появления и присоединиться к его P2P-сессии. Вот и всё. Это единственный способ использования этого запроса в игре.
Я не могу достаточно подчеркнуть, насколько это ужасно небезопасно. Любой игрок может фактически выдать себя за матчмейкинг-сервер. Используя этот запрос для отправки эксплойта через PushRequestVisit, атакующий может удалённо нацелиться на любого онлайн-игрока, если известен его ID игрока. Атакующий также может очень быстро отправить эксплойт всей онлайн-аудитории, отправив несколько запросов, каждый из которых содержит большой диапазон возможных ID игроков.
Хотя RCE не переносится один в один на каждую игру, основная идея эксплойта, дающая атакующему перенаправление произвольного кода, одинакова. Если этого удаётся достичь, весьма вероятно, что затем можно найти специфичную для игры цепочку виртуальных вызовов или ROP-цепочку. Этот «первый шаг» использует следующие уязвимости:
Push-запросы матчмейкинга, содержащие информацию о присоединении к сессии, хранят эту информацию в собственном двоичном формате, который представляет собой цепочку записей данных, разделённых по длине. Каждая запись имеет следующий формат:
struct Entry
{
uint32_t type_or_id; // not sure, but probably a type (fixed length = 2, variable length = 1 ?)
uint32_t size;
uint8_t data[size];
}
Игровая функция, отвечающая за копирование данных этих записей, слепо доверяет полю размера, что создаёт чтение за пределами границ. Злоумышленный клиент может воспользоваться этим, установив поле размера в такие значения, как 0x7FFFFFFF, что приведёт к сбою выделения памяти и вылету игры жертвы. Позже этот размер также передаётся в конструктор DLMemoryInputSteam, что является важной частью эксплойта.