
Escalade de privilèges IPDL de Firefox du contenu vers le parent (N-day, bug 2054416) : PDocumentChannel forgé avec RemoteTypeOverride -> placement dans le processus privilegedabout, via injection du chemin d'envoi mojo-port depuis un processus de contenu compromis.
Preuve de concept pour une évasion de la sandbox dans Firefox 149.0a1 nightly (2fbc0748c4, avant le correctif). Un processus de contenu compromis forge un message IPDL qui fait charger par le processus parent une page dans un processus privilégié (privilegedabout).
C'est l'évasion de sandbox de stade 2, conçue pour être chaînée après une exécution de code dans le processus de contenu (RCE) (par exemple CVE-2026-2796).
Le processus parent désérialise un nsDocShellLoadState à partir de messages IPDL content→parent. La version vulnérable ne rejette pas un champ RemoteTypeOverride défini par le contenu, ce qui permet au contenu de choisir le type de processus dans lequel une navigation atterrit.
Le correctif (commit 3ec5c71b41bb, « Validate RemoteTypeOverride ») fait en sorte que le constructeur de nsDocShellLoadState rejette toute surcharge sur un chargement déclenché par le contenu.
Lorsque la surcharge est honorée — chargement du document about:blank, contexte de haut niveau — IsolationOptionsForNavigation définit le type remote du chargement sur la valeur de la surcharge, et la page est placée dans un processus privilégié. La frontière de la sandbox est franchie.
La surcharge voyage sur PNecko::PDocumentChannel, un message que chaque processus de contenu envoie pour chaque chargement de document (DocumentChannelCreationArgs.loadState est un nsDocShellLoadState).
La livraison est la partie intéressante : les écritures brutes sur le socket IPC sont silencieusement ignorées, car les messages IPDL voyagent désormais sur des ports mojo. Le PoC pilote donc le vrai chemin d'envoi depuis JavaScript via des appels natifs (en utilisant la primitive funcref de CVE-2026-2796) :
operator new — alloue un bloc de tas pour le IPC::MessageIPC::Message::Message(routing, type, capacity, flags) — constructeur de placementPickle::WriteBytes — ajoute le payload forgéMessageChannel::Send sur le canal PContent — l'encadrement mojo, le routage des ports et les numéros de séquence sont tous pris en charge nativementLe payload (construit par forge.py) transporte RemoteTypeOverride = "privilegedabout", l'URI about:blank, un principal null, et des valeurs divulguées à l'exécution (id BrowsingContext, TriggeringRemoteType).
./irun
Les journaux côté parent (MOZ_LOG=ProcessIsolation:5,DocumentChannel:5) montrent le changement de processus vers le processus privilégié :
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 »| Fichier | Objectif |
|---|
privesc.html | Page PoC, exécutée dans le processus de contenu compromis |
forge.py / forge.json | construit le message IPDL forgé (auto-vérifiant) |
wasm-bytes.js | primitives de stade 1 : lectures/écritures arbitraires, appels funcref |
mdrive.py / mdrive2.py | harnais Marionette pour lancer et piloter Nightly |
irun | exécution instrumentée : lldb attaché au parent + preuves MOZ_LOG |
profile.user.js | préférences du profil Firefox (fission activé, dump activé) |
parse_dc.py | analyseur octet-exact pour les messages DocumentChannel capturés |
scan_sentinels.py / extract_fields.py | scanners de cartographie des champs pour les captures |