Compte rendu de recherche sur le SDK malveillant SourMint
Kirill Efimov
24 août 2020
0 minutes de lecturePrésentation
Le SDK Mintegral est un SDK publicitaire populaire pour les applications mobiles, disponible sur iOS et Android. Des milliers d’applications mobiles l’utilisent, avec plus d’un milliard de téléchargements par mois. Les développeurs d’applications s’en servent pour monétiser leurs applications grâce à des publicités tierces.
L’équipe de recherche en sécurité de Snyk a publié deux révélations importantes concernant le SDK Mintegral. La première révélation, publiée en août 2020, a mis au jour une collecte excessive de données et le détournement de clics dans la version iOS du SDK. La deuxième révélation a découvert une porte dérobée dans la version iOS du SDK permettant l’exécution de code à distance, ainsi que de nouveaux éléments concernant la version Android du SDK.
Cet article présente les détails techniques de nos recherches et découvertes, au-delà de ce qui était décrit dans les billets de blog.
Ce compte rendu se divise en trois sections :
Collecte excessive de données, notamment l’interception et l’enregistrement de toutes les requêtes HTTP dans le SDK iOS — publiée initialement le 24 août 2020 — décrit les capacités de suivi des URL et des requêtes dans la version iOS du SDK Mintegral.
Une porte dérobée dans la version iOS du SDK permet l’exécution de code à distance : cette section décrit les capacités d’exécution de code à distance de MintegralAdSDK, publiées le 15 octobre 2020.
Suivi des URL de téléchargement sur Android : cette section décrit différentes découvertes concernant la version Android du SDK Mintegral.
Collecte excessive de données sur iOS [août 2020]
Présentation
Cette partie de la recherche a été menée sur la version binaire du SDK Mintegral pour iOS, car la version open source n’était pas encore à notre disposition en août 2020. Les recherches suivantes ont porté sur la version 6.3.5.0 du SDK (pour l’architecture x86), disponible en téléchargement sur GitHub.
Nous avons constaté que les versions 5.5.1 et ultérieures du SDK Mintegral pour iOS comportent des fonctionnalités malveillantes entraînant une fuite d’informations. En termes simples, le SDK espionne les clics de l’utilisateur sur des liens et l’activité réseau au sein des applications concernées. Cet espionnage a lieu même si le développeur ou la plateforme de médiation publicitaire n’a pas activé le SDK. Celui-ci tente de dissimuler son comportement malveillant en détectant les proxys, les simulateurs et les appareils jailbreakés.
Swizzling de méthodes
Le SDK Mintegral utilise une technique appelée swizzling de méthodes pour remplacer à l’exécution les implémentations des méthodes UIApplication openURL et SKStoreProductViewController loadProductWithParameters. Il enregistre également une classe NSURLProtocol personnalisée.
Ces hooks servent à espionner les utilisateurs de l’application en envoyant toutes les informations sur les requêtes HTTP, les URL ouvertes et les liens de l’App Store sur lesquels ils cliquent dans l’application.
Les en-têtes des requêtes HTTP et les URL eux-mêmes peuvent contenir des données sensibles. Associées à l’IDFA (Identifier for Advertisers), ces données permettent à Mintegral de commettre une fraude à l’attribution publicitaire.
Fraude à l’attribution publicitaire
Pour monétiser leurs applications, les développeurs installent souvent des plateformes publicitaires. Celles-ci perçoivent des revenus des annonceurs pour chaque installation effectuée après qu’un utilisateur a cliqué sur leur publicité. Il n’est pas rare que les développeurs utilisent plusieurs plateformes publicitaires dans leurs applications. Pour déterminer quelle plateforme doit recevoir l’attribution d’une installation, chaque clic est donc enregistré auprès d’un fournisseur d’attribution, une plateforme de mesure mobile (MMP).
La figure ci-dessous montre le fonctionnement des fonctionnalités malveillantes de Mintegral. Dans cet exemple, l’utilisateur a cliqué sur une publicité d’« Another Platform ». Mais comme Mintegral peut intercepter toutes les URL ouvertes par l’application, la plateforme peut envoyer des requêtes supplémentaires à un fournisseur d’attribution en prétendant que le clic a été effectué sur sa propre publicité. Voici le déroulement complet :
L’utilisateur clique sur un lien dans une publicité intégrée à l’application, diffusée par un réseau publicitaire autre que Mintegral, pour installer une nouvelle application depuis l’App Store.
Le SDK du réseau publicitaire envoie les informations sur le clic à sa plateforme backend.
Après avoir intercepté l’événement de clic au moyen de code injecté dans les gestionnaires d’événements iOS via le swizzling de méthodes, Mintegral enregistre les données du clic sur son serveur.
Le réseau publicitaire enregistre une notification de clic auprès du fournisseur d’attribution.
Mintegral enregistre également une notification de clic auprès du fournisseur d’attribution.
Lorsque le fournisseur d’attribution tente de faire correspondre l’événement d’installation aux notifications de clic enregistrées, il en trouve deux qui correspondent. Avec un modèle d’attribution au dernier contact, la notification de clic de Mintegral est créditée de l’attribution, tandis que celle de l’autre réseau publicitaire est rejetée.

Snyk a collaboré avec un important fournisseur d’attribution pour confirmer que Mintegral utilise les données de clic afin de générer de fausses notifications de clic. Au cours de son enquête, le fournisseur a pu démontrer que ces fausses notifications étaient générées et qu’elles attribuaient à tort les clics publicitaires à Mintegral.
Application de démonstration
Pour démontrer l’attaque, nous avons créé une application de démonstration. Elle montre le hook malveillant openURL en action. Nous utilisons un proxy de débogage pour intercepter tout le trafic réseau.
Pour initialiser l’application, nous utilisons l’extrait de code suivant tiré de la documentation Mintegral :
Une fois le SDK initialisé, nous ouvrons example.com depuis l’application en cliquant sur un bouton :
Après le lancement de l’application, nous voyons immédiatement quelques requêtes du SDK Mintegral dans notre proxy :
GET https://setting.rayjump.com/sdk/customidGET https://setting.rayjump.com/settingPOST https://analytics.rayjump.com

Paramètres
La réponse de https://setting.rayjump.com/setting est un objet JSON comportant de nombreuses options. Le tableau suivant décrit les champs les plus intéressants pour notre recherche.
Champ JSON | Description |
|---|---|
csw | Active ou désactive la fonctionnalité anti-débogage. |
cou | Active ou désactive le hook de la méthode |
cdai | URL à laquelle envoyer les informations divulguées (*). |
cspn | Active ou désactive le hook des méthodes StoreKit. |
cud | Activez ou désactivez le hook sur NSURLProtocol. |
cudl | Tableau des URL à suivre via NSURLProtocol (**). |
* Dans notre cas, il s’agissait de LdxThdi1WBK/WgfPhbxQYkeXHBPwHZKsYFh= , qui correspond à https://n.systemlog.me/log après décodage.
** Dans notre cas, il s’agissait de kBzuJd5/H+i/D+SMY7V/DFKwR0M0D+SMhBPthdSsHZPUYFT0+N==, qui correspond à ["itunes.apple.com","apps.apple.com"] après décodage.
Décodage du payload
Après avoir cliqué sur le bouton qui ouvre example.com, nous voyons deux autres requêtes. La première est une requête GET vers http://example.com, comme prévu. La deuxième est une requête POST vers https://n.systemlog.me/log.

Le corps de la requête semble encodé en base64. En réalité, il ne s’agit pas d’une chaîne encodée en base64. Le SDK Mintergral implémente sa propre logique d’encodage et de décodage, que l’on trouve dans +[MTGBase base64DecodeString:] et +[MTGBase base64CleverDecodeString:]. Notez que MTGBase n’est pas exposée dans les en-têtes publics du SDK et n’est pas destinée à être accessible aux développeurs.
Nous utilisons l’extrait de code suivant pour décoder le payload :

Le payload contient de nombreuses données, notamment l’IDFA, l’IDFV, la version du système d’exploitation, l’agent utilisateur, etc. Il contient également un champ nommé « clever », qui est lui aussi encodé. Nous pouvons le décoder à l’aide de base64DecodeString :
Comme vous pouvez le constater, il contient l’URL, la trace de pile et des informations supplémentaires, comme le contrôleur et le nom de la méthode.
Examen approfondi
Comme indiqué précédemment, le SDK Mintegral est à code source fermé. Nous allons examiner la version 6.3.5.0 pour l’architecture x86.
Le binaire est un exécutable Mach-O qui contient plusieurs autres binaires. Le code qui nous intéresse se trouve dans _CXX_CXX_OperationPKTask.o.
En examinant la classe, nous trouvons +[_CXX_CXX_OperationPKTask load], qui s’exécute automatiquement lorsque la classe est ajoutée à l’exécution. Cela signifie que si le SDK est installé via CocoaPods, la logique malveillante est initialisée, que les développeurs utilisent réellement le SDK ou non.
La méthode load effectue une série d’appels qui nous conduisent à ___cxxwebk_init_vw. Cette méthode vérifie si l’indicateur de protection anti-débogage est activé et initialise les hooks si l’indicateur est désactivé ou si le débogage est désactivé.

L’initialisation des hooks dépend de la requête de paramètres mentionnée ci-dessus. Le tableau suivant montre les correspondances entre les champs JSON de la réponse et la classe MTGSetting :
Champ JSON | Propriété MTGSetting | Description |
|---|---|---|
csw | cSrtW | Active ou désactive la fonctionnalité anti-débogage. |
cou | cOpenURL | Active ou désactive le hook de la méthode |
cspn | cPackageName | Active ou désactive le hook des méthodes StoreKit. |
Logique anti-débogage

La fonction __cxx_cxx_op_isInSuperViewFrame renvoie true dans les cas suivants :
La plateforme de l’appareil est un « simulateur ».
Un débogueur est connecté (implémenté dans
____mvpmvvm_isDebuggerAttached_block_invoke).L’un des fichiers suivants est présent sur l’appareil (indiquant un jailbreak) :
/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt
/usr/bin/ssh
Un proxy est activé (à l’aide de
CFNetworkCopySystemProxySettings).
Swizzling de la méthode openURL
La logique de la capture d’écran suivante est implémentée dans la méthode ___cxxwebkmcouitninapo, appelée depuis ___cxxwebk_init_vw si l’indicateur correspondant est activé.

La capture d’écran ci-dessus montre l’implémentation du swizzling de méthodes. Elle effectue les appels suivants :
NSSelectorFromStringpour obtenir un sélecteur pour la méthode « openURL: ».NSClassFromStringpour obtenir un descripteur de classe pourUIApplication.class_getInstanceMethodpour obtenir le descripteur de méthode.method_getImplementationpour obtenir l’implémentation réelle de la méthode.Ils définissent ensuite un bloc de code qui appelle
_____cxxwebkmcouitninapo_block_invoke_2, puis appelle la méthodeopenURLd’origine.method_setImplementationpour remplacer la méthode openURL d’origine par le bloc de code de l’étape précédente.
La même opération est effectuée pour la méthode openURL:options:completionHandler:, à ceci près que la version du système est vérifiée au préalable (le gestionnaire a été introduit pour la première fois dans iOS 10).
Nous avons maintenant vu comment le hook était appliqué. Nous allons ensuite examiner l’implémentation du hook lui-même (_____cxxwebkmcouitninapo_block_invoke_2).
Implémentation du hook openURL
En pratique, l’implémentation se trouve dans la méthode ___cxxwebkmcoulsz. On y trouve un autre appel de vérification anti-débogage, puis le code vérifie l’indicateur __mc_notifyInHouse et ne fait rien si sa valeur est 1.
Cela permet d’ignorer toutes les URL marketing sur lesquelles un utilisateur clique dans une publicité diffusée par Mintegral. La logique correspondante se trouve dans +[MTGBase mtgOpenURL:options:completionHandler:], comme le montre la capture d’écran ci-dessous :

Le code suivant montre également que les données de la trace de pile sont sérialisées et divulguées dans le payload envoyé à https://n.systemlog.me/log.
Nous pouvons définir un point d’arrêt sur l’appel +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:]. Les arguments de l’appel sont visibles dans la capture d’écran suivante :

L’URL ouverte (http://example.com?foo=bar&x=y).
La classe dans laquelle le clic a eu lieu (
ViewController).La méthode dans laquelle le clic a eu lieu (
openURLWithOptions:).Informations sur la trace de pile.
Une autre fonction intéressante est _nsh_id_by_cc, qui semble chargée d’identifier les SDK concurrents. La logique correspondante est présentée dans la capture d’écran suivante :

En revenant à +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:], une fois la charge utile encodée avec +[MTGBase base64EncodeString:], un nouveau bloc de code est créé et _dispatch_async est utilisé pour l’exécuter.
Cela entraîne une série d’appels accompagnés de transformations supplémentaires de la charge utile et aboutit à -[_MC_ApiManager AFRequestWithUrl:paras:success:failure:], qui envoie une requête POST à collectDomainUrl dans MTGSetting, dont la valeur par défaut est https://n.systemlog.me/log.
Vidéo montrant comment une URL privée peut être divulguée.

Interception de SKStoreProductViewController
SKStoreProductViewController est un contrôleur de vue qui affiche une page permettant à l’utilisateur d’acheter des contenus sur l’App Store.
La méthode loadProductWithParameters:completionBlock: charge un nouvel écran de produit à afficher.
Plutôt que de détailler techniquement la mise en œuvre de l’interception, nous avons ajouté l’extrait de code suivant à l’application de démonstration :
Nous constatons ainsi une requête POST vers https://n.systemlog.me/log, avec la charge utile suivante dans le champ « clever » :
Comme nous pouvons le constater, l’ID du produit figure dans la requête. CQFD.
Interception de NSURLProtocol
La classe NSURLProtocol permet aux développeurs de redéfinir le fonctionnement du système de chargement d’URL d’Apple. Le SDK Mintegral enregistre une implémentation malveillante de NSURLProtocol, configurable à distance pour intercepter toutes les requêtes sortantes d’une application et suivre les URL ainsi que les en-têtes HTTP, y compris l’en-tête Authorization.
Pour les développeurs d’applications, cela signifie que Mintegral pourrait potentiellement collecter des jetons d’API, des cookies et des en-têtes d’authentification de base.
Pour comprendre comment le SDK active cette partie du code malveillant, revenons à ___cxxwebk_init_vw.

La capture d’écran ci-dessus montre que l’indicateur cud doit être activé et que le tableau cudl ne doit pas être vide pour déclencher l’interception.
La capture d’écran suivante montre une partie de la fonction ___cxxwebkterisiuuxx, appelée depuis la méthode ci-dessus.

Le code de la fonction ___cxxwebkterisiuuxx effectue les actions suivantes :
Crée une classe héritant de
NSURLProtocol(objc_registerClassPair,objc_allocateClassPair).Ajoute une implémentation de
canInitWithRequest:, qui agit en pratique comme un intercepteur (class_addMethod).Appelle
+[NSURLProtocol registerClass:]pour enregistrer la classe auprès du système de chargement d’URL.
Dans le cadre de nos recherches, nous avons ajouté l’extrait de code suivant afin de vérifier quelles données sont collectées par le code malveillant :
Nous constatons ainsi une requête POST vers https://n.systemlog.me/log, avec la charge utile suivante dans le champ « clever » :
Dans la requête, nous pouvons voir l’URL et l’en-tête d’autorisation. Bien que le corps de la requête ne soit pas inclus, les en-têtes contiennent souvent des données sensibles, qui peuvent même inclure des informations personnelles identifiables. Par exemple, si une API utilise des jetons JWT, ceux-ci peuvent contenir une adresse e-mail ou un nom d’utilisateur.
Conclusion
Au cours de nos recherches, nous avons observé de nombreuses techniques intéressantes utilisées par les développeurs de Mintegral pour dissimuler le comportement malveillant de leur SDK. Comme nous pouvons le constater, les interceptions ne sont activées que pour certaines applications dans certaines régions, ce qui a permis au code malveillant de rester présent pendant plus d’un an sans attirer l’attention.
Pour ce qui est de la chronologie, la première version (5.5.1) du SDK malveillant a été publiée le 17 juillet 2019. Nous avons constaté que toutes les versions suivantes contenaient les mêmes fonctionnalités malveillantes.
De nombreuses applications populaires ont été touchées par les activités malveillantes de ce SDK. Nous espérons que cette recherche, en faisant la lumière sur la situation, incitera à renforcer la vigilance et les contrôles de confidentialité des réseaux publicitaires.
Exécution de code à distance (RCE) sur iOS [octobre 2020]
En bref
Nous avons découvert que la classe MTGBaseBridgeWebView, utilisée partout dans le SDK pour communiquer avec JavaScript, sert de porte dérobée et permet d’appeler des fonctions arbitraires depuis le code natif de l’application.

L’illustration ci-dessus présente un schéma simplifié de l’exécution de code à distance.
Analyse des différences
Après notre première divulgation publique, Mintegral a annoncé la publication d’une version open source du SDK.
Nous avons comparé la nouvelle version open source à la version binaire précédente, distribuée sous forme de cocoapod. Même si nous ne disposions pas du code source de l’ancienne version, nous pouvions comparer les noms de classes. Pour cela, nous avons extrait les fichiers .o des binaires et comparé leurs symboles aux fichiers .h de la version open source.
Comme prévu, le composant malveillant _CXX_CXX_OperationPKTask découvert précédemment avait bien été supprimé, mais l’analyse des différences a révélé autre chose. Les classes suivantes ont retenu notre attention :
MTGCommandDispatcher
MTGComponentCommands
MTGRemoteCommand
MTGRemoteCommandParameterModel
MTGRemoteCommandParser
MTGInvocationBoxing
Nous avons décidé d’examiner les binaires de plus près afin de comprendre à quoi servaient ces fichiers.
Versions concernées
Toutes les versions de MintegralAdSDK jusqu’à la version 6.5.0.0 incluse. La version 6.6.0.0, publiée le 10 septembre 2020, ne comporte pas la porte dérobée décrite dans cet article.
Mise en œuvre du pont
Nous avons commencé par chercher où la classe MTGRemoteCommandParser était utilisée et avons trouvé un seul emplacement : -(void)handleNativeObject:parameters: dans la classe MTGBaseBridgeWebView.
L’implémentation montre que -(void)handleNativeObject:parameters: utilise MTGRemoteCommandParser pour analyser l’argument parameters et appelle la méthode -(void)dispatchCommand:feedback: de la classe MTGCommandDispatcher.
À première vue, -(void)handleNativeObject:parameters: ne semble pas être utilisée, mais ce n’est pas le cas. Voyons comment elle peut être appelée depuis du code JavaScript.
MTGBaseBridgeWebView implémente la méthode -(void)webView:decidePolicyForNavigationAction:decisionHandler: du protocole WKNavigationDelegate. Cette méthode est appelée chaque fois qu’une navigation a lieu dans la vue Web. Cela signifie que nous pouvons la déclencher depuis JavaScript en appelant simplement location.href=something. Dans la version open source du SDK, nous avons trouvé une expression régulière qui analyse les URL des requêtes de navigation : mv://(.+?):(.+?)/(.+?)\\?([\\s\\S]*).

Dans la capture d’écran ci-dessus, -(void)callFunctionWithName:fucId:param: appelle simplement self avec le sélecteur fucName.
Pour appeler -(void)handleNativeObject:parameters: de MTGBaseBridgeWebView, il faut donc utiliser la ligne de code JavaScript suivante : location.href = 'mv://1:fucId/handleNativeObject?<parameters>'.
Notez que tout ce que nous avons décrit ci-dessus reste valable dans la dernière version du SDK disponible au moment de la rédaction, ainsi que dans la version open source. La seule exception est que -(void)handleNativeObject:parameters: a été supprimée des versions les plus récentes.
Invocation de méthodes à distance
Nous ne décrirons pas l’intégralité de l’implémentation de MTGInvocationBoxing ni celle des autres classes. Nous montrerons plutôt comment créer du code JavaScript malveillant pour déclencher la méthode à distance.
La preuve de concept suivante cible une application de « prise de notes » simple, qui possède une classe NoteRepository dotée de deux méthodes : +(void)save: et +(NSString*)load.
Nous injectons le code JavaScript malveillant en remplaçant le serveur Mintegral par notre propre implémentation. Vous trouverez ici le code source complet de cette application et du serveur.
Voici le code JavaScript malveillant pour cette application :
Valeur | Décodé |
|---|---|
hbxtJ7QU+TPXJ75ZH+SXhFQTYbzP | static_NoteRepository |
Y7KtHv== | load |
Ce code appelle la méthode +(NSString*)load de la classe NoteRepository et envoie le résultat à notre point de terminaison demo-evil-server.com/log.
Il utilise les mêmes techniques d’obfuscation que celles décrites dans la section précédente. Toutefois, la preuve de concept inclut déjà du code JavaScript pour effectuer l’encodage et le décodage (voir banner.html).
Obtenir une exécution de code à distance (RCE) complète
Dans l’exemple ci-dessus, nous avons vu comment le SDK peut servir à appeler n’importe quelle méthode statique d’une classe arbitraire. Dans cette section, nous allons montrer comment exploiter cette possibilité pour exécuter du code natif quelconque.
À titre de démonstration, nous allons montrer comment créer un UIAlertController avec le message « PWNED! ».
Prenons le code Objective-C suivant comme référence :
Nous devons déterminer comment créer et conserver une instance de UIAlertController entre les appels, comment obtenir une instance partagée de l’application et comment appeler presentViewController:animated:completion: avec cette instance.
Étape 1 : enregistrer une référence à la classe UIAlertController
MTGRemoteCommandParser prend en charge deux types de références d’objet :
static: récupère une référence à un objet de classe par son nom.singleton: effectue plusieurs étapes :Récupère une classe par son nom (
MTGSettingdans notre exemple).Exécute la méthode
sharedInstancesur la classe.[MTGSetting sharedInstance]en Objective-C.
Utilise
valueForKey:pour accéder aux propriétés séparées par des points. Dans notre cas, il s’agira de[[MTGSetting sharedInstance] valueForKey:@"jsonTitles"].
Notez que jsonTitles est simplement une instance de NSMutableDictionary. Dans l’exploit, elle sert de stockage temporaire pour nos références. MTGRemoteCommandParser prend en charge les types de paramètres suivants :
0: nombre.1: référence.2: chaîne de caractères.4:nil.
Le type référence (1) nous permet de passer une référence à un objet comme argument d’une méthode. Il est important de noter que uniqueIdentifier est analysé exactement de la même manière qu’un uniqueIdentifier de premier niveau ; le type singleton est donc également pris en charge.
Étape 2 : allouer une nouvelle instance de la classe UIAlertController
Dans ce cas, tout se joue dans singleton_MTGSetting.jsonTitles.a.alloc.init. Comme nous le savons déjà, singleton_MTGSetting.jsonTitles.a nous fournit une référence à la classe UIAlertController. Mais pourquoi [[UIAlertController valueForKey:@"alloc"] valueForKey:@"init"] fonctionne-t-il ? La documentation de valueForKey: nous apprend que :
Le modèle de recherche utilisé par valueForKey: pour trouver la valeur à renvoyer est décrit dans les modèles de recherche d’accesseurs du guide de programmation sur le codage clé-valeur.
Nous avons découvert que valueForKey: peut appeler n’importe quelle méthode par son nom si elle ne prend aucun argument.
Nous pouvons donc créer une nouvelle instance de la classe UIAlertController, référencée par la propriété b du dictionnaire jsonTitles.
Étape 3 : définir le message « PWNED! »
Cette étape est assez évidente : nous appelons setMessage: sur l’instance de UIAlertController pour définir le message PWNED!.
Étape 4 : enregistrer une référence à la classe UIApplication
Cette étape est similaire à la première. Nous devons enregistrer la référence à la classe UIApplication dans jsonTitles.x.
Étape 5 : afficher l’alerte
Cette étape peut sembler compliquée, mais elle fait simplement appel à différentes techniques des étapes précédentes. En Objective-C, le code se présente ainsi :
Nous avons maintenant montré comment afficher une alerte par exécution de code à distance. Vous trouverez la charge utile complète ici. Pour exécuter les étapes une par une, nous avons créé un tableau d’actions et exécuté chaque action dans le rappel window.WindVane.onSuccess (l’une après l’autre, une fois l’action précédente terminée).
Vidéo montrant comment le contenu du presse-papiers peut être divulgué en diffusant l’exploit par le biais d’une publicité malveillante.

Code source de l’exploit JavaScript
Nous avons déjà vu comment le SDK Mintegral permet l’exécution de code à distance native via du code JavaScript. Toutefois, ce code JavaScript est entièrement détenu et contrôlé par Mintegral. Mais, fait intéressant, il est possible d’obtenir le même résultat avec des publicités interactives créées par les annonceurs eux-mêmes. Ces publicités sont des pages Web basées sur JavaScript.
En théorie, un annonceur peut cibler précisément un groupe d’utilisateurs ou un ensemble spécifique d’appareils en diffusant une publicité malveillante contenant l’exploit JavaScript.
Conclusion
Nous ne pouvons que spéculer sur les raisons qui ont poussé Mintegral à inclure dans son SDK la possibilité d’invoquer des méthodes natives à distance. Toutefois, d’après le nom des classes, comme MTGCommandDispatcher et MTGRemoteCommand, nous pensons que cette fonctionnalité était intentionnelle. De plus, Mintegral a supprimé le code immédiatement après notre publication, alors même que nous n’en avions pas connaissance à l’époque.
Suivi des téléchargements sur Android [octobre 2020]
Présentation générale
Dans les deux sections précédentes de cet article de recherche, nous avons expliqué comment l’équipe de sécurité de Snyk a découvert un comportement malveillant dans le SDK Mintegral, exploitable sur les appareils iOS et pouvant entraîner une fraude publicitaire, une fuite de données et l’exécution de code à distance (RCE). Nous avons voulu approfondir nos recherches sur la distribution Android du SDK, sujet de cette section.
Voici, en résumé, nos principales conclusions :
Suivi des URI de téléchargement depuis Google, concernant les téléchargements depuis les navigateurs et les applications, y compris les téléchargements de fichiers classiques, les pièces jointes d’e-mails et les liens Google Docs.
Suivi de tous les téléchargements d’APK, qu’ils soient organiques ou non.
Ces données sont renvoyées aux serveurs de Mintegral.
Comportement observé
Après avoir téléchargé un lien Google Docs, nous avons remarqué que l’application envoyait les requêtes suivantes à https://n.systemlog.me :

Il s’agit du même point de terminaison que celui utilisé dans le SDK iOS pour transmettre des données au serveur Mintegral. La charge utile est encodée, mais nous pouvons utiliser la logique de décodage présente dans le binaire du SDK pour obtenir le résultat suivant :
Nous avons deux paramètres encodés supplémentaires, clever et dvi. Après les avoir également décodés, nous avons fait une découverte intéressante :
Comme nous pouvons le voir, l’URL de la feuille Google téléchargée depuis l’application Google Drive est envoyée au serveur dans le champ ul, le nom du fichier téléchargé dans le champ kw, tandis que dvi contient des données sur l’appareil.
Utilisations potentielles
Dans le scénario iOS, des clics frauduleux en double étaient envoyés depuis l’appareil du client aux serveurs de Mintegral, puis au fournisseur d’attribution (MMP). Dans ce cas, les APK téléchargés ou installés sont signalés aux serveurs et pourraient être utilisés pour générer des clics côté serveur. Le schéma suivant illustre le flux de données :

Module Alphab
Le comportement décrit ci-dessus se trouve dans le module alphab, que Mintegral présentait comme un « package d’optimisation » :

À la suite de notre publication, le module a été supprimé du site de Mintegral et ne semble plus faire partie du SDK distribué. Nous avons décompilé le SDK et localisé le code responsable de ce comportement.
Classe AlphaCommonConst
Cette classe contient de nombreuses définitions de constantes codées en dur. Certaines chaînes sont masquées au moyen d’un schéma d’encodage personnalisé basé sur Base64, situé dans la classe AlphabBase64Util, comme nous l’avions observé dans la distribution iOS.
Après décodage, nous obtenons les chaînes suivantes :
Elles sont utilisées lors des étapes d’initialisation que nous allons examiner ensuite.
Récepteur Alphab
Dans la méthode init() de la classe AlphabReceiver, le BroadcastReceiver est initialisé à l’aide de certaines des chaînes précédemment masquées :
En remplaçant celles-ci par les chaînes décodées, le code devient :
Nous pouvons voir que l’API de réflexion Java permet de créer un nouveau récepteur de diffusion qui écoute deux types d’intents :
android.intent.action.PACKAGE_ADDED: un intent système qui se déclenche lorsqu’un package est installé sur l’appareil.alphab_net_debug_action: un intent personnalisé qui semble détecter le débogage réseau.
À la réception de l’intent, la classe AlphabReceiver construit une méthode ParseAndLoad() :
Ce champ est ensuite utilisé dans une condition :
La décompilation des deux autres méthodes de cette clause if révèle qu’elles vérifient si la connexion réseau actuelle passe par un proxy Wi-Fi ou un client VPN. Ces vérifications visent à empêcher le débogage de l’application et l’analyse de son trafic. Cet intent permet aux développeurs du SDK de contourner cette fonctionnalité anti-débogage.
Observateur Alphab
De la même manière, le bloc d’initialisation de ce ContentObserver est lui aussi dissimulé au moyen de la réflexion et de chaînes obfusquées :
Après nettoyage, nous obtenons le résultat suivant :
Cela signifie que l’observateur de contenu est enregistré pour écouter l’URI content://downloads et se déclenche chaque fois qu’un fichier est téléchargé sur l’appareil.
Il interroge le gestionnaire de téléchargements Android pour récupérer les téléchargements publics :
et le décodage de la chaîne donne le résultat suivant :
Si l’URL de téléchargement répond à l’une des conditions suivantes, un rapport est envoyé à https://n.systemlog.met/stlog :
Se termine par
apk: pour les téléchargements manuels.Fait référence à un package appartenant à
com.android.vendingou l’URL contient google.com : cela permet de détecter toute application Google, voire les URL de navigateur répondant à cette condition.
Voici l’extrait de code qui envoie la requête au serveur https://n.systemlog.met/stlog.
ce qui correspond à :
Nous retrouvons ici les paramètres observés dans la requête capturée dans notre exemple :
p: nom du package téléchargé, c’est-à-dire l’applicationv: version de l’applicationul: URL du fichier téléchargékw: nom du fichier téléchargéfl: taille du fichier
Application de démonstration

Pour illustrer ce comportement, nous avons créé une application de démonstration qui nous permettait de :
1. Activer l’indicateur de débogage réseau par réflexion afin de contourner la logique anti-débogage
2. Télécharger un fichier depuis une URL contenant google.com
3. Télécharger un fichier depuis une URL se terminant par apk
Nous avons capturé les requêtes sortantes à l’aide d’un proxy HTTP. Après avoir cliqué sur l’un des boutons de téléchargement, nous avons constaté l’envoi d’une requête au point de terminaison du serveur :

Voici une vidéo qui illustre le comportement de suivi :

Chronologie
Date | |
|---|---|
5 août | L’équipe de recherche de Snyk découvre que le SDK iOS de Mintegral collecte excessivement des données et détourne des clics |
17 août | Snyk communique ses conclusions à Apple de manière responsable |
24 août | Snyk publie ses conclusions sur Sour Mint pour iOS |
25 août | Mintegral publie une déclaration niant les accusations concernant son SDK |
3 septembre | IronSource annonce le retrait de Mintegral de sa plateforme de médiation |
3 septembre | Mintegral publie la version 6.5.0.0 du SDK iOS, qui supprime le composant malveillant et dissimulé _CXX_CXX_OperationPKTask |
4 septembre | La plateforme de médiation MoPub (Twitter) annonce la révocation de l’accréditation de Mintegral sur sa plateforme |
4 septembre | Mintegral annonce son intention de rendre son SDK open source |
4 septembre | L’équipe de recherche de Snyk découvre une fonctionnalité cachée de suivi des téléchargements dans la version Android du SDK |
9 septembre | Snyk communique de manière responsable à Google ses conclusions concernant le SDK Android |
10 septembre | Mintegral publie la version 6.6.0.0 du SDK iOS, qui supprime le composant de porte dérobée MTGRemoteCommandParser |
22 septembre | Snyk obtient le code source de la version 6.6.0.0 du SDK iOS et effectue une analyse différentielle |
23 septembre | Snyk découvre que Mintegral a supprimé le module de suivi des téléchargements Google de son SDK Android |
30 septembre | Grâce à une analyse différentielle, Snyk découvre une porte dérobée dans la version iOS du SDK permettant l’exécution de code à distance (RCE) |
2 octobre | Snyk communique de manière responsable ses nouvelles conclusions concernant iOS à Apple |
3 octobre | Apple informe les éditeurs concernés et leur demande de supprimer le code permettant l’exécution de code à distance |
15 octobre | Snyk publie ses dernières conclusions concernant iOS et Android |
