packageorg.owasp.mastestappimportandroid.app.Activityimportandroid.content.Contextimportandroid.graphics.Colorimportandroid.view.Gravityimportandroid.view.MotionEventimportandroid.view.ViewGroupimportandroid.widget.Buttonimportandroid.widget.FrameLayoutimportandroid.widget.LinearLayoutimportandroid.widget.Toast// SUMMARY: This sample demonstrates three approaches to overlay attack protection on sensitive UI elements:// a vulnerable button with no protection, a button using setFilterTouchesWhenObscured, and a button// with a custom onFilterTouchEventForSecurity override.classMastgTest(privatevalcontext:Context){valshouldRunInMainThread=truefunmastgTest():String{vallayout=LinearLayout(context).apply{orientation=LinearLayout.VERTICALgravity=Gravity.CENTERsetBackgroundColor(Color.TRANSPARENT)}valhalfWidth=(context.resources.displayMetrics.widthPixels*0.5).toInt()valbuttonParams=LinearLayout.LayoutParams(halfWidth,LinearLayout.LayoutParams.WRAP_CONTENT).apply{gravity=Gravity.CENTER_HORIZONTALtopMargin=24}// FAIL: [MASTG-TEST-0x01] The vulnerable button performs a sensitive action (payment confirmation)// without any overlay protection, making it susceptible to tapjacking attacks.valvulnerableButton=Button(context).apply{text="Vulnerable: Confirm Payment"setOnClickListener{Toast.makeText(context,"Vulnerable button clicked",Toast.LENGTH_SHORT).show()}}layout.addView(vulnerableButton,buttonParams)// PASS: [MASTG-TEST-0x01] The protected button uses filterTouchesWhenObscured=true to discard// touch events when the view is obscured by another window.valprotectedButton=Button(context).apply{text="Protected: Confirm Payment"filterTouchesWhenObscured=truesetOnClickListener{Toast.makeText(context,"Protected button clicked",Toast.LENGTH_SHORT).show()}}layout.addView(protectedButton,buttonParams)// PASS: [MASTG-TEST-0x01] The custom protected button overrides onFilterTouchEventForSecurity// and checks FLAG_WINDOW_IS_OBSCURED to implement a custom security policy.valcustomProtectedButton=object:Button(context){overridefunonFilterTouchEventForSecurity(event:MotionEvent):Boolean{if((event.flagsandMotionEvent.FLAG_WINDOW_IS_OBSCURED)!=0){Toast.makeText(context,"Blocked obscured touch",Toast.LENGTH_SHORT).show()returnfalse}returnsuper.onFilterTouchEventForSecurity(event)}}.apply{text="Custom Protection: Grant Permission"setOnClickListener{Toast.makeText(context,"Custom protected button clicked",Toast.LENGTH_SHORT).show()}}layout.addView(customProtectedButton,buttonParams)(contextas?Activity)?.let{activity->valroot=activity.findViewById<ViewGroup>(android.R.id.content)if(layout.parent==null){root.addView(layout,FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT))}}return"Created buttons with various overlay protections"}}
packageorg.owasp.mastestapp;importandroid.app.Activity;importandroid.content.Context;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.Button;importandroid.widget.FrameLayout;importandroid.widget.LinearLayout;importandroid.widget.Toast;importkotlin.Metadata;importkotlin.jvm.internal.Intrinsics;/* compiled from: MastgTest.kt */@Metadata(d1={"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u000b\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\u000f\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0004\b\u0004\u0010\u0005J\u0006\u0010\n\u001a\u00020\u000bR\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000R\u0014\u0010\u0006\u001a\u00020\u0007X\u0086D¢\u0006\b\n\u0000\u001a\u0004\b\b\u0010\t¨\u0006\f"},d2={"Lorg/owasp/mastestapp/MastgTest;","","context","Landroid/content/Context;","<init>","(Landroid/content/Context;)V","shouldRunInMainThread","","getShouldRunInMainThread","()Z","mastgTest","","app_debug"},k=1,mv={2,0,0},xi=48)/* loaded from: classes3.dex */publicfinalclassMastgTest{publicstaticfinalint$stable=8;privatefinalContextcontext;privatefinalbooleanshouldRunInMainThread;publicMastgTest(Contextcontext){Intrinsics.checkNotNullParameter(context,"context");this.context=context;this.shouldRunInMainThread=true;}publicfinalbooleangetShouldRunInMainThread(){returnthis.shouldRunInMainThread;}/* JADX WARN: Type inference failed for: r6v8, types: [org.owasp.mastestapp.MastgTest$mastgTest$customProtectedButton$1] */publicfinalStringmastgTest(){LinearLayoutlayout=newLinearLayout(this.context);layout.setOrientation(1);layout.setGravity(17);layout.setBackgroundColor(0);inthalfWidth=(int)(this.context.getResources().getDisplayMetrics().widthPixels*0.5d);LinearLayout.LayoutParams$this$mastgTest_u24lambda_u241=newLinearLayout.LayoutParams(halfWidth,-2);$this$mastgTest_u24lambda_u241.gravity=1;$this$mastgTest_u24lambda_u241.topMargin=24;finalButton$this$mastgTest_u24lambda_u243=newButton(this.context);$this$mastgTest_u24lambda_u243.setText("Vulnerable: Confirm Payment");$this$mastgTest_u24lambda_u243.setOnClickListener(newView.OnClickListener(){// from class: org.owasp.mastestapp.MastgTest$$ExternalSyntheticLambda0@Override// android.view.View.OnClickListenerpublicfinalvoidonClick(Viewview){MastgTest.mastgTest$lambda$3$lambda$2($this$mastgTest_u24lambda_u243,view);}});layout.addView($this$mastgTest_u24lambda_u243,$this$mastgTest_u24lambda_u241);finalButton$this$mastgTest_u24lambda_u245=newButton(this.context);$this$mastgTest_u24lambda_u245.setText("Protected: Confirm Payment");$this$mastgTest_u24lambda_u245.setFilterTouchesWhenObscured(true);$this$mastgTest_u24lambda_u245.setOnClickListener(newView.OnClickListener(){// from class: org.owasp.mastestapp.MastgTest$$ExternalSyntheticLambda1@Override// android.view.View.OnClickListenerpublicfinalvoidonClick(Viewview){MastgTest.mastgTest$lambda$5$lambda$4($this$mastgTest_u24lambda_u245,view);}});layout.addView($this$mastgTest_u24lambda_u245,$this$mastgTest_u24lambda_u241);finalContextcontext=this.context;final??r6=newButton(context){// from class: org.owasp.mastestapp.MastgTest$mastgTest$customProtectedButton$1@Override// android.view.ViewpublicbooleanonFilterTouchEventForSecurity(MotionEventevent){Intrinsics.checkNotNullParameter(event,"event");if((event.getFlags()&1)!=0){Toast.makeText(getContext(),"Blocked obscured touch",0).show();returnfalse;}returnsuper.onFilterTouchEventForSecurity(event);}};r6.setText("Custom Protection: Grant Permission");r6.setOnClickListener(newView.OnClickListener(){// from class: org.owasp.mastestapp.MastgTest$$ExternalSyntheticLambda2@Override// android.view.View.OnClickListenerpublicfinalvoidonClick(Viewview){MastgTest.mastgTest$lambda$7$lambda$6(r6,view);}});layout.addView((View)r6,$this$mastgTest_u24lambda_u241);Contextcontext2=this.context;Activityactivity=context2instanceofActivity?(Activity)context2:null;if(activity!=null){ViewGrouproot=(ViewGroup)activity.findViewById(android.R.id.content);if(layout.getParent()==null){root.addView(layout,newFrameLayout.LayoutParams(-1,-1));return"Created buttons with various overlay protections";}return"Created buttons with various overlay protections";}return"Created buttons with various overlay protections";}/* JADX INFO: Access modifiers changed from: private */publicstaticfinalvoidmastgTest$lambda$3$lambda$2(Buttonthis_apply,Viewit){Intrinsics.checkNotNullParameter(this_apply,"$this_apply");Toast.makeText(this_apply.getContext(),"Vulnerable button clicked",0).show();}/* JADX INFO: Access modifiers changed from: private */publicstaticfinalvoidmastgTest$lambda$5$lambda$4(Buttonthis_apply,Viewit){Intrinsics.checkNotNullParameter(this_apply,"$this_apply");Toast.makeText(this_apply.getContext(),"Protected button clicked",0).show();}/* JADX INFO: Access modifiers changed from: private */publicstaticfinalvoidmastgTest$lambda$7$lambda$6(MastgTest$mastgTest$customProtectedButton$1this_apply,Viewit){Intrinsics.checkNotNullParameter(this_apply,"$this_apply");Toast.makeText(this_apply.getContext(),"Custom protected button clicked",0).show();}}
To demonstrate this vulnerability in a live environment, you can use App Requesting SYSTEM_ALERT_WINDOW Permission, which shows an attacker app that requests the SYSTEM_ALERT_WINDOW permission to draw overlays over other apps. Running the attacker app while the victim app is in the foreground lets you verify whether the unprotected button accepts touch events through an overlay.
rules:-id:mastg-android-overlay-protection-setfiltertoucheswhenobscuredseverity:INFOlanguages:-javametadata:summary:DetectsusageofsetFilterTouchesWhenObscuredmethodforoverlayattackprotectionmessage:"[MASVS-PLATFORM-3] setFilterTouchesWhenObscured is used to protect against overlay attacks"pattern:$VIEW.setFilterTouchesWhenObscured(...)-id:mastg-android-overlay-protection-onfiltertoucheventforsecurityseverity:INFOlanguages:-javametadata:summary:DetectsoverridingofonFilterTouchEventForSecurityforcustomoverlayprotectionmessage:"[MASVS-PLATFORM-3] onFilterTouchEventForSecurity is overridden for custom overlay protection"pattern:|publicbooleanonFilterTouchEventForSecurity(...){...}-id:mastg-android-overlay-protection-flag-window-is-obscuredseverity:INFOlanguages:-javametadata:summary:DetectschecksforFLAG_WINDOW_IS_OBSCUREDflagtodetectoverlayattacksmessage:"[MASVS-PLATFORM-3] FLAG_WINDOW_IS_OBSCURED is checked to detect overlay attacks"pattern-either:-pattern:$EVENT.getFlags()&MotionEvent.FLAG_WINDOW_IS_OBSCURED-pattern:($EVENT.getFlags()&MotionEvent.FLAG_WINDOW_IS_OBSCURED)!=0-id:mastg-android-overlay-protection-flag-window-is-partially-obscuredseverity:INFOlanguages:-javametadata:summary:DetectschecksforFLAG_WINDOW_IS_PARTIALLY_OBSCUREDflagtodetectoverlayattacksmessage:"[MASVS-PLATFORM-3] FLAG_WINDOW_IS_PARTIALLY_OBSCURED is checked to detect overlay attacks"pattern-either:-pattern:$EVENT.getFlags()&MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED-pattern:($EVENT.getFlags()&MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED)!=0-id:mastg-android-overlay-protection-xml-attributeseverity:INFOlanguages:-xmlmetadata:summary:DetectsfilterTouchesWhenObscuredattributeinlayoutXMLfilesmessage:"[MASVS-PLATFORM-3] android:filterTouchesWhenObscured attribute is used to protect against overlay attacks"pattern:android:filterTouchesWhenObscured="true"-id:mastg-android-overlay-protection-sethideoverlaywindowsseverity:INFOlanguages:-javametadata:summary:DetectsusageofsetHideOverlayWindowstopreventoverlaywindowsfromappearingovertheactivitymessage:"[MASVS-PLATFORM-3] setHideOverlayWindows is used to prevent overlay windows from appearing over this window"pattern:$WINDOW.setHideOverlayWindows(...)-id:mastg-android-overlay-protection-hide-overlay-windows-permissionseverity:INFOlanguages:-xmlmetadata:summary:DetectsHIDE_OVERLAY_WINDOWSpermissioninthemanifest,requiredforsetHideOverlayWindowsmessage:"[MASVS-PLATFORM-3] HIDE_OVERLAY_WINDOWS permission is declared, required to use setHideOverlayWindows"pattern:android:name="android.permission.HIDE_OVERLAY_WINDOWS"
run.sh
1234
#!/bin/bash# Run semgrep to detect overlay protection mechanismsNO_COLOR=truesemgrep-c../../../../rules/mastg-android-overlay-protection.yml./MastgTest_reversed.java--text>output.txt
Line 54: setFilterTouchesWhenObscured(true) is set on the protected button.
Lines 64-72: onFilterTouchEventForSecurity is overridden to implement custom overlay protection, including a check for the FLAG_WINDOW_IS_OBSCURED flag (literal value 1) at line 67.
FAIL: The first button ("Vulnerable: Confirm Payment") doesn't appear in the output, meaning it implements no overlay protection. This button performs a sensitive action (payment confirmation) and is susceptible to tapjacking attacks.
PASS: The second button (line 54) correctly implements overlay protection using setFilterTouchesWhenObscured(true), which filters out touch events when the view is obscured by another window.
PASS: The third button (lines 64-72) implements custom overlay protection by overriding onFilterTouchEventForSecurity and checking the FLAG_WINDOW_IS_OBSCURED flag. This provides fine-grained control over how the app responds to overlay attempts.
In a real-world assessment, the unprotected button should be flagged as a finding. Sensitive UI elements such as payment confirmations, permission grants, or authentication controls should implement overlay protection using one of the demonstrated mechanisms.