Уязвимости в пользовательских картах Titan Quest позволяют выполнить произвольный код

Titan Quest

В игре Titan Quest: Anniversary Edition обнаружены уязвимости переполнения кучи при загрузке пользовательских файлов карт (.map) и эффектов частиц (.pfx). Эксплуатация возможна при установке вредоносного контента, распространяемого через сообщество. Разработчик уведомлён, но официального патча на момент публикации не выпущено.

Детали уязвимостей

Titan Quest - hack-and-slash в сеттинге античности, выпущенный студией Iron Lore и переизданный THQ Nordic в 2016 году. Игра поддерживает мультиплеер и установку дополнительных архивов с ресурсами, которые вручную добавляются в папку "custommaps". Именно этот механизм стал вектором для атак: любой пользователь может загрузить чужую карту или архив, после чего игра десериализует данные из бинарных файлов, не проверяя корректность значений.

Исследователи из команды, проводившей анализ, сосредоточились на библиотеке Engine.dll, которая содержит 49 методов, принимающих на вход структуру "BinaryReader". Каждый такой метод последовательно считывает данные из буфера, увеличивая указатель "currentPtr". Проблемы возникают, когда размеры блоков или количество элементов не верифицируются должным образом.

Первая уязвимость находится в методе "GAME::ImpassableData::Load", вызываемом при обработке блока "CHUNK_TYPE_IMPASSABLE_DATA" в .lvl-файле. Псевдокод показывает: программа вычисляет размер буфера как произведение ширины и высоты, считываемых из файла. Если эти значения подобраны так, что результат умножения превышает 32-битный предел, возникает целочисленное переполнение. Выделяется буфер меньшего размера, чем ожидается. Затем в него копируется массив байтов длиной "count", которая также берётся из файла и не проверяется. Это приводит к переполнению кучи за пределами выделенной области.

Вторая группа уязвимостей выявлена в методе "GAME::EmitterData::InternalBinaryRead", загружающем файлы .pfx. В структуре "GAME::EmitterData" есть несколько фиксированных массивов - для строк, логических значений, 32-битных целых чисел и данных кривой. Каждый из этих массивов заполняется циклом, где количество итераций задаётся значением из файла. Никакой проверки на вместимость целевого массива не производится. Таким образом, злоумышленник может записать произвольный объём данных за границы структуры, что также даёт переполнение кучи.

Эксплуатация осложнена тем, что игра - 32-битное приложение. Некоторые её DLL-библиотеки, включая DevIL.dll (упакованную UPX2), лишены поддержки ASLR, что облегчает прогнозирование адресов. Для использования переполнения в "ImpassableData::Load" необходимо скорректировать состояние кучи таким образом, чтобы перезаписываемый буфер оказался перед объектом Level, который впоследствии можно повредить. Исследователи реализовали эту подготовку, манипулируя загрузкой водных слоёв (WaterType) через строки переменной длины. Создавая "дыры" в куче, они добились того, что буфер "ImpassableData" размещается непосредственно перед объектом Level. Затем, при обработке блока "CHUNK_TYPE_WATER" (тип 09h), вызывается деструктор "GAME::Water::~Water", который выполняет косвенный вызов по указателю из таблицы виртуальных функций. Подменив этот указатель через повреждённый объект Level, можно перехватить поток выполнения.

Для обхода ASLR в 32-битном пространстве исследователи заполнили кучу повторяющимися структурами поддельного объекта Water. Каждая строка (название текстуры) WaterType может достигать 1 Мбайт, и таких строк можно загрузить до 128, что даёт до 128 Мбайт контролируемых данных. Адреса строк выравниваются по страницам, поэтому младшие 12 бит предсказуемы. Внутри каждой строки размещена полезная нагрузка: фиктивный Water с указателем на vtable, где единственный адрес - это гаджет "xchg esp, eax", переключающий стек на данные в куче. Затем выполняется ROP-цепочка, которая делает кучу исполняемой и передаёт управление шелл-коду.

Пользователям Titan Quest: Anniversary Edition рекомендуется проявлять осторожность при установке пользовательских карт и архивов из непроверенных источников. До выхода официального исправления единственным способом защиты является отказ от загрузки контента от незнакомых авторов. Уязвимость в очередной раз демонстрирует, что разделяемые игровые ресурсы могут служить вектором для вредоносного кода, и разработчикам необходимо внедрять строгую валидацию входных данных в функциях десериализации.

Ссылки

Комментарии: 0