
Escalada de privilégios IPDL content-to-parent do Firefox (N-day, bug 2054416): PDocumentChannel forjado com RemoteTypeOverride -> posicionamento de processo privilegedabout, via injeção no caminho de envio mojo-port a partir de um processo de conteúdo comprometido
Prova de conceito para uma fuga de sandbox no Firefox 149.0a1 nightly (2fbc0748c4,
pré-correção). Um processo de conteúdo comprometido forja uma mensagem IPDL que faz o
parent carregar uma página em um processo privilegiado (privilegedabout).
Esta é a fuga de sandbox de estágio 2, projetada para ser encadeada após um RCE no processo de conteúdo (ex.: CVE-2026-2796).
O processo parent desserializa um nsDocShellLoadState a partir de mensagens IPDL content→parent.
A versão vulnerável não rejeita um campo RemoteTypeOverride definido pelo conteúdo, então o conteúdo
pode escolher em qual tipo de processo uma navegação vai parar.
O correção (commit 3ec5c71b41bb, "Validate RemoteTypeOverride") faz o
construtor do nsDocShellLoadState rejeitar qualquer override em um carregamento iniciado pelo conteúdo.
Quando o override é honrado — carga de documento about:blank, contexto de nível superior —
IsolationOptionsForNavigation define o tipo remoto da carga para o valor do override,
e a página é colocada em um processo privilegiado. Fronteira da sandbox violada.
O override viaja em PNecko::PDocumentChannel, uma mensagem que todo processo de conteúdo
envia para cada carga de documento (DocumentChannelCreationArgs.loadState é um
nsDocShellLoadState).
A entrega é a parte interessante: escritas cruas no socket de IPC são silenciosamente descartadas, porque mensagens IPDL agora viajam por portas mojo. Em vez disso, o PoC dirige o caminho real de envio a partir do JavaScript via chamadas nativas (usando a primitiva funcref do CVE-2026-2796):
operator new — aloca um bloco no heap para o IPC::MessageIPC::Message::Message(routing, type, capacity, flags) — placement ctorPickle::WriteBytes — anexa o payload forjadoMessageChannel::Send no canal PContent — framing mojo, roteamento de portas,
e números de sequência são todos tratados nativamenteO payload (construído por forge.py) carrega RemoteTypeOverride = "privilegedabout",
URI about:blank, um principal nulo, e valores vazados em tempo de execução (id do BrowsingContext,
TriggeringRemoteType).
./irun
Logs do lado do parent (MOZ_LOG=ProcessIsolation:5,DocumentChannel:5) mostram a
troca de processo para o processo privilegiado:
V/ProcessIsolation using remote type override (privilegedabout) for load
I/ProcessIsolation Process Switch: Changing Remoteness from 'webIsolated=http://127.0.0.1' to 'privilegedabout'
3ec5c71b41bb "Validate RemoteTypeOverride"| Arquivo | Finalidade |
|---|
privesc.html | Página do PoC, executada dentro do processo de conteúdo comprometido |
forge.py / forge.json | constroem a mensagem IPDL forjada (autoverificável) |
wasm-bytes.js | primitivas do estágio 1: R/W arbitrário, chamadas funcref |
mdrive.py / mdrive2.py | harness marionette para iniciar e dirigir o Nightly |
irun | execução instrumentada: lldb anexado ao parent + evidência de MOZ_LOG |
profile.user.js | prefs do perfil do Firefox (fission ativado, dump habilitado) |
parse_dc.py | parser byte-exato para mensagens DocumentChannel capturadas |
scan_sentinels.py / extract_fields.py | scanners de mapa de campos para capturas |