Defending Against Activityjack Attacks

A number of media outlets reported on a research paper and USENIX conference presentation describing a way by which your users could be tricked into providing confidential information — passwords, credit card information, and such — to a piece of malware, rather than to your app.

The paper points out that there are ways of writing malware such that:

  • the malware can pop an activity in front of yours, and

  • do so at just the right time, to mimic one of your activities, such that the user thinks that the malware’s activity is actually yours and enters the confidential data into the malware activity

For the purposes of this blog post, I’ll refer to this as an “activityjack” attack. Just as a clickjacking attack tricks Web users into clicking on the wrong things, and just as a tapjacking attack steals Android touch events via a transparent layer on top of the screen, an activityjack attack steals input destined for your activity by interposing another activity on top of yours.

The particular means of implementing the activityjack attack outlined in the paper is a bit esoteric. What it does do, though, is illustrate that such an attack is possible. Half the battle with security is knowing what you need to defend against.

The paper outlines solutions to their particular flavor of activityjack attack that require OS modifications. That’s fine, and perhaps the Android project will implement that stuff. But it will take years for such changes to percolate through the Android device ecosystem. For example, tapjacking was “solved” in Android 4.0, but there are millions of people using devices older than that, even today. Hence, we need to think as much, if not more, about application-level solutions.

Let’s ignore the details of the particular approach from the paper. Let’s merely assume that an attacker can get their activity in front of ours at the right time, as there are less-esoteric ways of doing the same thing (e.g., via an AccessibilityService). How do we defend against that for critical activities, such as “login” activities that require the user enter a passphrase?

An activityjack attack has two key weaknesses:

  1. The attacker cannot see the screen, because on non-buggy devices, the attacker has no means of capturing a screenshot of our activity as it comes into the foreground. Hence, while the attacker can create an activity that tries to mimic ours, they can only do so statically, analyzing our activity’s UI on their development machine and creating their own lookalike.

  2. We know that our activity has left the foreground, as we are called with onPause() (and perhaps other lifecycle methods, depending upon the nature of the attacker).

Hence, one defense can be to include in our activity a secure element that cannot be mimicked ahead of time, then hide that element (or our whole UI) when we are no longer in the foreground.

This concept of a secure element is not new. Some financial services Web sites have taken this approach. As part of the user setting up their online banking account, the user chooses an image from a collection of clipart. On the Web page that collects the user’s passphrase, the page also shows this secure element. The user is taught that if they do not see their chosen image, then the Web page they are looking at is not really from their bank, and therefore they should not type in their passphrase.

This is not that hard to implement in Android. You too would allow the user to choose a piece of clipart, displaying that in an ImageView on your secure activity in onResume(). In onPause() you would hide that ImageView via setVisibility(View.INVISIBLE). That way:

  • Since the image is chosen by the user, the attacker is unlikely to mimic the same image

  • Since you are hiding the image when you are not in the foreground, the attacker cannot use a transparent region in their activity to have your image “peek through” their attacking activity

As a result, if the user is paying attention, the user should see either the wrong image or no image at all, and the user should realize that they are being activityjacked and therefore fail to proceed.

You might be tempted to do something else in response to your secure activity being replaced in the foreground by another app’s activity, such as pop up a warning dialog. However, there are plenty of valid scenarios when this would occur, such as an incoming phone call, and you have no reliable means of whitelisting all possible valid scenarios. There will be a high incidence of false positives, and that may not help the user. Having this as an user-selectable option is fine, but I would not go this route by default.

With luck, somebody will come up with a better defense, one that makes it more likely that the user will not provide confidential information to the attacker, yet not be so onerous that they get fed up with your app and uninstall you. However, this approach should be reasonably easy to implement and help defend your users from activityjacking attacks in critical activities.

Nervous about how the newest version of Android affects your app? Consider subscribing, then asking questions in the office hours chats!