
Google Chrome CVE-2026-6307 PoC
Lokale Reproduktion und Ausnutzung der V8-JS-zu-Wasm-Deoptimierungstypenkonfusion, beschrieben von Nebula, bis zu einem xcalc gebracht, das aus dem Renderer von Chrome for Testing 146.0.7680.165 aufgetaucht ist (der Fehler ist in 147.0.7727.101 behoben).
Alle Payloads sind harmlos (ein Taschenrechner / exit(0x42) / jmp $).
Alles läuft gegen einen bewusst veralteten Browser in einem lokalen Labor. Richten Sie es nicht gegen andere.
https://github.com/user-attachments/assets/d450f064-ba52-4f39-a88b-367f31217143
Der Gleichheitsoperator von JSToWasmFrameStateFunctionInfo lässt den Vergleich der Wasm-Signatur aus, sodass CSE/GVN Frame-Zustände zusammenführt, die sich nur in der Signatur unterscheiden. Eine verzögerte Deoptimierung materialisiert dann eine Wasm i64 als getaggtes externref (und umgekehrt), was eine vollständige 64-Bit addrof/fakeobj ergibt, deren Zeiger nicht cage-komprimiert sind (Wasm-Referenzen verwenden die getaggte Registerdarstellung, zurückgegeben über kReturnRegister0).
Alles unten wurde live verifiziert gegen 146.0.7680.165. Die Zahlen pro Ladevorgang sind gemessene Trefferraten über wiederholte Läufe (die Konfusion ist GC-empfindlich; jede Seite startet auf einem unsauberen Build neu). Kein Lauf erzeugte jemals einen False Positive.
--allow-natives-syntaxDie meisten V8-Fehler-PoCs erzwingen die Optimierung mit %OptimizeFunctionOnNextCall, einem nur für Tests gedachten Intrinsic, das hinter --allow-natives-syntax versteckt ist und das kein echtes Opfer aktiviert. Diese treiben den Fehler mit überhaupt keinen Flags, indem sie das Warmup-Feedback so formen, dass die Deopt-Konfusion natürlich auslöst. Jede Adresse wird zur Laufzeit geleakt — nichts ist fest codiert. Führen Sie sie headless ohne Flags aus.
rce-no-aslr/ führt es zur Code-Ausführung: Eine optimierte JS-Funktion g inszeniert execve-Shellcode als JIT-Double-Literale (movabs-Konstanten, jede endet in eb rel8, um die nächste zu verketten), der konfuse Speicher patcht ein nop; jmp in den Code von g, und der Aufruf von g() schiebt RIP in den Shellcode.
Dieser Build verwendet --allow-natives-syntax (%Optimize fixiert gs JIT-Payload, sodass der Deopt-GC sie nicht leeren kann) und --no-memory-protection-keys (damit der konfuse Speicher die JIT-Seite patchen kann — V8s PKU markiert sie ansonsten als schreibgeschützt). ASLR ist ausgeschaltet (randomize_va_space=0), sodass die Adressen deterministisch sind (A_MAP = 0x5555bbc0128a). Der Renderer benötigt auch --disable-seccomp-filter-sandbox --no-zygote, da Seccomp ansonsten den execve-Shellcode blockiert.
Natives x86_64 Linux, ASLR aus, Chrome 146 im PATH, ein X-Display auf :0 (Xvfb oder echtes X). rce-no-aslr/run.sh setzt alle Flags und serviert über 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 wechselt, was der RCE-execve("/usr/bin/xcalc") startet (einen echten Taschenrechner vs. die markierte Box). Die flag-freien Primitiven benötigen nur einen Browser:
chrome --headless=new --no-sandbox http://127.0.0.1:8080/flag-free/01-primitives-flagfree.html
flag-free/ der Beitrag ohne Flags (KEIN --allow-natives-syntax)
00-reachability Auslöser + Patch-Unterschied (anfälliges 146 vs. gepatchtes 147)
01-primitives addrof / fakeobj
02-store Out-of-Cage-Speicher
03-arw In-Cage read64 / write64
rce-no-aslr/ die sichtbare RCE (deterministisch, No-ASLR-Lab-Build)
exploit-calc.html / exploit-exit.html
run.sh, demo.sh, pocmode.sh, xcalc-msgbox.sh
Bug- und Root-Cause-Bericht: Nebula Security (oben verlinkt). Flag-freier Auslöser, Primitiven und die sichtbaren Arbeiten in diesem Repository sind Reproduktionen/Erweiterungen, die in einem lokalen Labor verifiziert wurden.
| Datei | Beweist | Verifiziert |
|---|
flag-free/00-reachability-flagfree.html | löst den konfusen Zustand aus; feuert auf anfälligem 146, nicht auf gepatchtem 147 | 6/15 pro Ladevorgang |
flag-free/01-primitives-flagfree.html | addrof / fakeobj (fakeobj(addrof(o))===o) | 8/12 |
flag-free/02-store-flagfree.html | Out-of-Cage-Speicher legt einen gewählten Wert in einem gewählten Objekt ab | 12/12 |
flag-free/03-arw-flagfree.html | In-Cage read64 / write64 (falsches PACKED_DOUBLE Array) | 2/12 (unzuverlässig, wiederholen) |
| Datei | Beweist | Verifiziert |
|---|
rce-no-aslr/exploit-calc.html | öffnet ein echtes xcalc-Fenster via execve aus dem Renderer | öffnet in ~1s auf einer sauberen Ausgangsbasis |
rce-no-aslr/exploit-exit.html | Renderer führt den injizierten Shellcode aus, um exit(66) zu erreichen; #jmp dreht RIP darin | exit(66) 8/8 (strace) |