Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/crixpwn/cve-2026-8389
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийCTFОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubcrixpwn/cve-2026-8389

CVE-2026-8389

Технический анализ и эксплойт-доказательство концепции для CVE-2026-8389, уязвимости типа путаницы типов в SpiderMonkey BaselineJIT в Firefox, продемонстрированной с помощью усечения байт-кода и манипуляции раскруткой исключений.

Репозиторий
40723 месяцев назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-8389

Эта уязвимость предназначалась для использования на Pwn2Own 2026 Berlin, но была исправлена в версии 150.0.3.

Усечение битового поля pcOffset в BaselineJIT SpiderMonkey на пути упреждающей компиляции baseline вне основного потока, приводящее к неверному, но в пределах границ, pc байт-кода во время раскрутки исключений и последующей путанице типов.

Краткое описание

RetAddrEntry хранит смещение байт-кода pcOffset_ как 28-битное битовое поле. Константа BaselineMaxScriptLength = 0x0fffffff, определённая в том же заголовочном файле, имеет размер, точно соответствующий диапазону этого битового поля.

root@kitploit:~
// js/src/jit/BaselineJIT.h:73
static constexpr uint32_t BaselineMaxScriptLength = 0x0fffffffu;

// js/src/jit/BaselineJIT.h:100-105
class RetAddrEntry {
  // Offset from the start of the JIT code where call instruction is.
  uint32_t returnOffset_;

  // The offset of this bytecode op within the JSScript.
  uint32_t pcOffset_ : 28;
root@kitploit:~
// js/src/jit/BaselineJIT.h:141-156 (RetAddrEntry constructor)
RetAddrEntry(uint32_t pcOffset, Kind kind, CodeOffset retOffset)
    : returnOffset_(uint32_t(retOffset.offset())),
      pcOffset_(pcOffset),
      kind_(uint32_t(kind)) {
  MOZ_ASSERT(returnOffset_ == retOffset.offset(),
             "retOffset must fit in returnOffset_");

  // The pc offset must fit in at least 28 bits, since we shave off 4 for
  // the Kind enum.
  MOZ_ASSERT(pcOffset_ == pcOffset);
  static_assert(BaselineMaxScriptLength <= (1u << 28) - 1);
  MOZ_ASSERT(pcOffset <= BaselineMaxScriptLength);

  MOZ_ASSERT(kind < Kind::Invalid);
  MOZ_ASSERT(this->kind() == kind, "kind must fit in kind_ bit field");
}

До исправления эта верхняя граница проверялась в релизных сборках только внутри CanEnterBaselineJIT (js/src/jit/BaselineJIT.cpp), который является точкой входа основного потока для прогрева / OSR. Путь упреждающей компиляции baseline вне основного потока не проходил эту проверку, поэтому скрипт, чей байт-код превышает 256 МБ, мог пройти компиляцию baseline, в то время как его pcOffset незаметно усекался 28-битным сохранением (pcOffset & 0x0FFFFFFF). Два информативных MOZ_ASSERT выше (pcOffset_ == pcOffset и pcOffset <= BaselineMaxScriptLength) являются no-ops в релизных сборках, поэтому усечение оставалось незамеченным.

Пострадавший путь

Путь упреждающей компиляции baseline вне основного потока:

root@kitploit:~
CompilationStencil::instantiateStencils
  -> MaybeDoEagerBaselineCompilations        (js/src/frontend/Stencil.cpp:2720)
    -> DispatchOffThreadBaselineBatchEager    (js/src/jit/BaselineJIT.cpp:386)
      -> BaselineCompileTask::runTask         (js/src/jit/BaselineCompileTask.cpp:69)
        -> BaselineCompile

До исправления MaybeDoEagerBaselineCompilations проверял только script->baselineDisabled() и jit::CanBaselineInterpretScript(script). Ни одна из этих проверок не проверяет длину скрипта, поэтому чрезмерно длинный скрипт достигал компиляции baseline через этот путь.

root@kitploit:~
// js/src/frontend/Stencil.cpp, MaybeDoEagerBaselineCompilations (pre-patch)
    if (script->baselineDisabled()) {
      continue;
    }

    if (!jit::CanBaselineInterpretScript(script)) {
      continue;
    }

Напротив, путь основного потока обеспечивал соблюдение границы (этот блок позже был перемещён в общий CanBaselineCompileScript):

root@kitploit:~
// js/src/jit/BaselineJIT.cpp, CanEnterBaselineJIT (pre-patch)
  if (script->length() > BaselineMaxScriptLength) {
    script->disableBaselineCompile();
    return Method_CantCompile;
  }

Последствия

Усечённый pcOffset преобразуется обратно в указатель на байт-код в JSJitFrameIter::baselineScriptAndPc через RetAddrEntry::pc -> JSScript::offsetToPC.

root@kitploit:~
// js/src/jit/JSJitFrameIter.cpp:155-160
  // address.
  uint8_t* retAddr = resumePCinCurrentFrame();
  const RetAddrEntry& entry =
      script->baselineScript()->retAddrEntryFromReturnAddress(retAddr);
  *pcRes = entry.pc(script);
}
root@kitploit:~
// js/src/jit/BaselineJIT.h:162-164 (RetAddrEntry::pc)
jsbytecode* pc(JSScript* script) const {
  return script->offsetToPC(pcOffset_);
}

Этот pc передаётся обработчику исключений HandleExceptionBaseline. Поскольку усечённое смещение меньше реальной длины скрипта, offsetToPC возвращает pc, находящийся в пределах границ, но неверный, поэтому сбой происходит незаметно, а не как очевидное падение из-за выхода за границы.

root@kitploit:~
// js/src/jit/JitFrames.cpp:584-591
static void HandleExceptionBaseline(JSContext* cx, JSJitFrameIter& frame,
                                    CommonFrameLayout* prevFrame,
                                    ResumeFromException* rfe) {
  MOZ_ASSERT(frame.isBaselineJS());
  MOZ_ASSERT(prevFrame);

  jsbytecode* pc;
  frame.baselineScriptAndPc(nullptr, &pc);

Этот неверный pc приводит к неправильному сопоставлению try-заметок во время раскрутки исключений (HandleExceptionBaseline опирается на script->trynotes()), что приводит к некорректному чтению слота стека. Слот, который не является JSObject*, затем может быть обработан как таковой и диспетчеризован через его vtable, создавая путаницу типов, которая является основой для дальнейшей эксплуатации.

Скачать инструмент