воскресенье, 6 июля 2014 г.

Quake 3 RCE 0-day vulnerability and JQ3Exploit



Доброго времени суток. Сегодня я раскажу о найденой мной RCE (remote code execution) уязвимости в движке моей любимой fps-игрушки Quake III и о построенном на уязвимости эксплойте. Поскольку в интернете упоминаний на этот счёт я не встречал, будем считать что данный эксплойт является 0-day.

Описание эксплойта

Позволяет через серверную часть выполнять удалённую загрузку данных и выполненять произвольный код в контесте процесса клиента. Эксплойт построен на 2х уязвимостях движка: перекрытие данных в VFS(virtual file system) и перехвате управления из виртуальной машины.

Предотвращение
Такая атака работает только при включенной конфигурации cl_allowDownload на стороне клиента, поэтому крайне рекомендуется во время сетевой игры отключать данную опцию :

cl_allowDownload "0"

Протестированные движки Q3

quake 3 arena 1.32b - работает
ioquake 1.36 - работает
openarena 0.8.8 - работает

Как оказалось уязвимость задела как сам движек Q3 так и большинство его модификаций.

Перекрытие данных в VFS

Все игровые данных (код, ресурсы, конфигурации и т.п.) хранятся в ZIP архивах с расширением .pk3. При загрузке игры на стандартном моде (q3 arena) , в директории baseq3, движек находит все pk3 файлы сортирует их в алфавитном порядке и загружает по очереди. Причем каждый следующий архив, перекрывает файлы уже загруженные ранее файлы. Таким образом если у нас есть 2 архива:

aaa.pk3 --> q3config.cfg, terrain.bmp
zzz.pk3 --> q3config.cfg, test.map, test.bmd


то при запуске игры, будет использоватся q3config.cfg из архива zzz.pk3. Это небыло бы проблемой, но в сетевом режиме игры, клиент может скачивать pk3 архивы с сервера. Этот функционал предназначен для того, чтобы клиент мог скачивать с сервера отсутствующие у него карты. Однако в архиве с файлами карт, сервер может передавать и .qvm файлы (код виртуальной машины), которые могут перекрывать оригинальный код игры.

Немного о QVM файлах
Quake 3 использует 3 QVM файла:

/vm/qagame.qvm - логика серверной части
/vm/cgame.qvm - логика клиента (в режиме сражения)
/vm/ui.qvm - модуль пользовательского интерфейса

Сами QVM файлы являются программами написанными на С и скомпилированными компилятором LCC в промежуточное представление, которое затем с помощью утилиты q3asm переводится в байт код виртуальной машины движка Id Tech3. Такой подход позволяет писать игровую логику платформо-независимым кодом, подробнее можно почитать в серии статей Quake 3 source code review.

Возвращаясь к теме, благодаря уязвимости с перекрытием файлом, мы можнм сформировать собственный .qvm файл который будет запускать наш собственный шеллкод, однако как же нам выйти за пределы виртуальной машины?

Перехват управления из виртуальной машины

Во времы выполнения, QVM файлы пропускаются через JIT компилятор, который генерирует x86 код. Виртуальная машина в Q3 не содержит регистров, она полностью стек-ориентированная. Поэтому байткод из QVM файлов оперирует только над стеком и мы не можем явно передавать управление на наши данные (например шеллкод). Однако исполняемый код и стек в процессе выполнения кладутся в один и тот же регион данных, используя стек мы можем передвигаясь по памяти, найти собственный код и перезаписать его, таким образом выполнив перехват управления. В качестве сигнатуры поиска, мы будем использовать пролог функции, который компилируется всегда в один и тот же опкод.

Реализация

Исходные коды и конфигурации серверной стороны: JQ3Exploit

Для реализации мы поднимем сервер с опцией:

sv_allowDownload "1"

В качестве начальной карты установим неизвестную или редкую карту, а в её .pk3 файл добавим наш собственный /vm/ui.qvm файл (исходный код и сам файл ищите в архиве). Поскольку в Q3 скорость скачки очень низкая, лучше всего создать собственную карту с минимальным весом. Переименуем полученный pk3 таким образом чтобы он перекрывал все остальные файлы (например zzz-new-map.pk3).

В клиенте установим опцию:

cl_allowDownload "1"

При подключении клиент скачает наш архив, после чего файл /vm/ui.qvm перекроет оригинальный, далее клиент перезапустит виртуальную машины, и мы выполним наш шеллкод. Вот впринципе и всё.

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

Отправить комментарий