Skip to content

MASTG-DEMO-0104: App Requesting SYSTEM_ALERT_WINDOW Permission

Download MASTG-DEMO-0104 APK Open MASTG-DEMO-0104 Folder Build MASTG-DEMO-0104 APK

Sample

The manifest below is from an attacker app that requests the SYSTEM_ALERT_WINDOW permission, which allows it to draw overlays over other apps.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MASTestApp"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:windowSoftInputMode="adjustResize"
            android:theme="@style/Theme.MASTestApp">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1"
    android:versionName="1.0"
    android:compileSdkVersion="35"
    android:compileSdkVersionCodename="15"
    package="org.owasp.mastestapp.attacker.overlay"
    platformBuildVersionCode="35"
    platformBuildVersionName="15">
    <uses-sdk
        android:minSdkVersion="29"
        android:targetSdkVersion="35"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <permission
        android:name="org.owasp.mastestapp.attacker.overlay.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
        android:protectionLevel="signature"/>
    <uses-permission android:name="org.owasp.mastestapp.attacker.overlay.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"/>
    <application
        android:theme="@style/Theme.MASTestApp"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:debuggable="true"
        android:allowBackup="true"
        android:supportsRtl="true"
        android:extractNativeLibs="false"
        android:fullBackupContent="@xml/backup_rules"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:appComponentFactory="androidx.core.app.CoreComponentFactory"
        android:dataExtractionRules="@xml/data_extraction_rules">
        <activity
            android:theme="@style/Theme.MASTestApp"
            android:name="org.owasp.mastestapp.attacker.overlay.MainActivity"
            android:exported="true"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity
            android:name="androidx.compose.ui.tooling.PreviewActivity"
            android:exported="true"/>
        <activity
            android:theme="@android:style/Theme.Material.Light.NoActionBar"
            android:name="androidx.activity.ComponentActivity"
            android:exported="true"/>
        <provider
            android:name="androidx.startup.InitializationProvider"
            android:exported="false"
            android:authorities="org.owasp.mastestapp.attacker.overlay.androidx-startup">
            <meta-data
                android:name="androidx.emoji2.text.EmojiCompatInitializer"
                android:value="androidx.startup"/>
            <meta-data
                android:name="androidx.lifecycle.ProcessLifecycleInitializer"
                android:value="androidx.startup"/>
            <meta-data
                android:name="androidx.profileinstaller.ProfileInstallerInitializer"
                android:value="androidx.startup"/>
        </provider>
        <receiver
            android:name="androidx.profileinstaller.ProfileInstallReceiver"
            android:permission="android.permission.DUMP"
            android:enabled="true"
            android:exported="true"
            android:directBootAware="false">
            <intent-filter>
                <action android:name="androidx.profileinstaller.action.INSTALL_PROFILE"/>
            </intent-filter>
            <intent-filter>
                <action android:name="androidx.profileinstaller.action.SKIP_FILE"/>
            </intent-filter>
            <intent-filter>
                <action android:name="androidx.profileinstaller.action.SAVE_PROFILE"/>
            </intent-filter>
            <intent-filter>
                <action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package org.owasp.mastestapp

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.PixelFormat
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.Toast

// SUMMARY: This sample demonstrates an attacker app that uses the SYSTEM_ALERT_WINDOW permission
// to draw a visible overlay over other apps. It is used to demonstrate how overlay attacks work
// against apps that lack overlay protections (see MASTG-DEMO-0x01).

class MastgTest(private val context: Context) {

    val shouldRunInMainThread = true

    companion object {
        private var overlayView: View? = null
    }

    fun mastgTest(): String {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {
            val intent = Intent(
                Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:${context.packageName}")
            ).apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            context.startActivity(intent)
            Toast.makeText(
                context,
                "Grant overlay permission, then press Start again",
                Toast.LENGTH_LONG
            ).show()
            return "Overlay permission required"
        }

        return if (overlayView == null) {
            showOverlay()
            "Overlay shown"
        } else {
            hideOverlay()
            "Overlay hidden"
        }
    }

    private fun showOverlay() {
        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager

        val overlay = View(context).apply {
            setBackgroundColor(Color.argb(140, 255, 0, 0))
        }

        val params = WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            800,
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            } else {
                @Suppress("DEPRECATION")
                WindowManager.LayoutParams.TYPE_PHONE
            },
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
            PixelFormat.TRANSLUCENT
        ).apply {
            gravity = Gravity.CENTER
        }

        windowManager.addView(overlay, params)
        overlayView = overlay

        Toast.makeText(context, "Overlay shown", Toast.LENGTH_SHORT).show()
    }

    private fun hideOverlay() {
        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        overlayView?.let {
            windowManager.removeView(it)
            overlayView = null
        }
        Toast.makeText(context, "Overlay hidden", Toast.LENGTH_SHORT).show()
    }
}

You can use this attacker app to demonstrate the vulnerability shown in Missing Overlay Protection on a Sensitive View: install and run it while the victim app is in the foreground, then activate the overlay. This lets you verify whether the unprotected button in the victim app accepts touch events through the overlay.

Note that the SYSTEM_ALERT_WINDOW permission itself isn't a vulnerability in the app that declares it. It's a legitimate Android feature used by apps such as screen overlay tools, chat heads, or accessibility services. However, its presence means the app can display overlays over other apps, which can be used to conduct overlay attacks against victim apps that don't implement proper protections.

Steps

Let's run our semgrep rule against the reversed manifest to check for the SYSTEM_ALERT_WINDOW permission.

../../../../rules/mastg-android-system-alert-window.yml
1
2
3
4
5
6
7
8
9
rules:
  - id: mastg-android-system-alert-window-permission
    severity: INFO
    languages:
      - xml
    metadata:
      summary: Detects SYSTEM_ALERT_WINDOW permission in the manifest, enabling the app to draw overlays over other apps
    message: "[MASVS-PLATFORM-3] SYSTEM_ALERT_WINDOW permission is declared, enabling the app to draw overlays over other apps"
    pattern: android:name="android.permission.SYSTEM_ALERT_WINDOW"
run.sh
1
2
3
4
#!/bin/bash

# Run semgrep to detect the SYSTEM_ALERT_WINDOW permission in the reversed manifest
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-system-alert-window.yml ./AndroidManifest_reversed.xml --text > output.txt

Observation

The rule detected the SYSTEM_ALERT_WINDOW permission in the manifest:

output.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
┌────────────────┐
 1 Code Finding 
└────────────────┘

    AndroidManifest_reversed.xml
      rules.mastg-android-system-alert-window-permission
          [MASVS-PLATFORM-3] SYSTEM_ALERT_WINDOW permission is declared, enabling the app to draw overlays
          over other apps                                                                                 

           14 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Evaluation

The finding confirms that this app declares the SYSTEM_ALERT_WINDOW permission. This isn't a vulnerability in this app itself; it shows that the app has the capability to draw overlays over other apps. The actual vulnerability lies in victim apps (like the one in Missing Overlay Protection on a Sensitive View) that don't implement overlay protections on sensitive UI elements.

When assessing an app for overlay attack vulnerabilities, the threat model should include apps that can request SYSTEM_ALERT_WINDOW to create overlays.