Эксплуатация CVE-2021-21220
От некорректного поведения JIT к удалённому выполнению кода
Обзор
Этот доклад объясняет эксплуатацию CVE-2021-21220 — уязвимости в движке V8 JavaScript Google Chrome, вызванной некорректными предположениями JIT-компилятора во время оптимизации.
В докладе рассматривается:
- Как V8 выполняет JIT-компиляцию (Just-In-Time)
- Как во время оптимизации возникает ошибка путаницы знаковых/беззнаковых типов
- Как ошибка приводит к примитиву массива с выходом за границы (OOB)
- Как атакующие используют OOB-доступ для утечки адресов и произвольной записи в память
- Как WebAssembly (Wasm) становится целью для выполнения нативного кода
- Существующие механизмы смягчения и современные защиты браузеров
Цели доклада
Цель этого доклада — продемонстрировать, как незаметная ошибка оптимизации внутри современного JavaScript-движка может перерасти в:
- Повреждение памяти
- Примитивы произвольного чтения/записи
- Модификацию нативного кода
- Потенциальное удалённое выполнение кода (RCE)
Цепочка эксплуатации показывает, как JIT-движки балансируют между производительностью и безопасностью и как неверные предположения оптимизации становятся эксплуатируемыми.
Рассматриваемые темы
1. Архитектура V8
В докладе представлены основные компоненты V8:
Интерпретатор Ignition
- Выполняет байткод JavaScript
- Собирает информацию об исполнении (feedback)
- Хранит информацию о типах в векторах обратной связи
Оптимизатор TurboFan
- Строит оптимизированные графы на основе данных об исполнении
- Вставляет спекулятивные предположения и проверки
- Выполняет агрессивные проходы оптимизации
Бэкенд машинного кода
- Генерирует нативные инструкции CPU
- Создаёт оптимизированный машинный код для «горячих» функций
Схема архитектуры в докладе иллюстрирует, как JavaScript проходит путь от:
Parsing → Bytecode → Optimization → Execution
2. Почему JavaScript сложно оптимизировать
JavaScript сложен для высокопроизводительного исполнения, потому что:
- Переменные динамически меняют типы
- Массивы меняют структуру и типы элементов
- Операторы вроде
+ могут иметь несколько значений
- Проверки во время исполнения дороги
V8 использует JIT-компиляцию для оптимизации часто встречающихся паттернов выполнения, делая предположения о поведении во время исполнения.
3. Корневая причина CVE-2021-21220
Уязвимость возникает из-за несоответствия знаковых и беззнаковых целых чисел во время JIT-оптимизации.
Демонстрируемые ключевые концепции:
Uint32Array
Word32Xor
- Некорректное распространение типов
ChangeInt32ToInt64
- Неверный выбор инструкций ассемблера
Эксплойт использует значение:
0x80000000
которое устанавливает знаковый бит 32-битного целого числа.
4. Ошибка оптимизации
Уязвимость возникает из-за того, что TurboFan оптимизирует:
x ^ 0
полностью устраняя это выражение.
Во время этой оптимизации:
- Операция XOR исчезает
- Информация о типах теряется
- Знаковые значения начинают интерпретироваться как беззнаковые
- Поведение JIT расходится с поведением интерпретатора
Это приводит к генерации некорректного машинного кода и значениям, контролируемым атакующим.
5. Создание OOB-примитива
Эксплойт преобразует некорректный результат JIT в контроль над поведением массива.
В докладе демонстрируется:
- Неверное оптимизированное целочисленное значение
- Преобразование в управляющую переменную
i
- Расхождение между прогревом и триггерным выполнением
- Переполнение длины при
Array.shift() (underflow)
- Создание массива с возможностью выхода за границы
Важные концепции эксплуатации:
- Оптимизация после прогрева
- Спекулятивная оптимизация
- Путаница типов
- Повреждение длины массива
6. Выход за границы
Когда длина массива становится -1, атакующий получает:
- Чтение за пределами границ
- Запись за пределами границ
- Доступ к соседним объектам кучи V8
Затем эксплойт демонстрирует:
- Утечку указателей
- Определение адресов объектов
- Перекрывающиеся массивы
- Извлечение «сырых» указателей V8
7. Использование WebAssembly
В докладе объясняется, как атакующие могут нацеливаться на:
- Страницы скомпилированного кода WebAssembly
- Нативную исполняемую память, созданную V8
Порядок атаки:
- Создать функцию Wasm
- Найти исполняемую память
- Перезаписать скомпилированный машинный код
- Повторно выполнить Wasm
- Добиться произвольного выполнения нативного кода
Это демонстрирует, как ошибка в JavaScript-движке может перейти в выполнение кода на уровне процесса.
Защитные механизмы и смягчение последствий
В заключительном разделе рассматриваются современные защиты браузеров:
Сжатые указатели (Compressed Pointers)
Снижают прямую раскрываемость указателей и предсказуемость кучи.
Косвенность указателей (Pointer Indirection)
Предотвращают прямой доступ к «сырым» адресам памяти.
Песочница для кучи (Heap Sandboxing)
Изолирует области памяти и снижает воздействие эксплойта.
W^X (Write XOR Execute)
Не допускает одновременной записи и исполнения на страницах памяти.
В докладе также приведён реальный diff патча V8, показывающий исправление проблемы знакового расширения.
Основные выводы
Этот доклад демонстрирует, как:
- Небольшие ошибки оптимизации могут становиться критическими уязвимостями
- JIT-компиляторы значительно усложняют поверхность атаки
- Спекуляции во время выполнения могут приводить к опасным несогласованностям
- WebAssembly меняет ландшафт эксплуатации уязвимостей
- Современные браузеры требуют многоуровневых защит
Рассматриваемые технологии
- JavaScript
- Движок Google V8
- TurboFan
- Ignition
- WebAssembly (Wasm)
- JIT-компиляция
- Повреждение памяти
- Выход за границы
- Эксплуатация браузеров
Образовательная цель
Этот материал предназначен строго для:
- Исследований в области безопасности
- Образовательных демонстраций
- Изучения внутреннего устройства браузеров
- Анализа уязвимостей
Не используйте эту информацию против систем, которыми вы не владеете или на тестирование которых у вас нет разрешения.
Ссылки