Investigación sobre el SDK malicioso SourMint
Kirill Efimov
16 de octubre de 2020
0 minutos de lecturaRecopilación excesiva de datos en iOS [agosto de 2020]
Ejecución remota de código (RCE) en iOS [octubre de 2020]
Seguimiento de descargas en Android [octubre de 2020]
Descripción general
Mintegral SDK es un SDK de publicidad para aplicaciones móviles muy popular, disponible para iOS y Android. Lo usan miles de aplicaciones móviles, con más de mil millones de descargas al mes. Los desarrolladores de aplicaciones usan el SDK para monetizar sus apps con anuncios de terceros.
El equipo de investigación de seguridad de Snyk realizó dos divulgaciones importantes sobre Mintegral SDK. La primera divulgación se publicó en agosto de 2020 y detectó la recopilación excesiva de datos y el secuestro de clics en la versión del SDK para iOS. La segunda divulgación detectó una puerta trasera en la versión del SDK para iOS que permite la ejecución remota de código, además de nuevos hallazgos sobre la versión para Android.
El objetivo de este artículo es compartir los detalles técnicos de nuestra investigación y nuestros hallazgos, más allá de lo que se abordó en las publicaciones del blog.
Este análisis se divide en tres secciones:
Recopilación excesiva de datos, incluida la interceptación y el registro de todas las solicitudes HTTP en el SDK para iOS —publicado originalmente el 24 de agosto de 2020—, describe las capacidades de seguimiento de URL y solicitudes en la versión de Mintegral SDK para iOS.
Una puerta trasera en la versión del SDK para iOS permite la ejecución remota de código: describe las capacidades de ejecución remota de código de MintegralAdSDK, publicadas el 15 de octubre de 2020.
Seguimiento de URL de descargas en Android: describe varios hallazgos en la versión de Mintegral SDK para Android.
Recopilación excesiva de datos en iOS [agosto de 2020]
Descripción general
Esta parte de la investigación se realizó sobre la versión binaria de Mintegral iOS SDK, ya que en agosto de 2020 todavía no teníamos acceso a la versión de código abierto. La investigación se realizó con la versión 6.3.5.0 del SDK (para arquitectura x86), disponible para descargar en GitHub.
Identificamos que las versiones 5.5.1 y posteriores de Mintegral iOS SDK contienen funciones maliciosas que provocan la filtración de información. En pocas palabras, el SDK espía los clics de los usuarios en enlaces y la actividad de red dentro de las aplicaciones afectadas. El espionaje ocurre incluso si el desarrollador o la plataforma de mediación de anuncios no habilitaron el SDK, y este intenta ocultar el comportamiento malicioso detectando proxies, simuladores y dispositivos con jailbreak.
Intercambio de métodos
Mintegral SDK usa una técnica llamada intercambio de métodos para reemplazar, durante la ejecución, las implementaciones de los métodos UIApplication openURL y SKStoreProductViewController loadProductWithParameters. También registra una clase NSURLProtocol personalizada.
Estos hooks se usan para espiar a los usuarios de las aplicaciones y enviar toda la información sobre las solicitudes HTTP, las URL abiertas y los enlaces de App Store en los que hacen clic dentro de la aplicación.
Los encabezados y las URL de las solicitudes HTTP podrían contener datos confidenciales, pero, junto con el IDFA (identificador para anunciantes), permiten que Mintegral cometa fraude de atribución de anuncios.
Fraude de atribución de anuncios
Para monetizar sus aplicaciones, los desarrolladores suelen instalar plataformas publicitarias. Estas plataformas reciben ingresos de los anunciantes por cada instalación que ocurre después de que un usuario hace clic en un anuncio. No es raro que los desarrolladores usen varias plataformas publicitarias en sus aplicaciones. Por eso, para determinar a qué plataforma publicitaria se debe atribuir una instalación, cada clic se registra con un proveedor de atribución, es decir, una plataforma de medición móvil (MMP).
La siguiente figura muestra cómo funciona la actividad maliciosa de Mintegral. En este ejemplo, el usuario hizo clic en un anuncio de “Otra plataforma”. Pero, como Mintegral puede interceptar todas las URL que abre la aplicación, podría enviar solicitudes adicionales a un proveedor de atribución, fingiendo que el clic se produjo en uno de sus anuncios. El proceso completo funciona así:
El usuario hace clic en un enlace de un anuncio dentro de una aplicación, publicado por una red publicitaria que no es Mintegral, para instalar una nueva aplicación desde App Store.
El SDK de la red publicitaria envía la información del clic a su plataforma de backend.
Tras interceptar el evento de clic mediante código inyectado en los controladores de eventos de iOS a través del intercambio de métodos, Mintegral registra los datos del clic en su servidor.
La red publicitaria registra una notificación de clic con el proveedor de atribución.
Mintegral también registra una notificación de clic con el proveedor de atribución.
Cuando el proveedor de atribución intenta asociar el evento de instalación con las notificaciones de clic registradas, encuentra dos coincidencias. Al usar un modelo de atribución de último contacto, se atribuye la instalación a la notificación de clic de Mintegral y se rechaza la de la otra red publicitaria.

Snyk trabajó con un importante proveedor de atribución para confirmar que Mintegral usa los datos de clics para generar notificaciones de clic falsas. Durante su investigación, el proveedor pudo demostrar que se generaban notificaciones falsas y que esto provocaba que se atribuyeran incorrectamente a Mintegral los clics en anuncios.
Aplicación de demostración
Para demostrar el ataque, configuramos una aplicación de demostración. Esta mostrará el hook malicioso de openURL en acción. Usamos un proxy de depuración para interceptar todo el tráfico de red.
Para inicializar la aplicación, usamos el siguiente fragmento de código de la documentación de Mintegral:
Con el SDK inicializado, abrimos example.com desde la aplicación al hacer clic en un botón:
Después de iniciar la aplicación, vemos de inmediato un par de solicitudes de Mintegral SDK en nuestro proxy:

Configuración
La respuesta de _https://setting.rayjump.com/setting es un objeto JSON con muchas opciones distintas. En la siguiente tabla se describen los campos más relevantes para nuestra investigación.
Campo JSON | Descripción |
|---|---|
csw | Habilita o deshabilita la funcionalidad antidepuración. |
cou | Habilita o deshabilita el hook del método |
cdai | URL a la que se envía la información filtrada (*). |
cspn | Habilita o deshabilita el hook en los métodos de StoreKit. |
cud | Habilita o deshabilita el hook en NSURLProtocol. |
cudl | Arreglo de URL para seguimiento mediante NSURLProtocol (**). |
* En nuestro caso era LdxThdi1WBK/WgfPhbxQYkeXHBPwHZKsYFh=, que, tras decodificarlo, corresponde a https://n.systemlog.me/log.
** En nuestro caso era kBzuJd5/H+i/D+SMY7V/DFKwR0M0D+SMhBPthdSsHZPUYFT0+N==, que, tras decodificarlo, corresponde a ["itunes.apple.com","apps.apple.com"].
Decodificación de la carga útil
Después de hacer clic en el botón que abre example.com, vemos dos solicitudes más. La primera es una solicitud GET a http://example.com, como esperaríamos. La segunda es una solicitud POST a https://n.systemlog.me/log.

El cuerpo de la solicitud parece estar codificado en base64. Pero, en realidad, no es una cadena codificada en base64. Mintegral SDK implementa su propia lógica de codificación y decodificación, que se encuentra en +[MTGBase base64DecodeString:] y +[MTGBase base64CleverDecodeString:]. Ten en cuenta que MTGBase no está expuesta en los encabezados públicos del SDK y no está diseñada para que los desarrolladores puedan acceder a ella.
Usamos el siguiente fragmento de código para decodificar la carga útil:

La carga útil contiene muchos datos, como IDFA, IDFV, la versión del sistema operativo, el agente de usuario y más. Sin embargo, también incluye un campo llamado “clever” que, una vez más, está codificado. Podemos decodificarlo con base64DecodeString:
Como puedes ver, contiene la URL, el seguimiento de la pila y algunos datos adicionales, como el controlador y el nombre del método.
Un análisis más profundo
Como mencionamos antes, Mintegral SDK es de código cerrado. Analizaremos la versión 6.3.5.0 para arquitectura x86.
El binario es un ejecutable Mach-O que contiene varios binarios adicionales. El código que nos interesa está en _CXX_CXX_OperationPKTask.o.
Al revisar la clase, vemos +[_CXX_CXX_OperationPKTask load], que se ejecuta automáticamente cuando la clase se agrega durante la ejecución. Esto significa que, si el SDK se instala mediante CocoaPods, la lógica maliciosa se inicializa independientemente de si los desarrolladores usan el SDK.
El método load realiza una serie de llamadas que nos llevan a ___cxxwebk_init_vw. Este método comprueba si la marca de protección antidepuración está habilitada e inicializa los hooks si la marca está desactivada o si la depuración está deshabilitada.

La inicialización de los hooks depende de la solicitud de configuración mencionada anteriormente. En la siguiente tabla se muestran las relaciones entre los campos de respuesta JSON y la clase MTGSetting:
Campo JSON | Propiedad de MTGSetting | Descripción |
|---|---|---|
csw | cSrtW | Habilita o deshabilita la funcionalidad antidepuración. |
cou | cOpenURL | Habilita o deshabilita el hook del método |
cspn | cPackageName | Habilita o deshabilita el hook en los métodos de StoreKit. |
Lógica antidepuración

La función __cxx_cxx_op_isInSuperViewFrame devuelve true en los siguientes casos:
La plataforma del dispositivo es un “simulador”.
Hay un depurador conectado (implementado en
____mvpmvvm_isDebuggerAttached_block_invoke).Uno de los siguientes archivos está presente en el dispositivo (indicio de jailbreak):
/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt
/usr/bin/ssh
El proxy está habilitado (mediante
CFNetworkCopySystemProxySettings).
Intercambio del método openURL
La lógica de la siguiente captura de pantalla está implementada en el método ___cxxwebkmcouitninapo, al que se llama desde ___cxxwebk_init_vw si la marca correspondiente está habilitada.

"blog-sour-mint-openurl-method-swirl" - La captura de pantalla anterior muestra la implementación del intercambio de métodos. Realiza las siguientes llamadas:
NSSelectorFromStringpara obtener un selector del método “openURL:”.NSClassFromStringpara obtener un descriptor de clase deUIApplication.class_getInstanceMethodpara obtener el descriptor del método.method_getImplementationpara obtener la implementación real del método.Luego definen un bloque de código que llama a
_____cxxwebkmcouitninapo_block_invoke_2y después llama alopenURLoriginal.method_setImplementationpara reemplazar el openURL original por el bloque de código del paso anterior.
Casi lo mismo ocurre con el método openURL:options:completionHandler:, excepto que antes comprueban la versión del sistema (el controlador se introdujo por primera vez en iOS 10).
En este punto, ya vimos cómo se aplica el hook. A continuación, veremos su implementación (_____cxxwebkmcouitninapo_block_invoke_2).
Implementación del hook de openURL
En la práctica, la implementación se encuentra en el método ___cxxwebkmcoulsz. Allí vemos otra llamada de comprobación antidepuración; luego comprueba la marca __mc_notifyInHouse y no hace nada si su valor es 1.
Esto se hace para ignorar todos los enlaces de marketing en los que hace clic un usuario en un anuncio publicado por Mintegral. En la captura de pantalla siguiente vemos la lógica correspondiente en +[MTGBase mtgOpenURL:options:completionHandler:]:

El siguiente fragmento de código muestra que también serializan los datos de seguimiento de la pila y los filtran en la carga útil que envían a https://n.systemlog.me/log.
Podemos establecer un punto de interrupción en la llamada +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:]. En la siguiente captura de pantalla puedes ver los argumentos de la llamada:

La URL que se abrió (http://example.com?foo=bar&x=y).
La clase en la que ocurrió el clic (
ViewController).El método desde el que se produjo el clic (
openURLWithOptions:).Información de seguimiento de la pila.
Otra función interesante es _nsh_id_by_cc, que parece encargarse de identificar los SDK de la competencia. La lógica relevante se muestra en la siguiente captura de pantalla:

Al volver a +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:], después de codificar la carga mediante +[MTGBase base64EncodeString:], se crea un nuevo bloque de código y se usa _dispatch_async para invocarlo.
Esto da lugar a una serie de llamadas con transformaciones adicionales de la carga y termina en -[_MC_ApiManager AFRequestWithUrl:paras:success:failure:], que envía una solicitud POST a collectDomainUrl de MTGSetting, cuyo valor predeterminado es https://n.systemlog.me/log.
Un video que muestra cómo se puede filtrar una URL privada.

Hook de SKStoreProductViewController
SKStoreProductViewController es un controlador de vista que ofrece una página donde el usuario puede comprar contenido multimedia en App Store.
El método loadProductWithParameters:completionBlock: carga una nueva pantalla de producto para mostrar.
En lugar de entrar en detalles técnicos sobre la implementación del hook, agregamos el siguiente fragmento de código a la aplicación de demostración:
Como resultado, vemos una solicitud POST a https://n.systemlog.me/log con la siguiente carga en el campo “clever”:
Como podemos ver, el ID del producto está en la solicitud. Caso cerrado.
Hook de NSURLProtocol
La clase NSURLProtocol permite a los desarrolladores redefinir el funcionamiento del sistema de carga de URL de Apple. El SDK de Mintegral registra una implementación maliciosa de NSURLProtocol, que se puede configurar de forma remota para interceptar cualquier solicitud saliente de una aplicación y rastrear URL y encabezados HTTP, incluido el encabezado Authorization.
Para los desarrolladores de aplicaciones, esto significa que Mintegral podría recopilar tokens de API, cookies y encabezados de autenticación básica.
Para entender cómo el SDK activa esa parte del código malicioso, debemos volver a ___cxxwebk_init_vw.

La captura de pantalla anterior muestra que la marca cud debe estar habilitada y que el arreglo cudl no debe estar vacío para activar el hook.
La siguiente captura de pantalla muestra parte de la función ___cxxwebkterisiuuxx, llamada desde el método anterior.

El código de la función ___cxxwebkterisiuuxx realiza las siguientes acciones:
Crea una clase que hereda de
NSURLProtocol(objc_registerClassPair,objc_allocateClassPair).Agrega una implementación para
canInitWithRequest:, que funciona como interceptor (class_addMethod).Llama a
+[NSURLProtocol registerClass:]para registrar la clase en el sistema de carga de URL.
En nuestra investigación, agregamos el siguiente fragmento de código para verificar qué datos recopila el código malicioso:
Como resultado, vemos una solicitud POST a https://n.systemlog.me/log con la siguiente carga en el campo “clever”:
En la solicitud podemos ver la URL y el encabezado de autorización. Aunque no se incluye el cuerpo de la solicitud, los encabezados suelen contener datos confidenciales. Incluso podrían incluir información de identificación personal. Por ejemplo, si una API usa tokens JWT, estos podrían contener el correo electrónico o el nombre de usuario.
Conclusión
Durante la investigación, observamos muchas técnicas interesantes que los desarrolladores de Mintegral usan para ocultar el comportamiento malicioso de su SDK. Como podemos ver, activan los hooks solo en aplicaciones específicas y en regiones específicas, lo que permitió que el código malicioso permaneciera allí más de un año sin llamar la atención.
En cuanto a la cronología, la primera versión (5.5.1) del SDK malicioso se publicó el 17 de julio de 2019. Descubrimos que todas las versiones posteriores incluían la misma funcionalidad maliciosa.
Muchas aplicaciones populares se vieron afectadas por la actividad maliciosa de este SDK. Esperamos que esta investigación, al arrojar luz sobre la situación, impulse un mayor escrutinio y mejores controles de privacidad para las redes de anunciantes en el futuro.
Ejecución remota de código (RCE) en iOS [octubre de 2020]
Resumen
Descubrimos que la clase MTGBaseBridgeWebView, que se usa en todo el SDK para comunicarse con JavaScript, funciona como una puerta trasera que permite invocar funciones arbitrarias desde el código nativo de la aplicación.

En la imagen de arriba se muestra un esquema simplificado de la ejecución remota de código.
Análisis de diferencias
Después de nuestra primera divulgación pública, Mintegral anunció el lanzamiento de una versión de código abierto del SDK.
Comparamos la nueva versión de código abierto con la versión binaria anterior, distribuida como cocoapod. Aunque no teníamos el código fuente de la versión anterior, podíamos comparar los nombres de las clases. Para ello, extrajimos los archivos .o de los binarios y comparamos los símbolos con los archivos .h de la versión de código abierto.
Como esperábamos, se eliminó el componente malicioso _CXX_CXX_OperationPKTask que habíamos descubierto anteriormente, pero el análisis de diferencias reveló algo más. Las siguientes clases nos llamaron la atención:
MTGCommandDispatcher
MTGComponentCommands
MTGRemoteCommand
MTGRemoteCommandParameterModel
MTGRemoteCommandParser
MTGInvocationBoxing
Decidimos analizar los binarios más de cerca para entender para qué se usaban esos archivos.
Versiones afectadas
Todas las versiones de MintegralAdSDK hasta 6.5.0.0 inclusive. La versión 6.6.0.0, publicada el 10 de septiembre de 2020, no tiene la funcionalidad de puerta trasera que se describe en este artículo.
Implementación del puente
Empezamos por buscar dónde se usa la clase MTGRemoteCommandParser y encontramos un solo lugar: -(void)handleNativeObject:parameters: en la clase MTGBaseBridgeWebView.
En la implementación vemos que -(void)handleNativeObject:parameters: usa MTGRemoteCommandParser para analizar el argumento parameters e invoca el método -(void)dispatchCommand:feedback: de la clase MTGCommandDispatcher.
A primera vista, parece que -(void)handleNativeObject:parameters: no se usa, pero no es así. Veamos cómo se puede invocar desde código JavaScript.
MTGBaseBridgeWebView implementa el método -(void)webView:decidePolicyForNavigationAction:decisionHandler: del protocolo WKNavigationDelegate. Este método se llama cada vez que se produce una navegación en la vista web. Esto significa que podemos activarlo desde JavaScript con solo llamar a location.href=something. En la versión de código abierto del SDK encontramos una expresión regular que analiza las URL de las solicitudes de navegación: mv://(.+?):(.+?)/(.+?)\\?([\\s\\S]*).

-(void)callFunctionWithName:fucId:param: en la captura de pantalla anterior simplemente realiza una llamada a self con el selector fucName.
Por lo tanto, para llamar a -(void)handleNativeObject:parameters: de MTGBaseBridgeWebView, necesitamos esta línea de código JavaScript: location.href = 'mv://1:fucId/handleNativeObject?<parameters>'.
Ten en cuenta que todo lo que describimos anteriormente sigue siendo válido en la versión más reciente del SDK al momento de escribir este artículo, así como en la versión de código abierto. La única excepción es que -(void)handleNativeObject:parameters: se eliminó de las versiones más recientes.
Invocación de métodos remotos
No describiremos la implementación completa de MTGInvocationBoxing ni de las demás clases. En su lugar, mostraremos cómo se puede crear código JavaScript malicioso para activar el método remoto.
La siguiente prueba de concepto ataca una aplicación de «notas simples» que tiene una clase NoteRepository con dos métodos: +(void)save: y +(NSString*)load.
Inyectamos el código JavaScript malicioso al reemplazar el servidor de Mintegral por nuestra propia implementación del servidor. El código fuente completo de esta aplicación y del servidor está disponible aquí .
El código JavaScript malicioso para esta aplicación es el siguiente:
Valor | Decodificado |
|---|---|
hbxtJ7QU+TPXJ75ZH+SXhFQTYbzP | static_NoteRepository |
Y7KtHv== | load |
Este código llamará al método +(NSString*)load de la clase NoteRepository y enviará el resultado a nuestro endpoint demo-evil-server.com/log.
Usa las mismas técnicas de ofuscación que se describen en la sección anterior. Sin embargo, la prueba de concepto ya incluye código JavaScript para codificar y decodificar (consulta banner.html).
Obtener ejecución remota de código (RCE) completa
En el ejemplo anterior vimos cómo se puede usar el SDK para invocar cualquier método estático de una clase arbitraria. En esta sección mostraremos cómo aprovechar esto para ejecutar cualquier código nativo.
Para la demostración, mostraremos cómo crear un UIAlertController con el mensaje "PWNED!".
Veamos el siguiente código de Objective-C como referencia:
Debemos averiguar cómo crear y conservar una instancia de UIAlertController entre llamadas, cómo obtener una instancia compartida de la aplicación y cómo llamar a presentViewController:animated:completion: con esa instancia.
Paso 1: Guardar una referencia a la clase UIAlertController
MTGRemoteCommandParser admite dos tipos de referencias a objetos:
static: obtiene una referencia a un objeto de clase por nombre.singleton: realiza varios pasos:Obtiene una clase por nombre (
MTGSettingen nuestro ejemplo).Ejecuta el método
sharedInstanceen la clase. En Objective-C:[MTGSetting sharedInstance].Usa
valueForKey:para obtener propiedades separadas por puntos. En nuestro caso, sería[[MTGSetting sharedInstance] valueForKey:@"jsonTitles"].
Ten en cuenta que jsonTitles es solo una instancia de NSMutableDictionary. En el exploit se usa como almacenamiento temporal para nuestras referencias. MTGRemoteCommandParser admite los siguientes tipos de parámetros:
0: número.1: referencia.2: cadena.4:nil.
El tipo de referencia (1) nos permite pasar una referencia a un objeto como argumento de un método. Es importante tener en cuenta que uniqueIdentifier se analiza exactamente igual que un uniqueIdentifier de nivel superior; por lo tanto, también admite el tipo singleton.
Paso 2: Asignar una nueva instancia de la clase UIAlertController
En este caso, toda la magia ocurre en singleton_MTGSetting.jsonTitles.a.alloc.init. Como ya sabemos, singleton_MTGSetting.jsonTitles.a nos proporciona una referencia a la clase UIAlertController. Pero debemos averiguar por qué funciona [[UIAlertController valueForKey:@"alloc"] valueForKey:@"init"]. En la documentación de valueForKey: encontramos lo siguiente:
El patrón de búsqueda que valueForKey: usa para encontrar el valor correcto que debe devolver se describe en Patrones de búsqueda de accesores de Guía de programación de codificación de valores clave.
Descubrimos que valueForKey: puede llamar a cualquier método por nombre si no tiene argumentos.
Así, ahora podemos crear una nueva instancia de la clase UIAlertController, a la que hará referencia la propiedad b del diccionario jsonTitles.
Paso 3: Configurar el mensaje "PWNED!"
Este paso es bastante obvio: llamamos a setMessage: en la instancia de UIAlertController para configurar el mensaje PWNED!.
Paso 4: Guardar una referencia a la clase UIApplication
Este paso es similar al paso 1. Debemos guardar la referencia a la clase UIApplication en jsonTitles.x.
Paso 5: Mostrar la alerta
Este paso parece complicado, pero solo utiliza varias técnicas de los pasos anteriores. En código Objective-C sería así:
En este punto, demostramos cómo mostrar una alerta mediante la ejecución remota de código. Puedes encontrar la carga completa aquí. Para ejecutar los pasos uno por uno, creamos un arreglo de acciones y ejecutamos cada acción en la devolución de llamada window.WindVane.onSuccess (es decir, después de que se completara la acción anterior).
Un video que muestra cómo se puede filtrar el contenido del portapapeles al distribuir el exploit mediante un anuncio malicioso.

Origen del exploit de JavaScript
Ya vimos cómo el SDK de Mintegral permite la ejecución remota de código nativo mediante código JavaScript. Sin embargo, Mintegral tiene el control total de ese código JavaScript. Pero, curiosamente, es posible lograr lo mismo mediante anuncios interactivos creados por los propios anunciantes. Los anuncios son páginas web basadas en JavaScript.
En teoría, un anunciante puede dirigir con precisión un anuncio malicioso que contiene el exploit de JavaScript a un grupo específico de usuarios o a un conjunto específico de dispositivos.
Conclusión
Solo podemos especular sobre por qué Mintegral incluyó en su SDK la capacidad de invocar métodos nativos de forma remota, pero, por los nombres de las clases, como MTGCommandDispatcher y MTGRemoteCommand, creemos que fue intencional. Además, Mintegral eliminó el código inmediatamente después de nuestra publicación, aunque en ese momento no teníamos conocimiento de ello.
Seguimiento de descargas en Android [octubre de 2020]
Resumen
En las dos secciones anteriores de este artículo de investigación, contamos cómo el equipo de seguridad de Snyk descubrió un comportamiento malicioso en el SDK de Mintegral que puede explotarse en dispositivos iOS y dar lugar a fraude publicitario, filtración de datos y ejecución remota de código (RCE). Queríamos investigar más la distribución del SDK para Android; eso es lo que abordaremos en esta sección. En resumen, estos son nuestros principales hallazgos:
Seguimiento de los URI de descarga de Google, que afecta tanto las descargas en el navegador como en las aplicaciones, incluidas las descargas habituales de archivos, los archivos adjuntos de correo electrónico y los enlaces de Google Docs.
Seguimiento de todas las descargas de APK, tanto orgánicas como no orgánicas.
Estos datos se envían a los servidores de Mintegral.
Comportamiento observado
Al descargar un enlace de Google Docs, observamos que la aplicación enviaba las siguientes solicitudes a https://n.systemlog.me:

Este es el mismo endpoint que se usó en el SDK de iOS para enviar datos al servidor de Mintegral. La carga útil está codificada, pero podemos usar la lógica de decodificación incluida en el binario del SDK para obtener lo siguiente:
Tenemos dos parámetros codificados adicionales: clever y dvi. Después de decodificarlos también, notamos algo interesante:
Como podemos ver, la URL de la hoja de cálculo de Google que descargamos desde la aplicación Google Drive se envía al backend en el campo ul, y el nombre del archivo descargado, en el campo kw, mientras que dvi contiene algunos datos del dispositivo.
Posibles usos
En el caso de iOS, se enviaban clics duplicados fraudulentos desde el dispositivo del cliente a los servidores de Mintegral y, luego, al proveedor de atribución (MMP). En este caso, las descargas o instalaciones de APK se reportan a los servidores y podrían usarse para generar clics del lado del servidor. El siguiente diagrama muestra el flujo de datos:

Módulo Alphab
El comportamiento mencionado arriba se encuentra en el módulo alphab, que Mintegral describió como un “paquete de optimización”:

Después de nuestra publicación, el módulo se eliminó del sitio de Mintegral y parece que ya no forma parte del SDK distribuido. Descompilamos el SDK y localizamos el código responsable de este comportamiento.
Clase AlphaCommonConst
Esta clase contiene muchas definiciones de constantes codificadas de forma rígida. Algunas cadenas están ofuscadas con un esquema de codificación propio basado en Base64, ubicado en la clase AlphabBase64Util, similar a lo que observamos en la distribución de iOS.
Al decodificarlas, obtenemos las siguientes cadenas:
Estas se usan en los pasos de inicialización que veremos a continuación.
Receptor Alphab
En el método init() de la clase AlphabReceiver, el BroadcastReceiver se inicializa con algunas de las cadenas previamente ofuscadas:
Al reemplazarlas por las cadenas decodificadas, el código queda así:
Podemos ver que, mediante la API de reflexión de Java, se crea un nuevo receptor de difusión que escucha dos tipos de intents:
android.intent.action.PACKAGE_ADDED: un intent de todo el sistema que se activa cuando se instala un paquete en el dispositivo.alphab_net_debug_action: un intent personalizado que parece detectar la depuración de red.
Al recibir el intent, la clase AlphabReceiver construye un método ParseAndLoad():
Este campo se usa posteriormente en una condición:
Al descompilar los otros dos métodos de esa cláusula if, se revela que comprueban si la conexión de red actual pasa por un proxy Wi-Fi o un cliente VPN. Esto busca impedir la depuración de la aplicación y la inspección de su tráfico. Este intent permite a los desarrolladores del SDK eludir esta función antidepuración.
Observador Alphab
De forma similar, el bloque de inicialización de este ContentObserver también está oculto mediante reflexión y cadenas ofuscadas:
Después de limpiar el código, obtenemos lo siguiente:
Esto significa que el observador de contenido está registrado para escuchar el URI content://downloads y se activa cada vez que se descarga un archivo en el dispositivo.
Consultará al administrador de descargas de Android para obtener las descargas públicas:
y, al decodificar la cadena, obtenemos lo siguiente:
Si la URL de descarga cumple alguna de las siguientes condiciones, se generará un informe a https://n.systemlog.met/stlog:
Termina en
apk: para las descargas manuales.Hace referencia a un paquete que pertenece a
com.android.vendingo la URL contiene google.com: esto detectará cualquier aplicación de Google e incluso las URL del navegador que cumplan la condición.
A continuación se muestra el fragmento de código que envía la solicitud al servidor https://n.systemlog.met/stlog.
que equivale a:
"Y aquí podemos ver los parámetros que observamos en la solicitud capturada en nuestro ejemplo:
p: nombre del paquete que se descarga, es decir, la aplicaciónv: versión de la aplicaciónul: URL del archivo descargadokw: nombre del archivo descargadofl: tamaño del archivo
Aplicación de demostración

Para demostrar este comportamiento, creamos una aplicación de demostración que nos permitió:
1. Habilitar la marca de depuración de red mediante reflexión para eludir la lógica antidepuración
2. Descargar un archivo desde una URL que contiene google.com
3. Descargar un archivo desde una URL que termina en apk
"Capturamos las solicitudes salientes con un proxy HTTP. Después de hacer clic en uno de los botones de descarga, vemos que se envía una solicitud al endpoint del servidor:

Aquí tienes un video que muestra el comportamiento de seguimiento:

Cronología
Fecha | Evento de investigación |
|---|---|
5 de ago. | El equipo de investigación de Snyk descubre que el SDK de Mintegral para iOS recopila datos en exceso y secuestra clics |
17 de ago. | Snyk comunica responsablemente los hallazgos a Apple |
24 de ago. | Snyk publica los hallazgos sobre Sour Mint para iOS |
25 de ago. | Mintegral publica una declaración en la que niega las acusaciones sobre el SDK |
3 de sept. | IronSource anuncia que eliminará Mintegral de su plataforma de mediación |
3 de sept. | Mintegral lanza la versión 6.5.0.0 del SDK para iOS y elimina el componente malicioso y oculto _CXX_CXX_OperationPKTask |
4 de sept. | La plataforma de mediación MoPub (Twitter) anuncia la descertificación de Mintegral de su plataforma |
4 de sept. | Mintegral anuncia sus planes para publicar el código fuente de su SDK |
4 de sept. | El equipo de investigación de Snyk identifica una funcionalidad oculta de seguimiento de descargas en la versión para Android del SDK |
9 de sept. | Snyk comunica responsablemente a Google los hallazgos sobre el SDK para Android |
10 de sept. | Mintegral lanza la versión 6.6.0.0 del SDK para iOS y elimina el componente de puerta trasera MTGRemoteCommandParser |
22 de sept. | Snyk obtiene el código fuente de la versión 6.6.0.0 del SDK para iOS y realiza un análisis de diferencias |
23 de sept. | Snyk descubre que Mintegral eliminó el módulo de seguimiento de descargas de Google de su SDK para Android |
30 de sept. | Mediante un análisis de diferencias, Snyk descubre una puerta trasera en la versión para iOS del SDK que permite la ejecución remota de código (RCE) |
2 de oct. | Snyk comunica responsablemente a Apple los nuevos hallazgos sobre iOS |
3 de oct. | Apple notifica a los editores afectados y les pide que eliminen el código que permite la ejecución remota de código |
15 de oct. | Snyk publica los hallazgos más recientes sobre iOS y Android |



