Informe de investigación sobre el SDK malicioso SourMint
Kirill Efimov
24 de agosto de 2020
0 minutos de lecturaDescripción general
Mintegral SDK es un popular SDK de publicidad para aplicaciones móviles, disponible para iOS y Android. Lo utilizan miles de aplicaciones móviles, con más de mil millones de descargas al mes. Los desarrolladores de aplicaciones usan este SDK para monetizar sus aplicaciones con anuncios de terceros.
El equipo de investigación de seguridad de Snyk realizó dos divulgaciones importantes relacionadas con Mintegral SDK. La primera divulgación se publicó en agosto de 2020 y reveló una recopilación excesiva de datos y el secuestro de clics en la distribución de iOS del SDK. La segunda divulgación descubrió una puerta trasera en la versión para iOS del SDK que permite la ejecución remota de código, además de nuevos hallazgos sobre la distribución para Android del SDK.
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 trató en las publicaciones del blog.
Este informe 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 distribución para iOS de Mintegral SDK.
Una puerta trasera en la distribución para iOS del SDK permite la ejecución remota de código: describe las capacidades de ejecución remota de código en MintegralAdSDK, publicado el 15 de octubre de 2020.
Seguimiento de URL de descargas en Android: describe varios hallazgos en la distribución para Android de Mintegral SDK.
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 del SDK de Mintegral para iOS, ya que en agosto de 2020 aún no teníamos acceso a la versión de código abierto. La investigación se llevó a cabo con la versión 6.3.5.0 del SDK (para arquitectura x86), disponible para descargar desde GitHub.
Identificamos que las versiones 5.5.1 y posteriores del SDK de Mintegral para iOS contienen funciones maliciosas que provocan filtraciones 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. Además, el SDK intenta ocultar su comportamiento malicioso al detectar proxies, simuladores y dispositivos con jailbreak.
Swizzling de métodos
Mintegral SDK utiliza una técnica llamada swizzling de métodos para reemplazar, en tiempo de ejecución, las implementaciones de los métodos UIApplication openURL y SKStoreProductViewController loadProductWithParameters. También registra una clase personalizada NSURLProtocol.
Estos hooks se utilizan 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), estos datos permiten que Mintegral cometa fraude de atribución publicitaria.
Fraude de atribución publicitaria
Para monetizar sus aplicaciones, los desarrolladores suelen instalar plataformas publicitarias. Estas plataformas reciben ingresos de los anunciantes por cada instalación que se produce después de que un usuario hace clic en un anuncio. Es común que los desarrolladores usen varias plataformas publicitarias en sus aplicaciones. Por eso, para determinar qué plataforma publicitaria debe recibir la atribución de una instalación, cada clic se registra en un proveedor de atribución, una plataforma de medición móvil (MMP).
La siguiente figura muestra cómo funciona la funcionalidad maliciosa de Mintegral. En este ejemplo, el usuario hizo clic en un anuncio de “Another Platform”. Sin embargo, como Mintegral puede interceptar todas las URL que abre la aplicación, podría enviar solicitudes adicionales a un proveedor de atribución y fingir 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 la 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 swizzling 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 notificación de clic 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 la investigación, el proveedor pudo demostrar que se generaban notificaciones de clic falsas y que estas provocaban que los clics en anuncios se atribuyeran incorrectamente a Mintegral.
Aplicación de demostración
Para demostrar el ataque, configuramos una aplicación de demostración. Esta muestra el hook malicioso 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:
GET https://setting.rayjump.com/sdk/customidGET https://setting.rayjump.com/settingPOST https://analytics.rayjump.com

Configuración
La respuesta de https://setting.rayjump.com/setting es un objeto JSON con muchas opciones diferentes. La siguiente tabla describe los campos más interesantes 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 de los métodos de StoreKit. |
cud | Habilita o deshabilita el hook de NSURLProtocol. |
cudl | Arreglo de URL que se rastrean mediante NSURLProtocol (**). |
* En nuestro caso, era LdxThdi1WBK/WgfPhbxQYkeXHBPwHZKsYFh= , que, al decodificarse, corresponde a https://n.systemlog.me/log.
** En nuestro caso, era kBzuJd5/H+i/D+SMY7V/DFKwR0M0D+SMhBPthdSsHZPUYFT0+N==, que, al decodificarse, 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 esperábamos. 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á pensada para que los desarrolladores accedan a ella.
Usamos el siguiente fragmento de código para decodificar la carga útil:

La carga útil contiene muchos datos, incluidos el IDFA, el 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 pila y algunos datos adicionales, como el controlador y el nombre del método.
Análisis en profundidad
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 Macho que contiene varios binarios más. El código que nos interesa se encuentra en _CXX_CXX_OperationPKTask.o.
Al revisar la clase, vemos +[_CXX_CXX_OperationPKTask load], que se ejecuta automáticamente cuando la clase se agrega en tiempo de ejecución. Esto significa que, si el SDK se instala mediante CocoaPods, la lógica maliciosa se inicializará 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 JSON de la respuesta 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 de 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).Hay uno de los siguientes archivos 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).
Swizzling 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.

La captura de pantalla anterior muestra la implementación del swizzling 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. Ahora analizaremos su propia 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 todas las URL de marketing en las que el usuario hace clic en un anuncio publicado por Mintegral. En la captura de pantalla siguiente podemos ver 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 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 a +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:]. En la siguiente captura de pantalla se muestran los argumentos de la llamada:

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

Al volver a +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:], después de codificar la carga útil mediante +[MTGBase base64EncodeString:], crea un nuevo bloque de código y usa _dispatch_async para invocarlo.
Esto da lugar a una serie de llamadas con transformaciones adicionales de la carga útil y termina en -[_MC_ApiManager AFRequestWithUrl:paras:success:failure:], que realiza una solicitud POST a collectDomainUrl de MTGSetting, cuyo valor predeterminado es https://n.systemlog.me/log.
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 mostrarla.
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 útil en el campo “clever”:
Como podemos ver, el ID del producto está en la solicitud. Queda demostrado.
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 activa el SDK esa parte del código malicioso, tenemos que volver a ___cxxwebk_init_vw.

La captura de pantalla anterior muestra que el indicador cud debe estar habilitado 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, que se llama 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 útil 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, el correo electrónico o el nombre de usuario podrían estar almacenados dentro del token.
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 y regiones específicas, lo que permitió que el código malicioso permaneciera allí durante 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 las actividades maliciosas de este SDK. Esperamos que esta investigación, al arrojar luz sobre la situación, impulse un mayor escrutinio y controles de privacidad en las redes publicitarias.
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, actúa como puerta trasera y permite invocar funciones arbitrarias desde el código nativo de la aplicación.

En la imagen anterior puedes ver un esquema simplificado de la ejecución remota de código en acción.
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 hacerlo, 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 había eliminado el componente malicioso _CXX_CXX_OperationPKTask que ya habíamos descubierto, 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 anteriores a la 6.5.0.0, inclusive. La versión 6.6.0.0, publicada el 10 de septiembre de 2020, no incluye 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, podemos ver 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 no se usa -(void)handleNativeObject:parameters:, 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.
Entonces, para llamar a -(void)handleNativeObject:parameters: de MTGBaseBridgeWebView, necesitamos la siguiente 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 otras clases. En cambio, 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 reemplazando el servidor de Mintegral por nuestra propia implementación de servidor. Puedes encontrar aquí el código fuente completo de esta aplicación y del servidor.
El código JavaScript malicioso para esta aplicación es el siguiente:
Valor | Decodificado |
|---|---|
hbxtJ7QU+TPXJ75ZH+SXhFQTYbzP | static_NoteRepository |
Y7KtHv== | load |
Este código llama al método +(NSString*)load de la clase NoteRepository y envía 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 aprovecharlo para ejecutar cualquier código nativo.
A modo de demostración, mostraremos cómo crear un UIAlertController con el mensaje "PWNED!".
Tomemos como referencia el siguiente código de Objective-C:
Tenemos que 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 la 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.[MTGSetting sharedInstance]en Objective-C.
Usa
valueForKey:para obtener propiedades separadas por puntos. En nuestro caso, sería[[MTGSetting sharedInstance] valueForKey:@"jsonTitles"].
Ten en cuenta que jsonTitles es simplemente 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 tenemos que entender por qué funciona [[UIAlertController valueForKey:@"alloc"] valueForKey:@"init"]. En la documentación de valueForKey: encontramos lo siguiente:
El patrón de búsqueda que usa valueForKey: para encontrar el valor correcto que debe devolver se describe en Patrones de búsqueda de accesores de la Guía de programación de codificación de valores clave.
Descubrimos que valueForKey: puede llamar a cualquier método por nombre si este no recibe 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: Establecer el mensaje "PWNED!"
Este paso es bastante obvio: llamamos a setMessage: en la instancia de UIAlertController para establecer el mensaje PWNED!.
Paso 4: Guardar una referencia a la clase UIApplication
Este paso es similar al paso 1. Tenemos que guardar la referencia a la clase UIApplication en jsonTitles.x.
Paso 5: Mostrar la alerta
Este paso parece complicado, pero simplemente utiliza varias técnicas de los pasos anteriores. En código Objective-C, sería así:
En este punto, demostramos cómo se puede mostrar una alerta mediante la ejecución remota de código. Puedes encontrar la carga útil completa aquí. Para llamar a los pasos uno por uno, creamos un arreglo de acciones y ejecutamos cada acción en la devolución de llamada window.WindVane.onSuccess (a su vez, después de que se completara la acción anterior).
Video que muestra cómo se puede filtrar el contenido del portapapeles al distribuir el exploit mediante un anuncio malicioso.

Código fuente del exploit de JavaScript
Ya vimos cómo el SDK de Mintegral permite la ejecución remota de código nativo mediante JavaScript. Sin embargo, Mintegral controla por completo 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 dirigirse con precisión a un grupo específico de usuarios o a un conjunto concreto de dispositivos mediante un anuncio malicioso que incluya el exploit de JavaScript.
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 el nombre 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 lo sabíamos.
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 provocar fraude publicitario, filtración de datos y ejecución remota de código (RCE). Quisimos investigar más la distribución del SDK para Android, como explicamos en esta sección.
En resumen, estos son nuestros principales hallazgos:
Seguimiento de URI de descargas de Google, tanto del navegador como de aplicaciones, incluidas las descargas de archivos habituales, los archivos adjuntos de correo electrónico y los enlaces de Google Docs.
Seguimiento de todas las descargas de APK, orgánicas o no.
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 usaba en el SDK de iOS para enviar datos al servidor de Mintegral. El payload está codificado, pero podemos aplicar 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, observamos 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 usuario a los servidores de Mintegral y, luego, al proveedor de atribución (MMP). En este caso, las APK descargadas o instaladas 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 anteriormente 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 directamente. 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 para 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, se inicializa BroadcastReceiver con algunas de las cadenas ofuscadas anteriormente:
Al reemplazarlas por las cadenas decodificadas, el código queda así:
Podemos ver que, mediante el uso de 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 del 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():
Luego, este campo se usa en una condición:
Al descompilar los otros dos métodos de esa cláusula if, vemos que verifican si la conexión de red actual pasa por un proxy wifi 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 funcionalidad 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á el 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 genera un reporte a https://n.systemlog.met/stlog:
Termina en
apk: para las descargas manuales.Hace referencia a un paquete de
com.android.vendingo la URL contiene google.com: detecta 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.
lo que equivale a:
Aquí podemos ver los parámetros que observamos en la solicitud capturada de 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 el indicador 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:

Este video muestra el comportamiento de seguimiento:

Cronología
Fecha | |
|---|---|
5 de agosto | El equipo de investigación de Snyk descubre que el SDK de Mintegral para iOS recopila datos en exceso y secuestra clics |
17 de agosto | Snyk divulga responsablemente los hallazgos a Apple |
24 de agosto | Snyk publica los hallazgos de Sour Mint para iOS |
25 de agosto | Mintegral publica un comunicado en el que niega las acusaciones sobre el SDK |
3 de septiembre | IronSource anuncia que retirará Mintegral de su plataforma de mediación |
3 de septiembre | Mintegral publica la versión 6.5.0.0 del SDK para iOS y elimina el componente malicioso y oculto _CXX_CXX_OperationPKTask |
4 de septiembre | La plataforma de mediación MoPub (Twitter) anuncia la descertificación de Mintegral |
4 de septiembre | Mintegral anuncia sus planes de publicar el código fuente de su SDK |
4 de septiembre | 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 septiembre | Snyk divulga responsablemente los hallazgos sobre el SDK para Android a Google |
10 de septiembre | Mintegral publica la versión 6.6.0.0 del SDK para iOS y elimina el componente de puerta trasera MTGRemoteCommandParser |
22 de septiembre | 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 septiembre | Snyk descubre que Mintegral eliminó el módulo de seguimiento de descargas de Google de su SDK para Android |
30 de septiembre | 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 octubre | Snyk divulga responsablemente los nuevos hallazgos sobre iOS a Apple |
3 de octubre | Apple notifica a los publishers afectados y les pide que eliminen el código que permite la ejecución remota de código (RCE) |
15 de octubre | Snyk publica los hallazgos más recientes sobre iOS y Android |



