BTR — атака на CPU Intel, AMD и ARM, эксплуатируемая через JIT-компиляторы

Группа исследователей из Амстердамского свободного университета разработала новый метод атаки BTR (Branch Target Reuse), относящийся к классу Spectre-v2 и позволяющий обойти механизмы изоляции памяти на системах с процессорами Intel, AMD и ARM. Инициирование утечки содержимого памяти в ходе спекулятивного выполнения инструкций при проведении атаки BTR осуществляются через манипуляции с JIT-компиляторами. Исследователями проанализирована возможность совершения атаки через JIT-движки cBPF в ядре Linux, Oracle GraalVM и SpiderMonkey в Firefox.

Для подтверждения практичности атаки подготовлены
два эксплоита, позволяющие извлечь хэш пароля пользователя root, загруженного из файла /etc/shadow в память после запуска утилиты su. Атака осуществляется через манипуляции с поставляемым в ядре Linux движком cBPF (Classic Berkeley Packet Filter), который, среди прочего, применяется в механизме seccomp для ограничения доступа к системным вызовам. Работа эксплоитов продемонстрирована в Ubuntu 24.04 с ядром 6.14.0-27-generic в конфигурации по умолчанию. На компьютере с CPU Intel скорость утечки составляет 8 байт в секунду, чего достаточно для извлечения из памяти хэша пароля за 3-5 минут.

В атаках класса Spectre-v2 для организации утечки данных используется подстановка значений в буфер адреса ветвления (Branch Target Buffer) или буфер с историей переходов (Branch History Buffer), применяемые для предсказания следующей операции ветвления. Через манипуляции с историей переходов создаются условия неверного предсказания перехода при спекулятивном выполнении инструкций. Задача атакующего в том, чтобы при выполнении спекулятивной операции ветвления адрес для перехода был взят из желаемой области памяти. После выполнения спекулятивного перехода, в процессорном кэше остаётся считанный из памяти адрес перехода (под видом адреса считываются необходимые атакующему данные из памяти). Для извлечения информации из кэша может применяться один из способов определения содержимого кэша на основе анализа изменения времени доступа к прокэшированным и не прокэшированным данным.

Атака BTR основывается на том, что кэширование предсказаний ветвления не синхронизировано с размещением JIT-компилятором инструкций в памяти. Состояние буфера адреса ветвления (BTB, Branch Target Buffer) сохраняется после модификации машинного кода JIT-компилятором, из-за чего оставшиеся в буфере BTB неочищенные устаревшие записи продолжают влиять на спекулятивное предсказание переходов. В итоге, CPU может предсказать переход по старому целевому адресу и выполнить чтение адреса из памяти в спекулятивном режиме даже если код в этот момент уже заменён.

В опубликованном эксплоите на первой стадии через JIT инициируется выполнение «тренировочного» BPF-кода (BPF-программа оформляется в виде seccomp-фильтра), приводящего к тому, что система предсказания переходов запоминает определённый адрес косвенного перехода как точку входа в исполняемый блок. На второй стадии атакующий добивается замены кода в памяти без сброса состояния буфера предсказания переходов, для чего он вначале выгружает «тренировочную» BPF-программу, а потом добивается загрузки новой BPF-программы в память, освобождённую после выгрузки прошлой BPF-программы. Новая BPF-программа содержит гаджеты — заданные атакующим цепочки инструкций.

Для обхода применяемой в JIT-компиляторах защиты «constant-blinding», не позволяющей эксплоитам кодировать гаджеты с машинным кодом в форме констант для последующего перехода на них в исполняемой памяти, в подготовленных экплоитах реализован метод кодирования гаждетов в форме операндов в инструкциях перехода. В случае изменения выравнивания потока исполнения (перехода на середину машинного кода с инструкцией jmp), вместо набора инструкций jmp начинают выполняться инструкции, закодированные в адресах перехода.

На третьей стадии в новой BPF-программе выполняется тот же косвенный переход, что использовался в первой BPF-программе. Так как состояние буфера адреса ветвления не было сброшено, процессор извлекает из него запомненный старый адрес точки входа и выполняет переход в спекулятивном режиме. В заменённом коде старая точка входа приходится на середину инструкции jmp и процессор начинает спекулятивно выполнять код закодированного через операнды гаджета.

В свою очередь, гаджет в процессе спекулятивного выполнения обращается к произвольной области памяти ядра и её содержимое оседает в процессорном кэше. В предложенном эксплоите гаджет спекулятивно перебирает структуру ядра со списком запущенных процессов, находит процесс su и выполнят обход связанных с ним таблиц страниц памяти, определяя страницу с хэшем пароля root по шаблону.


Защита для противодействия новому виду атак добавлена в ядро Linux в начале июля и вошла в состав выпусков 7.2-rc2, 7.1.4, 6.18.39, 6.12.97 и 6.6.145. Защита реализована через вызов процессорных инструкций IBPB (Indirect Branch Prediction Barriers) для сброса состояния блока предсказания переходов после каждого повторного использования исполняемой области памяти в cBPF/eBPF.

В SpiderMonkey показана возможность создания условий для спекулятивного обращения к памяти при манипуляциях с WebAssembly, но разработка рабочего эксплоита требует дополнительной работы. Компания Mozilla в качестве приоритетного метода борьбы со утечками данных рассматривает изоляцию сайтов в разных процессах.

В GraalVM эксперименты также не привели к созданию рабочего эксплоита, так как активность сборщика мусора приводила к слишком быстрой очистке буфера адреса ветвления (BTB), но исследователи не считают это полноценной защитой и полагают, что данное ограничение при желании можно обойти. Для усиления противодействия атаке BTR компания Oracle реализовала в GraalVM рандомизацию размещения кэша с кодом для JIT.

Источник: http://www.opennet.ru/opennews/art.shtml?num=66374