macOS Apps - Inspecting, debugging and Fuzzing
Last updated
Last updated
Impara e pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Puoi scaricare disarm da qui.
Puoi scaricare jtool2 qui o installarlo con brew
.
jtool è deprecato a favore di disarm
Codesign
si trova in macOS mentre ldid
si trova in iOS
SuspiciousPackage è uno strumento utile per ispezionare i file .pkg (installer) e vedere cosa c'è dentro prima di installarli.
Questi installer hanno script bash preinstall
e postinstall
che gli autori di malware di solito abusano per persist il malware.
Questo strumento consente di mount i file immagine disco Apple (.dmg) per ispezionarli prima di eseguire qualsiasi cosa:
It will be mounted in /Volumes
Controlla l'alta entropia
Controlla le stringhe (se ci sono quasi nessuna stringa comprensibile, impacchettato)
Il pacchetto UPX per MacOS genera una sezione chiamata "__XHDR"
Nota che i programmi scritti in Objective-C mantengono le loro dichiarazioni di classe quando compilati in Mach-O binaries. Tali dichiarazioni di classe includono il nome e il tipo di:
Le interfacce definite
I metodi dell'interfaccia
Le variabili di istanza dell'interfaccia
I protocolli definiti
Nota che questi nomi potrebbero essere offuscati per rendere più difficile il reverse engineering del binario.
Quando una funzione viene chiamata in un binario che utilizza Objective-C, il codice compilato invece di chiamare quella funzione, chiamerà objc_msgSend
. Che chiamerà la funzione finale:
I parametri che questa funzione si aspetta sono:
Il primo parametro (self) è "un puntatore che punta all'istanza della classe che deve ricevere il messaggio". In altre parole, è l'oggetto su cui viene invocato il metodo. Se il metodo è un metodo di classe, questo sarà un'istanza dell'oggetto classe (nel suo insieme), mentre per un metodo di istanza, self punterà a un'istanza instanziata della classe come oggetto.
Il secondo parametro, (op), è "il selettore del metodo che gestisce il messaggio". Ancora una volta, in termini più semplici, questo è solo il nome del metodo.
I parametri rimanenti sono eventuali valori richiesti dal metodo (op).
Vedi come ottenere queste informazioni facilmente con lldb
in ARM64 in questa pagina:
x64:
Argomento
Registro
(per) objc_msgSend
1° argomento
rdi
self: oggetto su cui viene invocato il metodo
2° argomento
rsi
op: nome del metodo
3° argomento
rdx
1° argomento al metodo
4° argomento
rcx
2° argomento al metodo
5° argomento
r8
3° argomento al metodo
6° argomento
r9
4° argomento al metodo
7°+ argomento
rsp+ (sullo stack)
5°+ argomento al metodo
Dynadump è uno strumento per class-dump di binari Objective-C. Il github specifica dylibs ma questo funziona anche con eseguibili.
Al momento della scrittura, questo è attualmente quello che funziona meglio.
class-dump è lo strumento originale per generare dichiarazioni per le classi, categorie e protocolli in codice formattato ObjectiveC.
È vecchio e non mantenuto, quindi probabilmente non funzionerà correttamente.
iCDump è un dump di classi Objective-C moderno e multipiattaforma. Rispetto agli strumenti esistenti, iCDump può funzionare indipendentemente dall'ecosistema Apple ed espone binding Python.
Con i binari Swift, poiché c'è compatibilità con Objective-C, a volte puoi estrarre dichiarazioni utilizzando class-dump ma non sempre.
Con i comandi jtool -l
o otool -l
è possibile trovare diverse sezioni che iniziano con il prefisso __swift5
:
Puoi trovare ulteriori informazioni sulle informazioni memorizzate in queste sezioni in questo post del blog.
Inoltre, i binari Swift potrebbero avere simboli (ad esempio, le librerie devono memorizzare simboli affinché le loro funzioni possano essere chiamate). I simboli di solito contengono informazioni sul nome della funzione e sugli attributi in un modo poco chiaro, quindi sono molto utili e ci sono "demanglers" che possono ottenere il nome originale:
Nota che per eseguire il debug dei binari, SIP deve essere disabilitato (csrutil disable
o csrutil enable --without debug
) oppure copiare i binari in una cartella temporanea e rimuovere la firma con codesign --remove-signature <binary-path>
o consentire il debug del binario (puoi usare questo script)
Nota che per strumentare i binari di sistema, (come cloudconfigurationd
) su macOS, SIP deve essere disabilitato (rimuovere solo la firma non funzionerà).
macOS espone alcune API interessanti che forniscono informazioni sui processi:
proc_info
: Questo è il principale che fornisce molte informazioni su ciascun processo. Devi essere root per ottenere informazioni su altri processi, ma non hai bisogno di diritti speciali o porte mach.
libsysmon.dylib
: Consente di ottenere informazioni sui processi tramite funzioni esposte da XPC, tuttavia, è necessario avere il diritto com.apple.sysmond.client
.
Stackshotting è una tecnica utilizzata per catturare lo stato dei processi, inclusi gli stack di chiamate di tutti i thread in esecuzione. Questo è particolarmente utile per il debug, l'analisi delle prestazioni e la comprensione del comportamento del sistema in un momento specifico. Su iOS e macOS, lo stackshotting può essere eseguito utilizzando diversi strumenti e metodi come gli strumenti sample
e spindump
.
Questo strumento (/usr/bini/ysdiagnose
) raccoglie fondamentalmente molte informazioni dal tuo computer eseguendo decine di comandi diversi come ps
, zprint
...
Deve essere eseguito come root e il demone /usr/libexec/sysdiagnosed
ha diritti molto interessanti come com.apple.system-task-ports
e get-task-allow
.
Il suo plist si trova in /System/Library/LaunchDaemons/com.apple.sysdiagnose.plist
che dichiara 3 MachServices:
com.apple.sysdiagnose.CacheDelete
: Elimina vecchi archivi in /var/rmp
com.apple.sysdiagnose.kernel.ipc
: Porta speciale 23 (kernel)
com.apple.sysdiagnose.service.xpc
: Interfaccia in modalità utente tramite la classe Obj-C Libsysdiagnose
. Tre argomenti in un dizionario possono essere passati (compress
, display
, run
)
MacOS genera molti log che possono essere molto utili quando si esegue un'applicazione cercando di capire cosa sta facendo.
Inoltre, ci sono alcuni log che conterranno il tag <private>
per nascondere alcune informazioni identificabili dell'utente o del computer. Tuttavia, è possibile installare un certificato per rivelare queste informazioni. Segui le spiegazioni da qui.
Nel pannello sinistro di Hopper è possibile vedere i simboli (Etichette) del binario, l'elenco delle procedure e delle funzioni (Proc) e le stringhe (Str). Queste non sono tutte le stringhe ma quelle definite in diverse parti del file Mac-O (come cstring o objc_methname
).
Nel pannello centrale puoi vedere il codice disassemblato. E puoi vederlo in un disassemblaggio grezzo, come grafico, come decompilato e come binario cliccando sull'icona rispettiva:
Facendo clic destro su un oggetto di codice puoi vedere riferimenti a/da quell'oggetto o persino cambiare il suo nome (questo non funziona nel pseudocodice decompilato):
Inoltre, nella parte centrale in basso puoi scrivere comandi python.
Nel pannello destro puoi vedere informazioni interessanti come la cronologia di navigazione (così sai come sei arrivato alla situazione attuale), il grafico delle chiamate dove puoi vedere tutte le funzioni che chiamano questa funzione e tutte le funzioni che questa funzione chiama, e informazioni sulle variabili locali.
Consente agli utenti di accedere alle applicazioni a un livello estremamente basso e fornisce un modo per gli utenti di tracciare programmi e persino cambiare il loro flusso di esecuzione. Dtrace utilizza sonde che sono posizionate in tutto il kernel e si trovano in posizioni come l'inizio e la fine delle chiamate di sistema.
DTrace utilizza la funzione dtrace_probe_create
per creare una sonda per ciascuna chiamata di sistema. Queste sonde possono essere attivate nel punto di ingresso e uscita di ciascuna chiamata di sistema. L'interazione con DTrace avviene tramite /dev/dtrace che è disponibile solo per l'utente root.
Per abilitare Dtrace senza disabilitare completamente la protezione SIP puoi eseguire in modalità di recupero: csrutil enable --without dtrace
Puoi anche dtrace
o dtruss
binari che hai compilato.
Le sonde disponibili di dtrace possono essere ottenute con:
Il nome della sonda è composto da quattro parti: il fornitore, il modulo, la funzione e il nome (fbt:mach_kernel:ptrace:entry
). Se non specifichi alcune parti del nome, Dtrace applicherà quella parte come un carattere jolly.
Per configurare DTrace per attivare le sonde e specificare quali azioni eseguire quando si attivano, dovremo utilizzare il linguaggio D.
Una spiegazione più dettagliata e ulteriori esempi possono essere trovati in https://illumos.org/books/dtrace/chp-intro.html
Esegui man -k dtrace
per elencare gli script DTrace disponibili. Esempio: sudo dtruss -n binary
In linea
script
È una struttura di tracciamento del kernel. I codici documentati possono essere trovati in /usr/share/misc/trace.codes
.
Strumenti come latency
, sc_usage
, fs_usage
e trace
lo utilizzano internamente.
Per interfacciarsi con kdebug
, si utilizza sysctl
sul namespace kern.kdebug
e i MIB da utilizzare possono essere trovati in sys/sysctl.h
, con le funzioni implementate in bsd/kern/kdebug.c
.
Per interagire con kdebug con un client personalizzato, questi sono solitamente i passaggi:
Rimuovere le impostazioni esistenti con KERN_KDSETREMOVE
Impostare il tracciamento con KERN_KDSETBUF e KERN_KDSETUP
Usare KERN_KDGETBUF per ottenere il numero di voci del buffer
Ottenere il proprio client dal tracciamento con KERN_KDPINDEX
Abilitare il tracciamento con KERN_KDENABLE
Leggere il buffer chiamando KERN_KDREADTR
Per abbinare ogni thread al suo processo, chiamare KERN_KDTHRMAP.
Per ottenere queste informazioni, è possibile utilizzare lo strumento Apple trace
o lo strumento personalizzato kDebugView (kdv).
Nota che Kdebug è disponibile solo per 1 cliente alla volta. Quindi solo uno strumento alimentato da k-debug può essere eseguito contemporaneamente.
Le API ktrace_*
provengono da libktrace.dylib
, che avvolge quelle di Kdebug
. Quindi, un client può semplicemente chiamare ktrace_session_create
e ktrace_events_[single/class]
per impostare callback su codici specifici e poi avviarlo con ktrace_start
.
Puoi utilizzare questo anche con SIP attivato.
Puoi utilizzare come client l'utilità ktrace
:
Or tailspin
.
Questo è usato per fare un profiling a livello di kernel ed è costruito utilizzando le chiamate Kdebug
.
Fondamentalmente, la variabile globale kernel_debug_active
viene controllata e se è impostata chiama kperf_kdebug_handler
con il codice Kdebug
e l'indirizzo del frame del kernel chiamante. Se il codice Kdebug
corrisponde a uno selezionato, ottiene le "azioni" configurate come un bitmap (controlla osfmk/kperf/action.h
per le opzioni).
Kperf ha anche una tabella MIB sysctl: (come root) sysctl kperf
. Questi codici possono essere trovati in osfmk/kperf/kperfbsd.c
.
Inoltre, un sottoinsieme della funzionalità di Kperf risiede in kpc
, che fornisce informazioni sui contatori di prestazioni della macchina.
ProcessMonitor è uno strumento molto utile per controllare le azioni relative ai processi che un processo sta eseguendo (ad esempio, monitorare quali nuovi processi un processo sta creando).
SpriteTree è uno strumento che stampa le relazioni tra i processi.
Devi monitorare il tuo mac con un comando come sudo eslogger fork exec rename create > cap.json
(il terminale che lancia questo richiede FDA). E poi puoi caricare il json in questo strumento per visualizzare tutte le relazioni:
FileMonitor consente di monitorare eventi di file (come creazione, modifiche e cancellazioni) fornendo informazioni dettagliate su tali eventi.
Crescendo è uno strumento GUI con l'aspetto e la sensazione che gli utenti Windows potrebbero conoscere da Procmon di Microsoft Sysinternal. Questo strumento consente di registrare vari tipi di eventi che possono essere avviati e fermati, consente il filtraggio di questi eventi per categorie come file, processo, rete, ecc., e fornisce la funzionalità di salvare gli eventi registrati in un formato json.
Apple Instruments fanno parte degli strumenti per sviluppatori di Xcode – utilizzati per monitorare le prestazioni delle applicazioni, identificare leak di memoria e tracciare l'attività del filesystem.
Consente di seguire le azioni eseguite dai processi:
Taskexplorer è utile per vedere le librerie utilizzate da un binario, i file che sta usando e le connessioni di rete. Controlla anche i processi binari contro virustotal e mostra informazioni sul binario.
In questo post del blog puoi trovare un esempio su come debuggare un daemon in esecuzione che utilizzava PT_DENY_ATTACH
per prevenire il debugging anche se SIP era disabilitato.
lldb è lo strumento de facto per il debugging di binari macOS.
Puoi impostare il sapore intel quando usi lldb creando un file chiamato .lldbinit
nella tua cartella home con la seguente riga:
All'interno di lldb, dump un processo con process save-core
(lldb) Comando
Descrizione
run (r)
Inizia l'esecuzione, che continuerà senza interruzioni fino a quando non viene colpito un breakpoint o il processo termina.
process launch --stop-at-entry
Inizia l'esecuzione fermandosi al punto di ingresso
continue (c)
Continua l'esecuzione del processo in debug.
nexti (n / ni)
Esegui la prossima istruzione. Questo comando salterà le chiamate di funzione.
stepi (s / si)
Esegui la prossima istruzione. A differenza del comando nexti, questo comando entrerà nelle chiamate di funzione.
finish (f)
Esegui il resto delle istruzioni nella funzione corrente (“frame”) restituisci e ferma.
control + c
Metti in pausa l'esecuzione. Se il processo è stato eseguito (r) o continuato (c), questo causerà l'arresto del processo ...dove si trova attualmente in esecuzione.
breakpoint (b)
b main
#Qualsiasi funzione chiamata main
b <binname>`main
#Funzione principale del bin
b set -n main --shlib <lib_name>
#Funzione principale del bin indicato
breakpoint set -r '\[NSFileManager .*\]$'
#Qualsiasi metodo NSFileManager
breakpoint set -r '\[NSFileManager contentsOfDirectoryAtPath:.*\]$'
break set -r . -s libobjc.A.dylib
# Interrompi in tutte le funzioni di quella libreria
b -a 0x0000000100004bd9
br l
#Elenco dei breakpoint
br e/dis <num>
#Abilita/Disabilita breakpoint
breakpoint delete <num>
help
help breakpoint #Ottieni aiuto sul comando breakpoint
help memory write #Ottieni aiuto per scrivere nella memoria
reg
x/s <reg/memory address>
Visualizza la memoria come una stringa terminata da null.
x/i <reg/memory address>
Visualizza la memoria come istruzione assembly.
x/b <reg/memory address>
Visualizza la memoria come byte.
print object (po)
Questo stamperà l'oggetto referenziato dal parametro
po $raw
{
dnsChanger = {
"affiliate" = "";
"blacklist_dns" = ();
Nota che la maggior parte delle API o dei metodi Objective-C di Apple restituiscono oggetti, e quindi dovrebbero essere visualizzati tramite il comando “print object” (po). Se po non produce un output significativo usa x/b
memory
memory read 0x000.... memory read $x0+0xf2a memory write 0x100600000 -s 4 0x41414141 #Scrivi AAAA in quell'indirizzo memory write -f s $rip+0x11f+7 "AAAA" #Scrivi AAAA nell'indirizzo
disassembly
dis #Disassembla la funzione corrente
dis -n <funcname> #Disassembla la funzione
dis -n <funcname> -b <basename> #Disassembla la funzione dis -c 6 #Disassembla 6 righe dis -c 0x100003764 -e 0x100003768 # Da un add fino all'altro dis -p -c 4 # Inizia nell'indirizzo corrente disassemblando
parray
parray 3 (char **)$x1 # Controlla l'array di 3 componenti nel registro x1
image dump sections
Stampa la mappa della memoria del processo corrente
image dump symtab <library>
image dump symtab CoreNLP
#Ottieni l'indirizzo di tutti i simboli da CoreNLP
Quando si chiama la funzione objc_sendMsg
, il registro rsi contiene il nome del metodo come stringa terminata da null (“C”). Per stampare il nome tramite lldb fare:
(lldb) x/s $rsi: 0x1000f1576: "startMiningWithPort:password:coreCount:slowMemory:currency:"
(lldb) print (char*)$rsi:
(char *) $1 = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"
(lldb) reg read $rsi: rsi = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"
Il comando sysctl hw.model
restituisce "Mac" quando l'host è un MacOS ma qualcosa di diverso quando è una VM.
Giocando con i valori di hw.logicalcpu
e hw.physicalcpu
alcuni malware cercano di rilevare se è una VM.
Alcuni malware possono anche rilevare se la macchina è basata su VMware in base all'indirizzo MAC (00:50:56).
È anche possibile scoprire se un processo è in fase di debug con un semplice codice come:
if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //processo in fase di debug }
Può anche invocare la chiamata di sistema ptrace
con il flag PT_DENY_ATTACH
. Questo preclude a un debugger di attaccarsi e tracciare.
Puoi controllare se la funzione sysctl
o ptrace
è stata importata (ma il malware potrebbe importarla dinamicamente)
Come notato in questo scritto, “Sconfiggere le tecniche Anti-Debug: varianti di macOS ptrace” : “Il messaggio Process # exited with status = 45 (0x0000002d) è di solito un chiaro segnale che il target di debug sta usando PT_DENY_ATTACH”
I core dumps vengono creati se:
kern.coredump
sysctl è impostato su 1 (per impostazione predefinita)
Se il processo non era suid/sgid o kern.sugid_coredump
è 1 (per impostazione predefinita è 0)
Il limite AS_CORE
consente l'operazione. È possibile sopprimere la creazione di core dump chiamando ulimit -c 0
e riabilitarli con ulimit -c unlimited
.
In questi casi il core dump viene generato secondo kern.corefile
sysctl e di solito memorizzato in /cores/core/.%P
.
ReportCrash analizza i processi in crash e salva un rapporto di crash su disco. Un rapporto di crash contiene informazioni che possono aiutare uno sviluppatore a diagnosticare la causa di un crash.
Per le applicazioni e altri processi in esecuzione nel contesto di launchd per utente, ReportCrash viene eseguito come un LaunchAgent e salva i rapporti di crash nella cartella ~/Library/Logs/DiagnosticReports/
dell'utente.
Per i demoni, altri processi in esecuzione nel contesto di launchd di sistema e altri processi privilegiati, ReportCrash viene eseguito come un LaunchDaemon e salva i rapporti di crash nella cartella /Library/Logs/DiagnosticReports
del sistema.
Se sei preoccupato che i rapporti di crash siano inviati ad Apple, puoi disabilitarli. In caso contrario, i rapporti di crash possono essere utili per capire come è andato in crash un server.
Durante il fuzzing su MacOS, è importante non permettere al Mac di andare in sospensione:
systemsetup -setsleep Never
pmset, Preferenze di Sistema
Se stai fuzzando tramite una connessione SSH, è importante assicurarsi che la sessione non si disconnetta. Quindi modifica il file sshd_config con:
TCPKeepAlive Yes
ClientAliveInterval 0
ClientAliveCountMax 0
Controlla la seguente pagina per scoprire come puoi trovare quale app è responsabile della gestione dello schema o protocollo specificato:
macOS File Extension & URL scheme app handlersÈ interessante trovare i processi che gestiscono i dati di rete:
Oppure usa netstat
o lsof
Funziona per strumenti CLI
Funziona "senza problemi" con strumenti GUI macOS. Nota che alcune app macOS hanno requisiti specifici come nomi di file unici, l'estensione corretta, e devono leggere i file dalla sandbox (~/Library/Containers/com.apple.Safari/Data
)...
Alcuni esempi:
Impara e pratica Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)