
PoC pour Google Chrome CVE-2026-6307
Reproduction locale et weaponization de la confusion de type de désoptimisation V8 JS-to-Wasm décrite par Nebula, aboutissant à un xcalc ouvert depuis le renderer de Chrome for Testing 146.0.7680.165 (le bug est corrigé dans 147.0.7727.101).
Tous les payloads sont bénins (une calculatrice / exit(0x42) / jmp $).
Tout s'exécute contre un navigateur volontairement obsolète dans un laboratoire local
ne le pointez sur personne d'autre.
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 (and vice-versa),
giving a full 64-bit / whose pointers are cage-compressed
(Wasm refs use the tagged register representation, returned via ).
externrefaddroffakeobjkReturnRegister0Tout ce qui suit a été vérifié en direct contre 146.0.7680.165. Les nombres par chargement sont des taux de réussite mesurés sur des exécutions répétées (la confusion est sensible au GC ; chaque page relance sur une build sale). Aucune exécution n'a jamais produit de faux positif.
--allow-natives-syntaxLa plupart des PoC de bugs V8 forcent l'optimisation avec %OptimizeFunctionOnNextCall, une intrinsèque réservée aux tests derrière --allow-natives-syntax qu'aucune vraie victime n'active. Ceux-ci exploitent le bug sans aucun drapeau, en façonnant le feedback de préchauffage pour que la confusion de désoptimisation se déclenche naturellement. Chaque adresse est divulguée à l'exécution — rien n'est codé en dur. Exécutez-les sans tête (headless) sans drapeaux.
| Fichier | Démontre | Vérifié |
|---|---|---|
flag-free/00-reachability-flagfree.html | déclenche l'état confus ; fonctionne sur 146 vulnérable, pas sur 147 corrigé | 6/15 par chargement |
flag-free/01-primitives-flagfree.html | addrof / fakeobj (fakeobj(addrof(o))===o) | 8/12 |
flag-free/02-store-flagfree.html | l'écriture hors cage place une valeur choisie dans un objet choisi | 12/12 |
flag-free/03-arw-flagfree.html | read64 / write64 dans la cage (fausse PACKED_DOUBLE array) | 2/12 (instable, réessayer) |
rce-no-aslr/ mène à l'exécution de code : une fonction JS optimisée g met en scène le shellcode execve sous forme de doubles littéraux JIT (movabs constants, chacun se terminant par eb rel8 pour enchaîner le suivant), l'écriture confuse patche un nop; jmp dans le code de g, et appeler g() glisse RIP dans le shellcode.
| Fichier | Démontre | Vérifié |
|---|---|---|
rce-no-aslr/exploit-calc.html | ouvre une vraie fenêtre xcalc via execve depuis le renderer | s'ouvre en ~1s sur une ardoise propre |
rce-no-aslr/exploit-exit.html | le renderer exécute le shellcode injecté pour exit(66) ; #jmp fait tourner RIP à l'intérieur | exit(66) 8/8 (strace) |
Cette build utilise --allow-natives-syntax (%Optimize épingle le payload JIT de g pour que le GC de désoptimisation ne puisse pas le vider) et --no-memory-protection-keys (pour que l'écriture confuse puisse patcher la page JIT — sinon PKU de V8 la marque en lecture seule). ASLR est désactivé (randomize_va_space=0) donc les adresses sont déterministes (A_MAP = 0x5555bbc0128a). Le renderer a aussi besoin de --disable-seccomp-filter-sandbox --no-zygote, car seccomp bloque autrement le execve du shellcode.
Native x86_64 Linux, ASLR désactivé, Chrome 146 dans PATH, un affichage X sur :0 (Xvfb ou X réel). rce-no-aslr/run.sh définit tous les drapeaux et sert via http.
cd rce-no-aslr
./run.sh calc # pop a real xcalc over http://127.0.0.1:8080, on :0
./run.sh exit # strace-confirms the renderer's exit(66)
./run.sh jmp # gdb-confirms RIP inside the injected shellcode
./demo.sh calc # clean-slate + auto-retry, full-size headful browser (for recording)
./demo.sh msgbox # same, but the pop is a branded "0xSha :: pwned" box
pocmode.sh calc|msgbox change ce que le execve("/usr/bin/xcalc") du RCE lance (une vraie calculatrice vs la boîte de marque). Les primitives sans drapeau n'ont besoin que d'un navigateur :
chrome --headless=new --no-sandbox http://127.0.0.1:8080/flag-free/01-primitives-flagfree.html
flag-free/ la contribution sans drapeau (PAS de --allow-natives-syntax)
00-reachability déclencheur + différentiel de correctif (146 vulnérable vs 147 corrigé)
01-primitives addrof / fakeobj
02-store écriture hors cage
03-arw read64 / write64 dans la cage
rce-no-aslr/ la RCE visible (déterministe, build de laboratoire sans ASLR)
exploit-calc.html / exploit-exit.html
run.sh, demo.sh, pocmode.sh, xcalc-msgbox.sh
Rapport du bug et analyse de cause racine : Nebula Security (lié ci-dessus). Le déclencheur sans drapeau, les primitives et les travaux visibles dans ce dépôt sont des reproductions/extensions vérifiées dans un laboratoire local.