TapJacking Attacks, a thorough guide LAST PART (3)
Recap
In PART 1 of this tutorial we went trough some basic theoretical concepts such as the Free Floating Windows (FFW), the SYSTEM_ALERT_WINDOW permission (SAW) and the Androidâs Window Manager. Finally we created an application that implements an FFW and added a view to it. In PART 2 we rendered our FFW âindependentâ from the parent activity and focused on its look, size and position on the screen.
In this, final part of the tutorial, we are going to cover more advanced topics in regards to the FFW appearance and see how an application may use these techniques to literally âimitateâ any type of dialog of a potential target application. We will also talk about the âfeelâ of the FFW and explain how it is possible to interact with the user while at the same time to hijacking the userâs interaction with other apps. Finally we will suggest a mitigation on how to protect an application from these type of attacks.
Creating more complex views
At the second part of this write up we created a Free Floating Window (FFW) and âattachedâ a button to it:
This is quite cool but far away from implementing a view that someone might leverage during a Tap-Jacking attack. Lets take for example the following dialog, where the tap-jacking objective would be to âchangeâ the userâs decision from ACTION 1 to ACTION 2, by modifying the âDialog Headerâ and âDialog body textâ:
How the humble green transparent button that we created in PART2 can imitate the dialog above or even more complex dialogs ? Before we answer that question, let us discuss about the LayoutInflater.
The LayoutInflater
According to the Android Developers documentation, a LayoutInflater instantiates a layout XML file into its corresponding View
objects[1]. For the non-Android developers (like me), an Android user interface can be created either at run time by using View/ViewGroup objects or the UI components may be declared in simple XML files which can be found in the res/layout folder[2]. To get an idea of how such an XML file looks like, simply create an Android project and navigate to the particular folder:
Simply said, a layout inflater will parse an XML Layout file and return a view via the inflate function.
Lets create a new Layout by right clicking on the layout folder and choosing New->Layout Resource File. The android studio will create, the requested layout and add the corresponding xml file to the specific folder:
The good news is that you donât have to add anything to the XML file as the Android Studio will do what is required in the background. All you have to do is to use its Design feature by simply dragging and dropping the desired components to the created layout:
Finally lets add the code to visualise what we did so far:
Create a LayoutInflater
LayoutInflater layoutInflater = getLayoutInflater();
Get the View instance returned by the inflate function:
View mLayout = layoutInflater.inflate(R.layout.tapjacking_dialog,null);
Add the view to the FFW:
windowManager.addView(mLayout,params);
Run the app:
Click through
The idea behind this capability is not to âconsumeâ the userâs touch but to dispatch it to a point on the screen where the outcome of the action can be leveraged in behalf of the attacker.
For example imagine the following scenario:
A hactivistâs application com.foo.a requests from Bob to top-up the amount of 1$ for charity reasons but sends a request for 100$ to the Bobâs bank. The bank will send a push notification to the application com.bar.bank in order to request the user to approve the transaction. Subsequently, the bank app will trigger a pop up a dialog asking the user to approve the hactivistâs request:
âcom.foo.a requests requested the amount of 100$, click on the OK button to proceed with the transactionâ
As Bob was prompted to contribute 1$ in the first place, the above transaction will be rejected due to the 100 times higher amount. Lets now assume that the hactivistâs app uses an overlay to cover the bankâs legitimate message with the following:
âcom.foo.a requests requested the amount of 1$, click on the OK button to proceed with the transactionâ
As Bob wonât notice any inconsistency, will click on the com.foo.aâs OK button. If the OK button wonât consume the âclickâ, this will be dispatched to the view bellow the overlay.
The result is obvious⌠Bob just approved a 100$ transaction ⌠lets hope for charity reasons:
Layout Parameters Again
Lets recall the LayoutParams instantiation from PART1:
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(1200,1200,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
And letâs focus on the FLAG_NOT_TOUCHABLE flag starting by the Android Developerâs definition:
The intention of this flag is to leave the touch to be handled by some window below this window (in Z order).
This simply means that despite the fact that the user will click on the view attached on the specific layout, this click will be dispatched to the window bellow. To better understand what this means, start your default android browser and navigate to a web page. Then start the application we have created so far:
Now scroll the page to a position where the link is covered by the âOKâ button and subsequently click on the button. As you will probably notice the the âclickâ will be sent to the browser instead of being consumed by our application.
Get notified but donât consume
To wrap up on what we have done so far:
- We created a Free Floating Window and âattachedâ a view that may imitate any type of dialog.
- We explained what is the click-trough capability
- We showed how the userâs touch can be dispatched from a View A to View B, assuming that A is on the Top of B
Assuming that View A is attached to an FFW which sets the FLAG_NOT_TOUCHABLE , it is important to understand that this View wonât get notified for a touch event.
Assume for example that we want to dismiss the View A by the time that the user has clicked on it and the touch has been dispatched to View B. How we interact with an event that we wonât get a notification that it took place ?
The FLAG_WATCH_OUTSIDE_TOUCH may be used to receive a single special MotionEvent with the action MotionEvent.ACTION_OUTSIDE for touches that occur outside of a window. Note that you will not receive the full down/move/up gesture, only the location of the first down as an ACTION_OUTSIDE [1].
Let us use the specific flag, by using the code bellow, and observe the behaviour of the FFW in regards to the userâs touch:
Button button = new Button(getApplicationContext());
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(1200,1200, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSPARENT);
params.x = 0;
params.y = 0;
windowManager.addView(button,params);
onBackPressed();
The code is quite simple as it creates a Button (button) and adds it to the FFW that we created. Let us also define how this button will behave when the user touches the screen:
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("onTouch Triggered with action type:" + event.getAction());
return false;
}
});
Let us now run the application and navigate to the Google results screen:
By clicking the button above, we may observe the following behaviour:
- The YouTube application will be triggered, which is something that we expected to happen:
2. The buttonâs onTouch callback will also be triggered:
The action type is 0x4:
A movement has happened outside of the normal bounds of the UI element. This does not provide a full gesture, but only the initial location of the movement/touch [1].
Putting it all together
Let us now summarise the steps that we did so far and finalise our code:
- Create the desired XML Layout
2. Create a LayoutInflater in order and inflate the XML created above:
LayoutInflater layoutInflater = getLayoutInflater();
View mLayout = layoutInflater.inflate(R.layout.tapjacking_dialog,null);
3. Create an Window manager instance:
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
4. Create a LayoutParameters instance and add the respective flags and desired attributes:
WindowManager.LayoutParams params = new WindowManager.LayoutParams(1200,1200, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSPARENT);
5. Add the view from step 2 to the FFW and remove the MainActivity from the background:
windowManager.addView(mLayout,params);
onBackPressed();
6. Finally add the respective code in order to react on userâs touch:
mLayout.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
System.out.println("onTouch Triggered with action type:" + event.getAction());
windowManager.removeView(mLayout);
android.os.Process.killProcess(Process.myPid());
return true;
}
});
Protecting your app from tap jacking
Screens and Dialogs that handle critical decisions should always take measures against these type of attacks. A critical decision might be a financial approval, a permission request dialog, a PII exfiltration disclosure e.t.c.
The mitigation is relatively simple as the developer may choose not to receive touch events when a view is covered by another. Using the Android Developerâs Reference:
Sometimes it is essential that an application be able to verify that an action is being performed with the full knowledge and consent of the user, such as granting a permission request, making a purchase or clicking on an advertisement. Unfortunately, a malicious application could try to spoof the user into performing these actions, unaware, by concealing the intended purpose of the view. As a remedy, the framework offers a touch filtering mechanism that can be used to improve the security of views that provide access to sensitive functionality.
To enable touch filtering, call
setFilterTouchesWhenObscured(boolean)
or set the android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework will discard touches that are received whenever the view's window is obscured by another visible window. As a result, the view will not receive touches whenever a toast, dialog or other window appears above the view's window.
Appendix
[1] https://developer.android.com/reference/android/view/LayoutInflater
[2] https://www.tutorialspoint.com/android/android_user_interface_layouts.htm