Skip to content

MASTG-DEMO-0057: Network Security Configuration Allows User-Added Certificates

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

Sample

This sample Kotlin code fetches the badssl server https://mitm-software.badssl.com/ using HttpsURLConnection, which is not normally allowed because the certificate is not trusted by the system. However, due to the Network Security Configuration that permits user-added CA certificates, the connection is allowed to proceed.

 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
package org.owasp.mastestapp

import android.content.Context
import java.net.URL
import javax.net.ssl.HttpsURLConnection

class MastgTest(private val context: Context) {

    fun mastgTest(): String {
        val content = StringBuilder("Response:\n\n")
        val thread = Thread {
            content.append(fetchUrl("https://mitm-software.badssl.com/"))
        }
        thread.start()
        thread.join()
        return content.toString()
    }

    private fun fetchUrl(urlString: String): String {
        return try {
            val url = URL(urlString)
            val connection = url.openConnection() as HttpsURLConnection

            connection.setRequestProperty("User-Agent", "OWASP MAS APP 9000")
            connection.connect()

            val response = connection.inputStream.bufferedReader().use { it.readText() }
            "\n[$urlString] Response OK\n$response\n"
        } catch (e: Exception) {
            "\n[$urlString] Error: ${e.message}\n"
        }
    }

}
 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
<?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" />
    <application
        android:allowBackup="true"
        android:networkSecurityConfig="@xml/network_security_config"
        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: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
<?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"
    platformBuildVersionCode="35"
    platformBuildVersionName="15">
    <uses-sdk
        android:minSdkVersion="29"
        android:targetSdkVersion="35"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <permission
        android:name="org.owasp.mastestapp.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
        android:protectionLevel="signature"/>
    <uses-permission android:name="org.owasp.mastestapp.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:testOnly="true"
        android:allowBackup="true"
        android:supportsRtl="true"
        android:extractNativeLibs="false"
        android:fullBackupContent="@xml/backup_rules"
        android:networkSecurityConfig="@xml/network_security_config"
        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.MainActivity"
            android:exported="true">
            <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:name="androidx.activity.ComponentActivity"
            android:exported="true"/>
        <provider
            android:name="androidx.startup.InitializationProvider"
            android:exported="false"
            android:authorities="org.owasp.mastestapp.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
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>

Running the app

You don't need to run the app on a device or emulator to test this demo because it focuses on the Network Security Configuration. However, if you want to run the app and verify that the connection is allowed, some additional preparation is required:

  1. Obtain the root CA certificate for the server. For this example, obtain it here: https://github.com/chromium/badssl.com/blob/master/certs/src/crt/ca-mitm-software.crt
  2. Copy the certificate file onto the device or emulator. For example, use the command adb push ca-mitm-software.crt /sdcard/Download/.
  3. On the device open Settings > Security > Encryption & credentials > Install from storage and select your certificate file. Confirm it installs under "User credentials".

Steps

First of all we obtain the AndroidManifest.xml file (AndroidManifest_reversed.xml), which contains the android:networkSecurityConfig attribute pointing to the app's Network Security Configuration file (network_security_config.xml).

Let's run our semgrep rule against the sample code.

../../../../rules/mastg-android-network-insecure-trust-anchors.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
rules:
  - id: mastg-android-network-insecure-trust-anchors
    severity: WARNING
    languages:
      - xml
    metadata:
      summary: Detects entries in network security config that allow user-added CAs.
    message: The network security config allows certificates imported on the user's behalf thereby allowing connections to potentially insecure CAs
    match:
      any:
        - <certificates src="user"
run.sh
1
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-network-insecure-trust-anchors.yml ./network_security_config.xml --text > output.txt

Observation

The rule has identified an element in the Network Security Configuration that allows user-added CA certificates.

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

    network_security_config.xml
    ❯❱ rules.mastg-android-network-insecure-trust-anchors
          The network security config allows certificates imported on the user's behalf thereby allowing
          connections to potentially insecure CAs                                                       

            6 <certificates src="user" />

Evaluation

The test fails due to the <certificates src="user" /> element in the Network Security Configuration which allows user-added CA certificates.