πŸ™ƒVulnerability #14: Insecure Content Provider

In Android, Content Providers are a very important component that serves the purpose of a relational database to store the data of applications. Insecure implementations of an application’s content provider could be a high-risk attack vector which could allow malicious applications to freely leak/retrieve data from it. While viewing the manifest for insecureshop, the content provider declaration sticks out as a red flag due to the exported attribute:

<provider android:name="com.insecureshop.contentProvider.InsecureShopProvider" 
          android:readPermission="com.insecureshop.permission.READ" 
          android:exported="true" 
          android:authorities="com.insecureshop.provider"/>

This means that any application on the device can interact with the provider with the proper permissions (com.insecureshop.permission.READ). Next, we’ll be looking at the source code for com.insecureshop.contentProvider.InsecureShopProviderarrow-up-right:

class InsecureShopProvider : ContentProvider() {

    companion object {
        var uriMatcher: UriMatcher? = null
        const val URI_CODE: Int = 100
    }

    override fun onCreate(): Boolean {
        uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
        uriMatcher?.addURI("com.insecureshop.provider", "insecure", URI_CODE)
        return true
    }

within the onCreate method, we can see that the uriMatcher adds a URI which should be used to connect with the provider. In this instance, we will be using the following URI: content://com.insecureshop.provider/insecure

 override fun query(
        uri: Uri,
        projection: Array<out String>?,
        selection: String?,
        selectionArgs: Array<out String>?,
        sortOrder: String?
    ): Cursor? {
        if (uriMatcher?.match(uri) == URI_CODE) {
            val cursor = MatrixCursor(arrayOf("username", "password"))
            cursor.addRow(arrayOf<String>(Prefs.username!!, Prefs.password!!))
            return cursor
        }
        return null
    }

    override fun getType(uri: Uri): String? {
        return null
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        return null
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
        return 0
    }

    override fun update(
        uri: Uri,
        values: ContentValues?,
        selection: String?,
        selectionArgs: Array<out String>?
    ): Int {
        return 0
    }

we can see that the query method is the only one with some code/logic on it. It creates a cursor with the username and password columns then populates them with the credentials from shared preferences.

AndroidManifest.xml

In order to exploit this, we’ll need to use the required permissions for the provider. After which, we can use a content resolver to query data from the content provider URI that we provide. If the query is succesful, we write the results into logcat.

MainActivity.kt

Last updated