
CVE-2024-29943, но с wasm
Сквозная цепочка эксплуатации для CVE-2024-29943, достигающая выполнения
произвольного нативного кода путём контрабанды шелл-кода в страницу JIT-кода
WebAssembly SpiderMonkey в виде непосредственных значений f64.const — без ROP,
без VirtualProtect, без внешнего тулчейна.
Проверено в работе на оболочке SpiderMonkey из ночной сборки
mozilla-central от 2024-03-20 (JavaScript-C126.0a1, linux x86-64,
до исправления): цепочка выполняется до конца, и полезная нагрузка исполняется
(write(1, "PWNED by wasm!\n"); exit(0)).
CVE-2024-29943 — критичная по безопасности ошибка анализа диапазонов в IonMonkey, использованная на Pwn2Own 2024 Манфредом Паулем, затрагивающая Firefox < 124.0.1 (Bugzilla 1886849, CVSS 9.8).
MObjectKeysLength::computeRange возвращал некорректный целочисленный диапазон
для Object.keys(x).length после того, как Object.keys стал устранимым
(регрессия из-за бага 1845728). Анализ диапазонов Ion пришёл к выводу, что
счётчик цикла не может стать отрицательным, и устранил проверки границ, которые
всё ещё были достижимы, что привело к чтению/записи за границами .
Uint8Arrayбаг анализа диапазонов Object.keys -> OOB чтение/запись на Uint8Array
-> повреждение соседнего ArrayBuffer -> addrof / fakeobj / произвольное чтение-запись
-> инстанцирование вручную собранного WASM-модуля (шелл-код как непосредственные значения f64.const)
-> WasmInstanceObject -> wasm::Instance -> wasm::Code -> CodeTier
-> ModuleSegment.bytes_ (страница JIT-кода, RX)
-> сканирование страницы в поисках константы-маркера
-> перезапись FuncExport.eagerInterpEntryOffset_ (обычная куча)
смещением шелл-кода внутри страницы
-> вызов экспорта через интерпретатор -> полезная нагрузка исполняется
Две детали стоили нам по одному segfault каждая, чтобы их выяснить, поэтому они записаны:
eagerInterpEntryOffset_ в размещённом в куче FuncExport — интерпретатор
вычисляет codeBase + offset и переходит туда.Техника шелл-кода в странице WASM-JIT взята из WasmBlazeFox; этот репозиторий демонстрирует, что данная техника сочетается с современным багом реального браузера вместо оригинального тренировочного бага 2018 года.
poc.js — минимальный триггер для бага анализа диапазонов.exploit.js — полная цепочка: примитивы + стадия шелл-кода в WASM JIT.gen_wasm.py — собирает WASM-модуль, встраивающий шелл-код, и проверяет
круговой обход константы. python3 gen_wasm.py mysc.bin для использования
другой полезной нагрузки. Полезная нагрузка по умолчанию — чисто
syscall-доказательство write(1, "PWNED by wasm!\n"); exit(0), не требующее
разрешения символов (поэтому оно также работает в голом jsshell). Для
классической полезной нагрузки system("gnome-calculator") на основе libxul
см. WasmBlazeFox ex6.test.gdb — точки останова и помощники ptype /o для вывода смещений
объектной модели на данной сборке.afbdf6822c9e9f9b6d44b9ea6904cb10878126b1 (Firefox ~124, до 124.0.1),
Linux x86-64 — или возьмите ночной jsshell до исправления, например
archive.mozilla.org/pub/firefox/nightly/2024/03/2024-03-20-21-16-35-mozilla-central/jsshell-linux-x86_64.zip.LD_LIBRARY_PATH=<jsshell dir> ./js --no-threads --ion-offthread-compile=off \
--spectre-mitigations=off poc.js # только триггер (segfault)
LD_LIBRARY_PATH=<jsshell dir> ./js --no-threads --ion-offthread-compile=off \
--spectre-mitigations=off exploit.js # полная цепочка ("PWNED by wasm!")
--spectre-mitigations=off требуется, потому что устранение проверок границ
опирается на отключённое маскирование индексов (см. комментарии в Bugzilla).
f64.const
встраиваются прямо в сегмент кода. Компиляция Ion могла бы их свернуть.WASM_INSTANCE_OFF_CODE = 0xa8, MetadataTier.funcExports + 448,
FuncExport + 8 и т. д.) были выведены из заголовков уязвимого коммита
и подтверждены на ночном jsshell от 2024-03-20; для других сборок
пересчитайте их с помощью test.gdb.