The Content Provider component is one of the key Android app components. It manages data access and is mainly used to implement data sharing between apps. Content Provider data sources can be SQLite databases or files. By separating the data storage layer from the application layer, Content Provider provides a common interface to various data sources.
To create a Content Provider, you need to inherit from the Content Provider abstract class and rewrite onCreate(), query(), insert(), update(), delete() and getType() abstract methods, which are used to add, delete, modify and query underlying data sources. You also need to register the Content Provider in the AndroidManifest file and specify access permissions, the "exported" attribute, and the value of the "authority" attribute during registration.
By using the ContentResolver object, other apps can query for and operate the Content Provider. This also has the same method names as those in the Content Provider. In this way, other apps can directly access underlying data of the Content Provider's data sources without having to know the structure or implementation of that data.
To locate specific data, you can use Content Uri. The following is a Content Uri example:
content://com.jaq.providertest.friendsprovider/friends
Generally, Content Uri consists of the following three parts:
For more details, please refer to Articles 1.
If we set the "exported" attribute of a Content Provider as "true" in the AndroidManifest file, it will create an attack point to this app. If the implementation of the Content Provider is flawed, we face such risks as arbitrary data access, SQL injection and directory traversal risks.
Private permission definition is prone to the following risks: when one defines a private permission but the said definition lacks a permission level, or the defined level is insufficient, malicious apps can access data provided by the Content Provider by declaring this permission, resulting in data leakage.
Taking the known WooYun-2014-57590 bug as an example:
We define a private permission in an online storage client. However, we do not define the private permission in the AndroidManifest file and other apps can access Providers offered by the client simply by declaring the permission, resulting in user data leakage.
When Providers are registered in the AndroidManifest file in the client, the system declares the read and write permissions self-defined by the client:
However, no definitions of the private permissions "com.huawei.dbank.v7.provider.DBank.READ_DATABASE" and "com.huawei.dbank.v7.provider.DBank.WRITE_DATABASE" can be found in the AndroidManifest file:
By decompiling the client, one can view URIs of Providers. By exploiting these URIs, other apps can forge them for malicious purposes:
Develop POC
With the downloaded file list of the online storage client as an example,
the system declares a private permission in the AndroidManifest file of the POC. It defines the protection level of the permission as "normal", which is the lowest level:
Relevant code is as below:
Obtain downloaded list data from a database:
The actual database is as follows:
With the code mentioned above, any malicious apps can access private information stored in the client such as user upload and download records as well as file lists.
Taking the known WooYun-2013-039697 bug as an example:
It defines a private permission with the protection level "dangerous" or "normal", that however, is insufficient given the importance of Providers for some apps.
The Provider in this case is:
It defines the private permission "com.renren.mobile.android.permission.PERMISSION_ADD_ACCOUNT" as follows:
By decompiling the client, you can view the implementation of AccountProvider:
Develop the POC:
Define and declare the permission in AndroidManifest:
Relevant code is as follows:
User account information is viewable, including the UID, mobile number and encrypted password:
If the data source of a Content Provider is SQLite databases, the Provider can result in local SQL injection risks if it fails to implement and expose the database properly.
We defines the query() method of the Content Provider as follows:
The parameters are as follows:
● uri: Content Uri, the database queried;
● projection: the name of the column queried;
● selection and selectionArgs: query conditions specified;
● sortOrder: sorting method of the query result.
The comparison between query() and SQL query is as follows:
If an SQL statement consisting of concatenated strings in query() queries the underlying SQLite databases, SQL injection can take place easily.
Taking the known Wooyun-2016-0175294 bug as an example:
The value of the "exported" attribute of com.sohu.sohuvideo.provider.PlayHistoryProvider in the client is "true":
By decompiling the client and tracking the implementation of PlayHistoryProvider, the original SQL query statement is found to consist of concatenated strings:
Verify the bug using the drozer tool:
Given that an exposed Content Provider implements the openFile() interface, other apps that invoke the Content Provider can access file data by invoking the openFile() interface of the Content Provider. If no access permission control is available to the Content Provider and no effective judgment mechanism is in place for URIs of target files, intruders can exploit the file directory traversal vulnerability to access any readable files or even write any data to writable directories on mobile phones.
Example 1
Taking the known Wooyun-2013-044407 bug as an example:
A Content Provider component for accessing local files is defined in the app, namely com.ganji.android.jobs.html5.LocalFileContentProvider. Given that minSdkServison is set as "8" and targetSdkVersion is set as "13", the Content Provider is using the default export configuration, namely android:exported="true":
This Provider implements the openFile() interface:
Through this interface, data stored under the app_webview directory is accessible. As no effective judgment mechanism is available for target files in the background, we can perform directory traversal by running "../" to access any private data.
Example 2
In a social app client, minSDKVersion is set as 8, private permissions defined and android:protectionLevel set as "signature".
However, it exposes a Content Provider, namely com.facebook.lite.photo.MediaContentProvider. This Provider does not have any set access permissions while another Provider has set access permissions:
MediaContentProvider implements the openFile() interface but does not restrict and filter inbound URIs:
The design objective of this interface is to access photo information, but we can also exploit it to read other files:
POC:
The content read from other files:
In addition, the implementation of the Openfile() interface allows intruders to create a file that did not exist previously and to write any files to app directories.
When designing an app, developers must identify which Provider data is private user data or critical data and consider whether it should be accessible to external apps or not. If not accessible, explicitly set the "exported" attribute as "false" in the AndroidManifest file to avoid most attacks.
Manual troubleshooting is complicated, so we recommend developers to use the security scanning service provided by Alibaba All-in-One Security to scan apps automatically before their launch to detect and eliminate potential security risks proactively.
Notes:
It is impossible to set the Content Provider component as do not export in Android 2.2 (with API level 8) systems. We recommend to declare the supported SDK version of SDK 8 or later (most SDK versions today are later than version 8).
The default value of the "android:exported" attribute is "true" for any apps of API level 17 and lower. We recommend to explicitly set the "android:exported" attribute of registered Content Providers as "false" if you do not need to export Content Providers of those apps.
If you have to provide data for external apps, elaborate the design and permission control to determine which external apps can access the data. For example, use the same signature for internal apps during permission definition and check partners' signatures for partner apps for the same purpose. In addition, we recommend that you should refrain from providing any user private information, whenever possible.
For Providers that must be exposed (for example, the risk described in section 2), use the following solution:
The syntax for defining private permissions in AndroidManifest is as follows:
Possible values and their meanings of android:protectionLevel are:
● normal: This is the default value and it indicates a low-risk level. During app installation, apps will automatically get this status.
● dangerous: It indicates a high-risk level and applies to texting, making phone calls and reading/writing the contact list. Use this protectionLevel value to identify the permissions that may concern users. During the installation of an app, Android prompts users for required permissions and behaviors depending on the actual Android version or the mobile device on which the app is installed.
● signature: This indicates the signature permission. When another app invokes the declared permissions, signatures of both apps must match. If the signatures match, it will grant declared permissions to third-party apps automatically, without prompting users.
● signatureOrSystem: In addition to apps with the same signature, apps in Android systems also have the authorization to access Providers.
Most open Providers are accessible to other internal apps. Normally, the signature certificates for packaging and signing apps are consistent and android:protectionLevel of providers should be set as "signature".
Note: Do not develop SQL statements with concatenated strings.
If the data source of Content Provider is SQLite databases, developing and executing the original SQL statement consisting of concatenated strings can result in SQL injection risks.
Using selection sub-statement as an example:
By executing this operation, users can concatenate malicious SQL statements to the original SQL statement.
For example, users can enter "nothing; DROP TABLE ** ; " for mUserInput and this generates the selection sub-statement:
var = nothing; DROP TABLE **;
As the selection sub-statement will process as a SQL statement, this can cause Providers to erase all the tables in basic SQLite databases (unless the Providers are set as able to capture SQL injection attempts).
Use parameterization query:
To avoid this problem, we can use a single "?" mark as the selection sub-statement that can replace parameters and use it as a separate selection parameter array.
When we execute this operation, queries directly control user entries but do not interpret them as part of a SQL statement.
Given that we do not process user entries as SQL statements, it is impossible to inject malicious SQL statements.
Always use this selection sub-statement but not concatenated strings to include user entries:
String mSelectionClause = "var = ?";
Set the selection parameter array by using the following code:
String[] selectionArgs = {""};
Place values into the selection parameter array using the following code:
selectionArgs[0] = mUserInput;
Alternatively, you can invoke the parameterization query method query() from the SQLiteDatabase class:
If there is need to set Providers as accessible by partners' apps, and those apps' signature certificates are different from the internal certificate, we can pre-write signature hash values of those apps to internal apps that offer Providers. The access will, however, only be permitted when app signatures at both ends match.
In this article we have shared an overview of the Content Provider, how it works, the risks involved while using it and the possible scenarios that can occur related to these risks. We have also discussed about the Alibaba Cloud Security Solution that can help in the prevention of such risks.
[1] Content Provider Basics https://developer.android.com/guide/topics/providers/content-provider-basics.html
[2] SQL Injection for Android Apps http://zone.wooyun.org/content/15097
[3] Android - Content Providers http://www.tutorialspoint.com/android/android_content_providers.htm
[4] http://www.compiletimeerror.com/2013/12/content-provider-in-android.html
[5] https://developer.android.com/guide/topics/manifest/permission-element.html?hl=zh-cn
[6] https://developer.android.com/guide/topics/manifest/permission-element.html
[7] http://www.wooyun.org/bugs/wooyun-2013-039697
[8] http://www.wooyun.org/bugs/wooyun-2014-057590
[9] Android Content Provider Security http://drops.wooyun.org/tips/4314
[10] http://www.wooyun.org/bugs/wooyun-2016-0175294
[11] Android Content Provider Security http://drops.wooyun.org/tips/4314
[12] http://www.wooyun.org/bugs/wooyun-2013-044407
[13] http://www.wooyun.org/bugs/wooyun-2013-044411
[14] Brief Analysis of the Directory Traversal Vulnerability for Content Providers https://jaq.alibaba.com/blog.htm?id=61
[15] https://github.com/programa-stic/security-advisories/tree/master/FacebookLite
Leveraging IoT Data in the Cloud: Why your business is more at risk
Design and Application Learning of the Distributed Call Tracing System
2,599 posts | 764 followers
FollowAliware - July 27, 2020
Alibaba Clouder - July 10, 2018
Joyer - January 11, 2021
Alibaba Clouder - February 3, 2019
Alibaba Cloud Project Hub - June 28, 2021
Alibaba Clouder - December 22, 2020
2,599 posts | 764 followers
FollowExplore Web Hosting solutions that can power your personal website or empower your online business.
Learn MoreExplore how our Web Hosting solutions help small and medium sized companies power their websites and online businesses.
Learn MoreBuild superapps and corresponding ecosystems on a full-stack platform
Learn MoreWeb App Service allows you to deploy, scale, adjust, and monitor applications in an easy, efficient, secure, and flexible manner.
Learn MoreMore Posts by Alibaba Clouder