
Questo è un exploit per CVE-2017-7047, funziona su 10.3.2 e versioni precedenti.
triple_fetch - ianbeer [https://bugs.chromium.org/p/project-zero/issues/detail?id=1247]
Questa è un exploit per CVE-2017-7047, un errore logico in libxpc che consentiva a mittenti di messaggi malintenzionati di inviare oggetti xpc_data supportati da memoria condivisa. I consumatori di messaggi xpc non sembravano aspettarsi che i buffer di supporto degli oggetti xpc_data potessero essere modificati dal mittente mentre venivano elaborati dal destinatario.
Questo progetto sfrutta CVE-2017-7047 per costruire uno stub proof-of-concept di debugserver remoto lldb in grado di agganciarsi e consentire il debug remoto di tutti i processi in spazio utente su iOS.
Questa è una panoramica ad alto livello dell'exploit; un'analisi approfondita potrebbe seguire in una data successiva. Per ora consulta il codice per ulteriori dettagli :)
Parte I
L'exploit prende di mira NSXPC, un'implementazione Objective-C di Remote Procedure Call usata da molti servizi iOS (1). Un messaggio NSXPC consiste in un oggetto bplist16 serializzato all'interno di un oggetto xpc_data serializzato xpc all'interno di un messaggio mach.
Tra le altre cose, l'oggetto bplist16 contiene una stringa di codifica dei tipi Objective-C (2) che verrà analizzata dalla funzione ___NSMS1 in CoreFoundation. Questa funzione non si aspetta che il contenuto della stringa che sta analizzando cambi e questo exploit sfrutta questo comportamento per costruire una primitiva di overflow della heap sfruttando il fatto che una certa parte della stringa viene letta dalla memoria tre volte. Alternando tre valori diversi, scelti con cura, siamo in grado di provocare un overflow oltre una dimensione di allocazione heap scelta con byte arbitrari.
minibplist16.c contiene un'implementazione minima della serializzazione bplist e una discussione su come funziona.
Il messaggio xpc esterno contiene l'heap groom. Usa un'implementazione personalizzata del protocollo di serializzazione XPC per preparare la heap creando dizionari xpc con chiavi in collisione, così da costruire primitive di allocazione e deallocazione. Il messaggio xpc esterno contiene anche uno heap spray (usando più copie di un oggetto di memoria condivisa per mantenere basso l'uso della memoria) e uno spray di nomi di send right di mach port.
L'overflow punta il puntatore isa Class di un oggetto Objective-C a un oggetto fittizio creato tramite heap spray, così che quando un metodo viene chiamato su quell'oggetto fittizio lo stack viene spostato su una piccola ROP stack. La ROP esegue un brute force tra i nomi dei send right di mach port spruzzati, cercando di inviare il send right del bersaglio al proprio task port a ciascuno dei nomi candidati di send right spruzzati. L'exploit resta in ascolto su tutte le porte spruzzate e, se ha successo, riceve un send right al task port del bersaglio, a quel punto ha il pieno controllo del task bersaglio.
Interludio
L'exploit prende di mira il servizio com.apple.CoreAuthentication.daemon ospitato dal demone coreauthd, che viene eseguito come root. Questo servizio è raggiungibile dalla sandbox dell'app. Un po' di sperimentazione dopo aver inizialmente fatto funzionare l'exploit ha rivelato che dal contesto di coreauthd l'API processor_set_tasks è in grado di ottenere send right ai task port di tutti i processi in spazio utente in esecuzione sul dispositivo. Questa è una conoscenza pubblica almeno dal 2012 e la storia è trattata in modo approfondito dal noto ricercatore di internals iOS Jonathan Levin sul suo sito (3). Il codice caricato da Levin nel 2015 funziona ancora oggi: non richiede un dispositivo jailbroken, basta root su un dispositivo di serie.
Parte II
L'obiettivo principale del debugger che volevo costruire con questo exploit era poter agganciare un processo arbitrario, impostare breakpoint e ispezionare e modificare lo stato di registri e memoria quando vengono raggiunti. Piuttosto che implementare da zero il protocollo remoto di gdb o lldb, ho deciso di apportare le modifiche necessarie al progetto debugserver di lldb e poi usare l'exploit per eseguirlo.
Invece di usare breakpoint software, che richiedono di disabilitare o aggirare la firma del codice, il debugserver è stato modificato per usare esclusivamente breakpoint hardware. ARM64 ha 16 registri per breakpoint hardware, il che significa che puoi avere al massimo 16 breakpoint attivi.
Il supporto prototipale per i breakpoint hardware ARM esisteva già nel codice di debugserver di lldb, ma serviva qualche hack per farlo funzionare. Ad esempio, ho dovuto aggiungere codice che modifica il puntatore a funzione pthread_introspection_hook nel processo in debug per farlo crashare sempre, così da poter rilevare la creazione di nuovi thread, propagare lo stato dei breakpoint hardware nei thread appena creati e continuare come se non fosse mai crashato.
Ho anche modificato il codice di attach e continue per sospendere e riprendere direttamente il task tramite task port, invece di usare ptrace e segnali.
Suggerimenti per la compilazione
Tutto dovrebbe funzionare su tutti i dispositivi iOS che eseguono da 10.0 a 10.3.2 inclusi. Ho testato su:
iPhone 7 + 10.3.2 iPod Touch + 10.1.1 iPad Mini 2 + 10.2
Ho incluso un binario debugserver precompilato che ti suggerisco di usare, ma la patch per il debugserver di lldb è inclusa anche in debugserver.diff.
Compilare il debugserver non è troppo difficile. Stavo lavorando con le seguenti revisioni git: lldb: 0db640c4cd1ec4e4c2580336fa5f53be029c5bc7 llvm: ec48fd127774a4b67c72ea7c3057b5c964375e77 clang: b6e778e0bfa2fc32f8821c6b33762f5cb6724659
Applica il debugserver.diff fornito.
Per la compilazione ti servono cmake e ninja (recenti); puoi ottenerli dai sorgenti o come binari dal tuo gestore di pacchetti Mac preferito.
(4) contiene una guida su come configurare una normale build di llvm su MacOS che potrebbe esserti utile.
Dovrai creare symlink per un gruppo di file header nel tuo iOS SDK, almeno:
xpc/ launchd.h libproc.h sys/proc_info.h sys/kern_control.h net/route.h mach/mach_vm.h mach/shared_region.h sys/ptrace.h crt_externs.h
la seguente invocazione cmake dovrebbe darti tutti gli indizi di cui hai bisogno:
cmake -G "Ninja" -DCMAKE_OSX_ARCHITECTURES="armv7;armv7s;arm64" -DCMAKE_TOOLCHAIN_FILE=../cmake/platforms/iOS.cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=Off -DLLVM_INCLUDE_TESTS=Off -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_ENABLE_BACKTRACES=Off ../
ninja debugserver
Dovrai quindi firmare o falsificare la firma del binario debugserver e sostituire quello presente nel progetto xcode fornito.
Firma del codice
Il progetto dell'exploit, per impostazione predefinita, installerà una versione migliorata dell'hook amfid di mach_portal (questa volta con supporto funzionante per i file fat e senza offset hardcoded :) )
Se vuoi solo eseguire il debug, dovresti essere in grado di firmare il binario debugserver con il tuo certificato e disabilitare l'hook amfid.
Se usi l'hook amfid, tieni presente che l'app in cui è in esecuzione è ancora soggetta ai limiti di esecuzione del codice in background. L'app richiede più tempo tramite beginBackgroundTaskWithName.
Utilizzo:
Collega il tuo host e l'iDevice di destinazione alla stessa rete wireless e annota l'indirizzo IP dell'iDevice.
Compila ed esegui l'app dell'exploit. Consiglio di farlo all'interno di xcode, ma funzionerà anche in modo autonomo.
Aspetta un po'. Se non funziona dopo un paio di minuti, riavvia forzatamente il dispositivo, aspetta un po' e riprova.
Se funziona, dovrebbe stampare “patched debugserver listening on port 1234”
Se fai clic sul pulsante “get process listing” dovresti vedere l'output di ps
(è più facile vedere l'output se usi xcode, ma l'exploit mostrerà comunque l'output)
Cerca il processo di destinazione che ti interessa debuggare e annota il suo pid.
sull'host avvia lldb dalla riga di comando: $ lldb (lldb)
imposta la piattaforma su ios remote: (lldb) platform select remote-ios
connettiti allo stub del debugserver: (lldb) process connect connect://192.168.0.172:1234
(dove 192.168.0.172 è l'indirizzo IP dell'iDevice)
aggancia il processo che ti interessa: (lldb) attach 55
...aspetta un po', debugserver è in esecuzione in modalità verbose...
Process 55 stopped
Executable module set to "/usr/libexec/backboardd".
sei agganciato :)
imposta un breakpoint: (lldb) break set --name malloc Breakpoint 1: 4 locations.
continua:
(lldb) c Process 55 resuming Process 55 stopped
malloc libsystem_malloc.dylibmalloc:
-> 0x1936161e0 <+0>: stp x20, x19, [sp, #-0x20]!
0x1936161e4 <+4>: stp x29, x30, [sp, #0x10]
0x1936161e8 <+8>: add x29, sp, #0x10 ; =0x10ottieni un backtrace:
(lldb) bt
malloc frame #1: 0x0000000100099648 backboardd_mh_execute_header + 71240
frame #2: 0x00000001945bf218 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56 frame #3: 0x00000001945be9cc CoreFoundation__CFRunLoopDoSource1 + 436
frame #4: 0x00000001945bc4b0 CoreFoundation__CFRunLoopRun + 1840 frame #5: 0x00000001944ea2b8 CoreFoundationCFRunLoopRunSpecific + 444
frame #6: 0x0000000194537b44 CoreFoundationCFRunLoopRun + 112 frame #7: 0x00000001000a5ba8 backboardd_mh_execute_header + 121768
frame #8: 0x00000001000a5bec backboardd_mh_execute_header + 121836 frame #9: 0x00000001936a5850 libsystem_pthread.dylib_pthread_body + 240
frame #10: 0x00000001936a5760 libsystem_pthread.dylib_pthread_start + 284 frame #11: 0x00000001936a2d94 libsystem_pthread.dylibthread_start + 4Risoluzione dei problemi:
Installa l'ultima versione di XCode (sviluppato e testato con 8.3.3) Se la connessione di lldb fallisce, assicurati di avere installato l'SDK per la versione iOS di destinazione.
Avvertenze:
Spero di sistemare queste cose ma al momento sono molto occupato, scusa!
Esecuzione di altri PoC:
Se inserisci un binario nella cartella pocs di questo progetto, puoi far eseguire all'exploit quel binario selezionandolo nell'interfaccia sul dispositivo e facendo clic su "exec bundle binary".
"Continuerà comunque a essere eseguito all'interno della sandbox dell'app, ma se l'app ha un simbolo chiamato privileged_task_port gli verrà concesso un send right al task port di launchd. La cartella triple_fetch_sdk contiene un progetto di esempio che mostra come usare tutto ciò per costruire PoC, ad esempio per innescare comportamenti in processi interessanti che puoi poi debuggare usando il debugserver.
Contiene anche le API remote call/ports/files/memory che ti permettono di chiamare facilmente funzioni in altri processi e spostare file descriptor, mach port e memoria.
(1) [https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html] (2) [https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html] (3) [http://newosxbook.com/articles/PST2.html] (4) [https://gist.github.com/thlorenz/a068c202f2487ec13809]
Questo progetto contiene codice (debugserver.diff) e un binario (debugserver) basati su lldb, soggetti alla seguente licenza:
University of Illinois/NCSA Open Source License
Copyright (c) 2010 Apple Inc. Tutti i diritti riservati.
Sviluppato da:
LLDB Team
Con la presente viene concessa l'autorizzazione, a titolo gratuito, a chiunque ottenga una copia di questo software e dei relativi file di documentazione (il "Software"), a trattare il Software senza alcuna restrizione, inclusi, senza limitazione, i diritti di utilizzare, copiare, modificare, fondere, pubblicare, distribuire, concedere in sublicenza e/o vendere copie del Software, e di consentire alle persone a cui il Software viene fornito di fare altrettanto, alle seguenti condizioni:
Le redistribuzioni del codice sorgente devono conservare l'avviso di copyright sopra indicato, questo elenco di condizioni e le seguenti clausole di esclusione di responsabilità.
Le redistribuzioni in forma binaria devono riprodurre l'avviso di copyright sopra indicato, questo elenco di condizioni e le seguenti clausole di esclusione di responsabilità nella documentazione e/o negli altri materiali forniti con la distribuzione.
Né i nomi del LLDB Team, né i nomi dei detentori del copyright, né i nomi dei suoi contributori possono essere usati per approvare o promuovere prodotti derivati da questo Software senza una specifica autorizzazione scritta preventiva.
IL SOFTWARE È FORNITO "COSÌ COM'È", SENZA GARANZIE DI ALCUN TIPO, ESPRESSE O IMPLICITE, INCLUSI, A TITOLO ESEMPLIFICATIVO, LE GARANZIE DI COMMERCIABILITÀ, IDONEITÀ PER UNO SCOPO PARTICOLARE E NON VIOLAZIONE. IN NESSUN CASO I CONTRIBUTORI O I DETENTORI DEL COPYRIGHT SARANNO RESPONSABILI PER QUALSIASI RIVENDICAZIONE, DANNO O ALTRA RESPONSABILITÀ, SIA IN UN'AZIONE CONTRATTUALE, EXTRACONTRATTUALE O DI ALTRO TIPO, DERIVANTE DA, O IN CONNESSIONE CON IL SOFTWARE O CON L'USO O ALTRE OPERAZIONI CON IL SOFTWARE.