2015-02-16 12 views
19

Stavo leggendo su Cycript e Cydia Substrate e come possono essere utilizzati per attacchi di iniezione di codice su un app iOS. Codice come questo dovrebbe spaventarti se stai lavorando in un ambiente ad alta sicurezza. (Ignorare il etc/parte/password, basta considerare la possibilità di sostituire OriginalMessage con crackedMessage.)Swift è vulnerabile all'iniezione di codice?

cy# MS.hookFunction(fopen, function(path, mode) { 
cy>  if (path == "/etc/passwd") 
cy>   path = "/var/passwd-fake"; 
cy>  var file = (*oldf)(path, mode); 
cy>  log.push([path, mode, file]); 
cy>  return file; 
cy> }, oldf) 

ho letto un blog (che non mi risparmio), che ha detto che non era così Swift vulnerabile come Objective-C poiché non era così dinamico. Poi, di nuovo, ho anche letto che puoi fare method swizzling in Swift quindi non mi è chiaro se Swift offra qualche protezione contro gli attacchi di iniezione di codice.

Quindi, Swift è vulnerabile agli attacchi di iniezione di codice?

risposta

36

In definitiva, non v'è alcun modo per impedire a qualcuno di dirottare il programma se si lascia correre sul proprio dispositivo. Ci sono modi per renderlo più difficile, ma non c'è modo di renderlo impossibile.

posso pensare di questi modi principali di iniettare codice in un'applicazione:

  • swizzling metodi Objective-C con il runtime;
  • swizzling metodi virtuali Swift analizzando l'eseguibile e calcolando i bit da modificare;
  • modifica dei target di chiamata;
  • swizzling dei simboli importati cambiando i target degli stub dei simboli;
  • utilizzando dyld per caricare forzatamente le librerie o modificare le librerie caricate dal programma;
  • sostituendo le librerie a cui il programma si collega.

E non c'è modo efficace al 100% per evitare qualsiasi di questi in un ambiente che l'utente controlla completamente. Dovresti decidere se essere preoccupato o meno a seconda del modello di minaccia.

Swizzling metodi Objective-C con il runtime

Metodo swizzling è una tecnica in cui si modifica l'attuazione di un metodo a runtime con, codice diverso arbitrario (di solito per uno scopo diverso). I casi di uso comune stanno bypassando i controlli o i parametri di registrazione.

Swizzling in Objective-C era una cosa enorme, perché il runtime ha bisogno di metadati che identifica ogni metodo e di ogni campo di istanza. Non conosco nessun altro linguaggio che compili al codice macchina nativo e che mantenga molti metadati in giro. Se hai qualcosa come -[AccessControl validatePassword:], lo stai rendendo davvero facile per i cattivi. Con method_setImplementation, questo è solo l'accattonaggio che accada.

classi Come Swift possono ereditare dalle classi Objective-C, questo è ancora qualcosa da cercare. Tuttavia, i nuovi metodi su classi che ereditano da una classe Objective-C sono esposti al runtime Objective-C solo se hanno l'attributo @objc (o se la classe stessa ha l'attributo @objc), quindi limita la superficie di attacco rispetto all'obiettivo -C.

Inoltre, il compilatore Swift può bypassare il runtime Objective-C per chiamare, devirtualize o metodi in linea Swift che non sono stati contrassegnati dynamic, anche se sono stati segnati @objc.Ciò significa che in alcuni casi, la rotazione potrebbe essere possibile solo per le chiamate inviate attraverso l'Objective-C.

E ovviamente, è del tutto impossibile se la classe o il metodo non è esposto al runtime Objective-C.

Swizzling metodi Swift virtuali analizzando il file eseguibile e capire i bit diritto di modificare

Tuttavia, non è necessario il runtime Objective-C per scambiare metodo implementazioni. Swift ha ancora tabelle virtuali per i suoi metodi virtuali e, a partire da febbraio 2015, si trovano nel segmento __DATA dell'eseguibile. È scrivibile, quindi dovrebbe essere possibile swizzle i metodi virtuali Swift se riesci a capire i bit giusti da cambiare. Non ci sono API convenienti per questo.

Le classi C++ possono essere modificate in modo simile, ma i metodi Swift sono virtuali per impostazione predefinita, la superficie di attacco è molto più grande. Il compilatore è autorizzato a devirtualizzare i metodi come un'ottimizzazione se non trova l'override, ma affidarsi alle ottimizzazioni del compilatore come funzionalità di sicurezza non è responsabile.

Per impostazione predefinita, gli eseguibili Swift implementati sono strip ped. Le informazioni per i simboli non public/open vengono scartate, e ciò rende l'identificazione dei simboli che si desidera modificare molto più difficile rispetto a Objective-C. I simboli Public/open non vengono rimossi perché si presume che altri client di codice esterni possano averne bisogno.

Tuttavia, se qualcuno individua l'implementazione della funzione che desidera scambiare, tutto ciò che devono fare è scrivere l'indirizzo della nuova implementazione nello slot della tabella virtuale corretto. Probabilmente avranno bisogno di creare il proprio parser Mach-O, ma questo non è certamente fuori dalla portata delle persone che fanno cose come Cycript.

Infine, i metodi final riducono questo rischio perché il compilatore non ha bisogno di chiamarli tramite il vtable. Inoltre, i metodi struct non sono mai virtuali.

chiamata Modifica rivolge

Se tutto il resto fallisce, l'attaccante può ancora camminare attraverso il vostro codice macchina e modificare le bl o call operandi delle istruzioni a dovunque che vorrebbero meglio. Questo è più complesso e abbastanza difficile/impossibile da ottenere al 100% con un metodo automatico, specialmente se mancano i simboli, ma qualcuno determinato abbastanza sarà in grado di farlo. Decidi se alla fine qualcuno troverà che vale la pena di farlo per la tua applicazione.

Questo funziona per metodi virtuali e non virtuali. È, tuttavia, estremamente difficile da fare quando il compilatore effettua chiamate in linea.

Swizzling simboli importati modificando simbolo obiettivi stub

Qualsiasi simbolo importati, a prescindere dalla lingua che è stato scritto con il linguaggio e è in uso da, è vulnerabile a swizzling. Questo perché i simboli esterni sono vincolati in fase di runtime. Ogni volta che si utilizza una funzione da una libreria esterna, il compilatore genera una voce in una tabella di ricerca. Questo è un esempio di ciò che una chiamata a fopen potrebbe apparire come se si ritorna vostro eseguibile a codice C:

FILE* locate_fopen(const char* a, const char* b) { 
    fopen_stub = dyld->locate("fopen"); // find actual fopen and replace stub pointer to it 
    return fopen_stub(a, b); 
} 

FILE* (*fopen_stub)(const char*, const char*) = &locate_fopen; 

int main() { 
    FILE* x = fopen_stub("hello.txt", "r"); 
} 

La chiamata iniziale al fopen_stub trova l'attuale fopen, e sostituisce l'indirizzo puntato da fopen_stub con esso.In questo modo, dyld non ha bisogno di risolvere le migliaia di simboli esterni usati dal tuo programma e dalle sue librerie prima che inizi a funzionare. Tuttavia, questo significa che un utente malintenzionato può sostituire fopen_stub con l'indirizzo di qualsiasi funzione che vorrebbero chiamare. Questo è ciò che fa l'esempio di Cycript.

A meno di scrivere il proprio linker e il linker dinamico, la vostra unica protezione contro questo tipo di attacco è di non usare librerie o framework condivisi. Questa non è una soluzione praticabile in un moderno ambiente di sviluppo, quindi probabilmente dovrai affrontarla.

Ci potrebbero essere dei modi per assicurarsi che gli stub vadano dove ci si aspetta che siano, ma sarebbe un po 'instabile, e questi controlli possono sempre essere eliminati da un determinato attaccante nop. Inoltre, non si è in grado di inserire questi controlli prima delle librerie condivise non si ha il controllo sui simboli di importazione delle chiamate. Questi controlli sarebbero anche inutili se l'attaccante decidesse di sostituire semplicemente la libreria condivisa con quella che controllano.

A parte, le chiusure di lancio consentono a dyld 3 di sostituire queste tabelle di ricerca con informazioni pre-associate. Non penso che le chiusure di lancio siano attualmente di sola lettura, ma sembra che potrebbero essere alla fine. Se lo sono, i simboli swizzling diventeranno più difficili.

Utilizzando dyld per forzare carico biblioteche o librerie di cambiamento che i carichi di programma

dyld supports biblioteche forza-caricamento nel vostro eseguibile. Questa funzionalità può essere utilizzata per sostituire quasi tutti i simboli importati utilizzati dall'eseguibile. Non ti piace il normale fopen? Scrivi un dylib che lo ridefinisce!

Dyld non collaborerà con questo metodo se l'eseguibile è contrassegnato come limitato. Ci sono three ways per raggiungere questo stato (cercare pruneEnvironmentVariables):

  • abilitare il bit setuid o il bit setgid sul file eseguibile;
  • firmare il codice e disporre dell'autorizzazione esclusiva per OS X "Limitato";
  • hanno una sezione chiamata __restrict in un segmento chiamato __RESTRICT.

È possibile creare la sezione __restrict e il segmento __RESTRICT previsti i seguenti "Altre Bandiere Linker":

-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null 

Si noti che tutti questi sono abbastanza facile da rompere. I bit setuid e setgid sono banali da cancellare quando l'utente controlla l'ambiente di esecuzione, una firma del codice è facile da rimuovere e la sezione o il segmento devono semplicemente essere rinominati per eliminare anche lo stato limitato.

Sostituzione delle librerie che il vostro link di programma contro

Se tutto il resto fallisce, un utente malintenzionato può ancora sostituire le librerie condivise che l'eseguibile utilizza per fargli fare ciò che vogliono. Non hai il controllo su questo.

tl; dr

iniezione di codice in un'applicazione Swift è più difficile di quanto non fosse per un'applicazione Objective-C, ma è ancora possibile. La maggior parte dei metodi che possono essere utilizzati per iniettare il codice sono indipendenti dalla lingua, il che significa che nessuna lingua ti renderà più sicuro.

Per la maggior parte, non c'è nulla che tu possa fare per proteggerti da questo. Finché l'utente controlla l'ambiente di esecuzione, il tuo codice è in esecuzione come ospite sul loro sistema e possono fare quasi quello che vogliono con esso.

+0

fantastico aggiornamento la tua risposta originale! Grazie mille. –

0

Si sta parlando di iniezioni di codice su dispositivi iOS jailbroken. Abbastanza semplice: l'utente ha rimosso la protezione del sistema operativo, quindi ora tutto va bene. Nessuna sicurezza. Se l'utente non ha rimosso volontariamente tale protezione, è impossibile entrare nello spazio degli indirizzi di un'applicazione.