
Google Chrome CVE-2026-6307 PoC
Локальное воспроизведение и эксплуатация путаницы типов при деоптимизации V8 JS-to-Wasm, описанной Nebula, доведённая до запуска xcalc из рендерера Chrome for Testing 146.0.7680.165 (ошибка исправлена в 147.0.7727.101).
Все полезные нагрузки безвредны (калькулятор / exit(0x42) / jmp $).
Всё запускается против намеренно устаревшего браузера в локальной лаборатории — не направляйте это на кого-либо ещё.
https://github.com/user-attachments/assets/d450f064-ba52-4f39-a88b-367f31217143
JSToWasmFrameStateFunctionInfo's equality operator omits the Wasm signature comparison, so CSE/GVN merges frame states that differ only in signature. A lazy deopt then materializes a Wasm i64 as a tagged externref (and vice-versa), giving a full 64-bit addrof/fakeobj whose pointers are not cage-compressed (Wasm refs use the tagged register representation, returned via kReturnRegister0).
Всё ниже было проверено вживую на 146.0.7680.165. Числа на загрузку — это измеренные показатели попаданий за несколько запусков (путаница чувствительна к GC; каждая страница перезапускается на грязной сборке). Ни один запуск не дал ложноположительного результата.
--allow-natives-syntaxБольшинство PoC для ошибок V8 форсируют оптимизацию с помощью %OptimizeFunctionOnNextCall — тестовой встроенной функции, доступной только через --allow-natives-syntax, которую ни одна реальная жертва не включает. Эти примеры используют ошибку вообще без флагов, формируя обратную связь прогрева так, чтобы путаница при деоптимизации срабатывала естественно. Каждый адрес утекает во время выполнения — ничего не захардкожено. Запускайте их в безголовом режиме без флагов.
rce-no-aslr/ доводит до выполнения кода: оптимизированная JS-функция g размещает шеллкод execve в виде JIT-литералов двойной точности (константы movabs, каждая заканчивается на eb rel8 для сцепления со следующей), путанная запись патчит nop; jmp в код g, и вызов g() направляет RIP в шеллкод.
Эта сборка использует --allow-natives-syntax (%Optimize фиксирует JIT-нагрузку g, чтобы деоптимизация-GC не могла её сбросить) и --no-memory-protection-keys (чтобы путанная запись могла пропатчить JIT-страницу — иначе PKU V8 помечает её как readonly). ASLR отключён (randomize_va_space=0), поэтому адреса детерминированы (A_MAP = 0x5555bbc0128a). Рендерер также требует --disable-seccomp-filter-sandbox --no-zygote, потому что иначе seccomp блокирует execve из шеллкода.
Native x86_64 Linux, ASLR выключен, Chrome 146 в PATH, X-дисплей на :0 (Xvfb или реальный X). rce-no-aslr/run.sh устанавливает все флаги и раздаёт через http.
cd rce-no-aslr
./run.sh calc # открывает настоящий xcalc через http://127.0.0.1:8080, на :0
./run.sh exit # strace подтверждает exit(66) рендерера
./run.sh jmp # gdb подтверждает RIP внутри внедрённого шеллкода
./demo.sh calc # чистый лист + авто-повтор, полноразмерный браузер с головой (для записи)
./demo.sh msgbox # то же, но всплывает брендированное окно "0xSha :: pwned"
pocmode.sh calc|msgbox переключает, что запускает RCE через execve("/usr/bin/xcalc") (настоящий калькулятор против брендированного окна). Примитивы без флагов просто требуют браузер:
chrome --headless=new --no-sandbox http://127.0.0.1:8080/flag-free/01-primitives-flagfree.html
flag-free/ вклад без флагов (НЕТ --allow-natives-syntax)
00-reachability триггер + разница патча (уязвимая 146 против исправленной 147)
01-primitives addrof / fakeobj
02-store запись вне клетки
03-arw внутриклеточные read64 / write64
rce-no-aslr/ видимое RCE (детерминированная сборка без ASLR)
exploit-calc.html / exploit-exit.html
run.sh, demo.sh, pocmode.sh, xcalc-msgbox.sh
Описание ошибки и первопричины: Nebula Security (ссылка выше). Триггер без флагов, примитивы и видимые эксплойты в этом репозитории являются воспроизведениями/расширениями, проверенными в локальной лаборатории.
| Файл | Доказывает | Проверено |
|---|
flag-free/00-reachability-flagfree.html | запускает путанное состояние; срабатывает на уязвимой 146, не на исправленной 147 | 6/15 на загрузку |
flag-free/01-primitives-flagfree.html | addrof / fakeobj (fakeobj(addrof(o))===o) | 8/12 |
flag-free/02-store-flagfree.html | запись вне клетки помещает выбранное значение в выбранный объект | 12/12 |
flag-free/03-arw-flagfree.html | внутриклеточные read64 / write64 (фальшивый массив PACKED_DOUBLE) | 2/12 (нестабильно, повторите) |
| Файл | Доказывает | Проверено |
|---|
rce-no-aslr/exploit-calc.html | открывает настоящее окно xcalc через execve из рендерера | открывается через ~1 с на чистом листе |
rce-no-aslr/exploit-exit.html | рендерер выполняет внедрённый шеллкод для exit(66); #jmp вращает RIP внутри него | exit(66) 8/8 (strace) |