Relatório da pesquisa sobre o SDK malicioso SourMint
Kirill Efimov
24 de agosto de 2020
0 minutos de leituraVisão geral
O Mintegral SDK é um SDK popular de publicidade para aplicativos móveis, disponível para iOS e Android. Ele é usado por milhares de aplicativos, que somam mais de um bilhão de downloads por mês. Desenvolvedores de aplicativos usam o SDK para monetizar seus apps com anúncios de terceiros.
A equipe de pesquisa de segurança da Snyk fez duas divulgações importantes sobre o Mintegral SDK. A primeira divulgação, publicada em agosto de 2020, revelou coleta excessiva de dados e sequestro de cliques na versão do SDK para iOS. A segunda divulgação revelou uma porta dos fundos na versão para iOS do SDK, que permite a execução remota de código, além de novas descobertas sobre a distribuição do SDK para Android.
Este artigo tem como objetivo compartilhar os detalhes técnicos da nossa pesquisa e das nossas descobertas, indo além do que foi apresentado nas publicações do blog.
Este relatório está dividido em três seções:
Coleta excessiva de dados, incluindo a interceptação e o registro de todas as solicitações HTTP no SDK para iOS — publicado originalmente em 24 de agosto de 2020 —, descreve os recursos de rastreamento de URLs e solicitações na distribuição do Mintegral SDK para iOS.
Uma porta dos fundos na distribuição do SDK para iOS permite a execução remota de código — descreve os recursos de execução remota de código do MintegralAdSDK, publicados em 15 de outubro de 2020.
Rastreamento de URLs de download no Android — descreve várias descobertas na distribuição do Mintegral SDK para Android.
Coleta excessiva de dados no iOS [agosto de 2020]
Visão geral
Esta parte da pesquisa foi feita com a versão binária do Mintegral SDK para iOS, pois a versão de código aberto ainda não estava disponível para nós em agosto de 2020. A pesquisa foi realizada na versão 6.3.5.0 do SDK (para arquitetura x86), disponível para download no GitHub.
Identificamos que as versões 5.5.1 e posteriores do Mintegral SDK para iOS contêm funcionalidades maliciosas que provocam vazamento de informações. Em termos simples, o SDK espiona os cliques dos usuários em links e a atividade de rede nos aplicativos afetados. A espionagem acontece mesmo quando o desenvolvedor ou a plataforma de mediação de anúncios não ativa o SDK. Além disso, ele tenta ocultar o comportamento malicioso detectando proxies, simuladores e dispositivos com jailbreak.
Swizzling de métodos
O Mintegral SDK usa uma técnica chamada swizzling de métodos para substituir, em tempo de execução, as implementações dos métodos UIApplication openURL e SKStoreProductViewController loadProductWithParameters. Ele também registra uma classe NSURLProtocol personalizada.
Esses hooks são usados para espionar os usuários dos aplicativos, enviando todas as informações sobre solicitações HTTP, URLs abertas e links da App Store em que eles clicam dentro do aplicativo.
Os cabeçalhos e as URLs das solicitações HTTP podem conter dados confidenciais. Combinados ao IDFA (Identifier for Advertisers), esses dados permitem que a Mintegral pratique fraude de atribuição de anúncios.
Fraude de atribuição de anúncios
Para monetizar seus aplicativos, os desenvolvedores costumam instalar plataformas de publicidade. Os anunciantes pagam essas plataformas por cada instalação realizada depois que um usuário clica em um anúncio. É comum que desenvolvedores usem várias plataformas de publicidade em seus aplicativos. Por isso, para determinar qual plataforma deve receber o crédito pela instalação, cada clique é registrado em um provedor de atribuição, uma plataforma de mensuração móvel (MMP).
A figura abaixo mostra como funciona a funcionalidade maliciosa do Mintegral. Neste exemplo, o usuário clicou em um anúncio de “Outra plataforma”. Mas, como o Mintegral consegue interceptar todas as URLs abertas pelo aplicativo, ele pode enviar solicitações adicionais a um provedor de atribuição, fingindo que o clique foi feito em um anúncio próprio. O processo completo funciona assim:
O usuário clica em um link de um anúncio no aplicativo, veiculado por uma rede de anúncios que não é a Mintegral, para instalar um novo aplicativo pela App Store.
O SDK da rede de anúncios envia as informações do clique para a plataforma de back-end.
Depois de interceptar o evento de clique por meio de código injetado nos manipuladores de eventos do iOS com swizzling de métodos, o Mintegral registra os dados do clique no próprio servidor.
A rede de anúncios registra uma notificação de clique no provedor de atribuição.
O Mintegral também registra uma notificação de clique no provedor de atribuição.
Quando o provedor de atribuição tenta associar o evento de instalação às notificações de clique registradas, encontra duas correspondências. Como usa um modelo de atribuição de último toque, atribui a instalação à notificação de clique do Mintegral e rejeita a notificação da outra rede de anúncios.

A Snyk trabalhou com um importante provedor de atribuição para confirmar que o Mintegral usa os dados de cliques para gerar notificações falsas. Na investigação, o provedor conseguiu demonstrar que essas notificações falsas estavam sendo geradas e faziam com que cliques em anúncios fossem atribuídos incorretamente ao Mintegral.
Aplicativo de demonstração
Para demonstrar o ataque, configuramos um aplicativo de demonstração. Ele mostra o hook malicioso openURL em ação. Usamos um proxy de depuração para interceptar todo o tráfego de rede.
Para inicializar o aplicativo, usamos o seguinte trecho de código da documentação do Mintegral:
Com o SDK inicializado, abrimos example.com no aplicativo ao clicar em um botão:
Depois de abrir o app, vemos imediatamente algumas solicitações do Mintegral SDK no nosso proxy:
GET https://setting.rayjump.com/sdk/customidGET https://setting.rayjump.com/settingPOST https://analytics.rayjump.com

Configurações
A resposta de https://setting.rayjump.com/setting é um objeto JSON com várias opções. A tabela a seguir descreve os campos mais relevantes para a nossa pesquisa.
Campo JSON | Descrição |
|---|---|
csw | Ativa ou desativa a funcionalidade antidepuração. |
cou | Ativa ou desativa o hook do método |
cdai | URL para onde as informações vazadas são enviadas (*). |
cspn | Ative ou desative o hook nos métodos do StoreKit. |
cud | Ativa ou desativa o hook no NSURLProtocol. |
cudl | Lista de URLs rastreadas pelo NSURLProtocol (**). |
* No nosso caso, era LdxThdi1WBK/WgfPhbxQYkeXHBPwHZKsYFh= , que, após a decodificação, corresponde a https://n.systemlog.me/log.
** No nosso caso, era kBzuJd5/H+i/D+SMY7V/DFKwR0M0D+SMhBPthdSsHZPUYFT0+N==, que, após a decodificação, corresponde a ["itunes.apple.com","apps.apple.com"].
Decodificação do payload
Depois de clicar no botão que abre example.com, vemos mais duas solicitações. A primeira é uma solicitação GET para http://example.com, como esperado. A segunda é uma solicitação POST para https://n.systemlog.me/log.

O corpo da solicitação parece estar codificado em base64. Na verdade, porém, não é uma string codificada em base64. O Mintegral SDK implementa sua própria lógica de codificação e decodificação, que pode ser encontrada em +[MTGBase base64DecodeString:] e +[MTGBase base64CleverDecodeString:]. Observe que MTGBase não está exposto nos cabeçalhos públicos do SDK e não foi projetado para ser acessível aos desenvolvedores.
Usamos o seguinte trecho de código para decodificar o payload:

O payload contém muitos dados, incluindo IDFA, IDFV, versão do sistema operacional, user agent e outros. No entanto, ele também contém um campo chamado “clever”, que, mais uma vez, está codificado. Podemos decodificá-lo usando base64DecodeString:
Como você pode ver, ele contém a URL, o rastreamento de pilha e algumas informações adicionais, como o controlador e o nome do método.
Análise aprofundada
Como mencionamos anteriormente, o Mintegral SDK tem código fechado. Vamos analisar a versão 6.3.5.0 para arquitetura x86.
O binário é um executável Mach-O que contém vários outros binários. O código que nos interessa está em _CXX_CXX_OperationPKTask.o.
Ao analisar a classe, encontramos +[_CXX_CXX_OperationPKTask load], que é executado automaticamente quando a classe é adicionada em tempo de execução. Isso significa que, se o SDK for instalado via CocoaPods, a lógica maliciosa será inicializada independentemente de os desenvolvedores usarem o SDK.
O método load executa uma série de chamadas que nos levam a ___cxxwebk_init_vw. Esse método verifica se a flag de proteção antidepuração está ativada e inicializa os hooks se a flag estiver desativada ou se a depuração estiver desabilitada.

A inicialização dos hooks depende da solicitação de configurações mencionada acima. Na tabela a seguir, vemos a relação entre os campos da resposta JSON e a classe MTGSetting:
Campo JSON | Propriedade de MTGSetting | Descrição |
|---|---|---|
csw | cSrtW | Ativa ou desativa a funcionalidade antidepuração. |
cou | cOpenURL | Ativa ou desativa o hook do método |
cspn | cPackageName | Ative ou desative o hook nos métodos do StoreKit. |
Lógica antidepuração

A função __cxx_cxx_op_isInSuperViewFrame retorna true nos seguintes casos:
A plataforma do dispositivo é um “simulador”.
Há um depurador conectado (implementado em
____mvpmvvm_isDebuggerAttached_block_invoke).Um dos seguintes arquivos está presente no dispositivo (indício de jailbreak):
/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt
/usr/bin/ssh
O proxy está ativado (usando
CFNetworkCopySystemProxySettings).
Swizzling do método openURL
A lógica da captura de tela a seguir está implementada no método ___cxxwebkmcouitninapo, chamado por ___cxxwebk_init_vw quando a flag correspondente está ativada.

A captura de tela acima mostra a implementação do swizzling de métodos. Ela executa as seguintes chamadas:
NSSelectorFromStringpara obter um seletor do método “openURL:”.NSClassFromStringpara obter um descritor da classeUIApplication.class_getInstanceMethodpara obter o descritor do método.method_getImplementationpara obter a implementação real do método.Em seguida, eles definem um bloco de código que chama
_____cxxwebkmcouitninapo_block_invoke_2e, depois, chama oopenURLoriginal.method_setImplementationpara substituir o openURL original pelo bloco de código da etapa anterior.
Quase o mesmo acontece com o método openURL:options:completionHandler:, mas antes eles verificam a versão do sistema (o handler foi introduzido pela primeira vez no iOS 10).
Neste ponto, já vimos como o hook foi aplicado. Agora vamos analisar a implementação do próprio hook (_____cxxwebkmcouitninapo_block_invoke_2).
Implementação do hook openURL
Na prática, a implementação está localizada no método ___cxxwebkmcoulsz. Nele, vemos outra verificação antidepuração. Em seguida, ele verifica a flag __mc_notifyInHouse e não faz nada se ela estiver definida como 1.
Isso serve para ignorar todos os URLs de marketing clicados pelo usuário em um anúncio veiculado pelo Mintegral. A captura de tela abaixo mostra a lógica correspondente em +[MTGBase mtgOpenURL:options:completionHandler:]:

O próximo trecho de código mostra que eles também serializam os dados do rastreamento de pilha e os vazam no payload enviado para https://n.systemlog.me/log.
Conseguimos definir um breakpoint na chamada +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:]. A captura de tela seguinte mostra os argumentos da chamada:

A URL aberta (http://example.com?foo=bar&x=y).
A classe em que ocorreu o clique (
ViewController).O método em que ocorreu o clique (
openURLWithOptions:).Informações do rastreamento de pilha.
Outra função interessante é _nsh_id_by_cc, que parece ser responsável por identificar SDKs concorrentes. A captura de tela seguinte mostra a lógica relevante:

Voltando a +[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:], depois que o payload é codificado por meio de +[MTGBase base64EncodeString:], um novo bloco de código é criado e _dispatch_async é usado para invocá-lo.
Isso leva a uma série de chamadas com transformações adicionais do payload e termina em -[_MC_ApiManager AFRequestWithUrl:paras:success:failure:], que faz uma requisição POST para collectDomainUrl de MTGSetting, cujo valor padrão é https://n.systemlog.me/log.
Vídeo que demonstra como um URL privado pode ser exposto.

Hook de SKStoreProductViewController
SKStoreProductViewController é um controlador de visualização que fornece uma página na qual o usuário pode comprar conteúdo na App Store.
O método loadProductWithParameters:completionBlock: carrega uma nova tela de produto para exibição.
Em vez de entrar nos detalhes técnicos da implementação do hook, adicionamos o seguinte trecho de código ao aplicativo de demonstração:
Como resultado, vemos uma requisição POST para https://n.systemlog.me/log com o seguinte payload no campo “clever”:
Como podemos ver, o ID do produto está na requisição. Q.E.D.
Hook de NSURLProtocol
A classe NSURLProtocol permite que um desenvolvedor redefina o funcionamento do sistema de carregamento de URLs da Apple. O SDK da Mintegral registra uma implementação maliciosa de NSURLProtocol, que pode ser configurada remotamente para interceptar quaisquer requisições de saída feitas por um aplicativo e rastrear URLs e cabeçalhos HTTP, inclusive o cabeçalho Authorization.
Para quem desenvolve aplicativos, isso significa que tokens de API, cookies e cabeçalhos de autenticação básica podem ser coletados pela Mintegral.
Para entender como o SDK ativa essa parte do código malicioso, precisamos voltar a ___cxxwebk_init_vw.

A captura de tela acima mostra que a flag cud precisa estar habilitada e que o array cudl não pode estar vazio para ativar o hook.
A captura de tela a seguir mostra parte da função ___cxxwebkterisiuuxx, chamada pelo método acima.

O código na função ___cxxwebkterisiuuxx realiza as seguintes ações:
Cria uma classe que herda de
NSURLProtocol(objc_registerClassPair,objc_allocateClassPair).Adiciona uma implementação para
canInitWithRequest:, que funciona como um interceptor (class_addMethod).Chama
+[NSURLProtocol registerClass:]para registrar a classe no sistema de carregamento de URLs.
Em nossa pesquisa, adicionamos o seguinte trecho de código para verificar quais dados são coletados pelo código malicioso:
Como resultado, vemos uma requisição POST para https://n.systemlog.me/log com o seguinte payload no campo “clever”:
Na requisição, podemos ver o URL e o cabeçalho de autorização. Embora o corpo da requisição não esteja incluído, os cabeçalhos muitas vezes contêm dados confidenciais. Esses dados podem até incluir informações de identificação pessoal. Por exemplo, se uma API usa tokens JWT, o e-mail ou o nome de usuário podem estar armazenados dentro do token.
Conclusão
Durante a pesquisa, observamos várias técnicas interessantes usadas pelos desenvolvedores da Mintegral para ocultar o comportamento malicioso do SDK. Como podemos ver, os hooks só são ativados em aplicativos específicos e em regiões específicas, o que ajudou o código malicioso a permanecer ativo por mais de um ano sem chamar atenção.
Sobre a linha do tempo, a primeira versão (5.5.1) do SDK malicioso foi publicada em 17 de julho de 2019. Descobrimos que todas as versões posteriores mantinham a mesma funcionalidade maliciosa.
Muitos aplicativos populares foram afetados pelas atividades maliciosas desse SDK. Esperamos que esta pesquisa, ao esclarecer a situação, leve a uma análise mais rigorosa e a controles de privacidade mais robustos para redes de publicidade.
Execução remota de código (RCE) no iOS [outubro de 2020]
Resumo
Descobrimos que a classe MTGBaseBridgeWebView, usada em todo o SDK para se comunicar com JavaScript, funciona como uma porta dos fundos, permitindo invocar funções arbitrárias a partir do código nativo do aplicativo.

Na imagem acima, você pode ver um esquema simplificado da execução remota de código em ação.
Análise de diferenças
Após nossa primeira divulgação pública, a Mintegral anunciou o lançamento de uma versão de código aberto do SDK.
Comparamos a nova versão de código aberto com a versão binária anterior distribuída como cocoapod. Embora não tivéssemos o código-fonte da versão mais antiga, ainda era possível comparar os nomes das classes. Para isso, extraímos os arquivos .o dos binários e comparamos os símbolos com os arquivos .h da versão de código aberto.
Como esperado, o componente malicioso _CXX_CXX_OperationPKTask, descoberto anteriormente, havia sido removido, mas a comparação revelou outra coisa. As seguintes classes chamaram nossa atenção:
MTGCommandDispatcher
MTGComponentCommands
MTGRemoteCommand
MTGRemoteCommandParameterModel
MTGRemoteCommandParser
MTGInvocationBoxing
Decidimos analisar os binários mais de perto para entender para que esses arquivos eram usados.
Versões afetadas
Todas as versões do MintegralAdSDK até a 6.5.0.0, inclusive. A versão 6.6.0.0, publicada em 10 de setembro de 2020, não contém a funcionalidade de porta dos fundos descrita neste artigo.
Implementação da ponte
Começamos verificando onde a classe MTGRemoteCommandParser era usada e encontramos apenas um local: -(void)handleNativeObject:parameters:, na classe MTGBaseBridgeWebView.
Pela implementação, podemos ver que -(void)handleNativeObject:parameters: usa MTGRemoteCommandParser para analisar o argumento parameters e invoca o método -(void)dispatchCommand:feedback: na classe MTGCommandDispatcher.
À primeira vista, parece que -(void)handleNativeObject:parameters: não é usado, mas não é o caso. Vamos ver como ele pode ser invocado a partir do código JavaScript.
MTGBaseBridgeWebView implementa o método -(void)webView:decidePolicyForNavigationAction:decisionHandler: do protocolo WKNavigationDelegate. Esse método é chamado sempre que ocorre uma navegação na web view. Isso significa que podemos acioná-lo a partir do JavaScript simplesmente chamando location.href=something. Na versão de código aberto do SDK, encontramos uma expressão regular que analisa os URLs das requisições de navegação: mv://(.+?):(.+?)/(.+?)\\?([\\s\\S]*).

-(void)callFunctionWithName:fucId:param: na captura de tela acima simplesmente faz uma chamada a self com o seletor fucName.
Portanto, para chamar -(void)handleNativeObject:parameters: de MTGBaseBridgeWebView, precisamos da seguinte linha de código JavaScript: location.href = 'mv://1:fucId/handleNativeObject?<parameters>'.
Vale observar que tudo o que descrevemos acima ainda é válido na versão mais recente do SDK disponível no momento da redação deste artigo, assim como na versão de código aberto. A única exceção é que -(void)handleNativeObject:parameters: foi removido das versões mais recentes.
Invocação remota de métodos
Não vamos descrever toda a implementação de MTGInvocationBoxing e de outras classes. Em vez disso, vamos mostrar como é possível criar código JavaScript malicioso para acionar o método remoto.
A prova de conceito a seguir ataca um aplicativo simples de anotações, que tem uma classe NoteRepository com dois métodos: +(void)save: e +(NSString*)load.
Injetamos o código JavaScript malicioso substituindo o servidor da Mintegral por uma implementação própria. O código-fonte completo deste aplicativo e do servidor está disponível aqui.
O código JavaScript malicioso para este aplicativo é o seguinte:
Valor | Decodificado |
|---|---|
hbxtJ7QU+TPXJ75ZH+SXhFQTYbzP | static_NoteRepository |
Y7KtHv== | load |
Esse código chama o método +(NSString*)load da classe NoteRepository e envia o resultado para o endpoint demo-evil-server.com/log.
Ele usa as mesmas técnicas de ofuscação descritas na seção anterior. Mas a prova de conceito já inclui código JavaScript para codificação e decodificação (consulte banner.html).
Obtendo execução remota de código (RCE) completa
No exemplo acima, vimos como o SDK pode ser usado para invocar qualquer método estático de uma classe arbitrária. Nesta seção, vamos demonstrar como isso pode ser aproveitado para executar qualquer código nativo.
Para fins de demonstração, vamos mostrar como criar um UIAlertController com a mensagem "PWNED!".
Vamos usar o seguinte código Objective-C como referência:
Precisamos descobrir como criar e manter uma instância de UIAlertController entre chamadas, como obter uma instância compartilhada do aplicativo e como chamar presentViewController:animated:completion: com essa instância.
Etapa 1: salvar uma referência à classe UIAlertController
O MTGRemoteCommandParser oferece suporte a dois tipos de referências a objetos:
static- obtém uma referência a um objeto de classe pelo nome.singleton- executa várias etapas:Obtém uma classe pelo nome (
MTGSetting, neste exemplo).Executa o método
sharedInstancena classe.[MTGSetting sharedInstance]em Objective-C.
Usa
valueForKey:para obter propriedades separadas por pontos. No nosso caso, isso será[[MTGSetting sharedInstance] valueForKey:@"jsonTitles"].
Observe que jsonTitles é apenas uma instância de NSMutableDictionary. No exploit, ela é usada como armazenamento temporário para nossas referências. O MTGRemoteCommandParser oferece suporte aos seguintes tipos de parâmetro:
0- número.1- referência.2- string.4-nil.
O tipo de referência (1) permite passar uma referência a um objeto como argumento de um método. É importante observar que uniqueIdentifier é analisado exatamente da mesma forma que um uniqueIdentifier de nível superior — portanto, também há suporte ao tipo singleton.
Etapa 2: alocar uma nova instância da classe UIAlertController
Neste caso, toda a mágica acontece em singleton_MTGSetting.jsonTitles.a.alloc.init. Como já sabemos, singleton_MTGSetting.jsonTitles.a nos fornece uma referência à classe UIAlertController. Mas precisamos entender por que [[UIAlertController valueForKey:@"alloc"] valueForKey:@"init"] funciona. Na documentação de valueForKey:, sabemos que:
O padrão de busca que valueForKey: usa para encontrar o valor correto a ser retornado é descrito em Accessor Search Patterns no Key-Value Coding Programming Guide.
Descobrimos que valueForKey: pode chamar qualquer método pelo nome, desde que não receba argumentos.
Assim, agora podemos criar uma nova instância da classe UIAlertController, que será referenciada pela propriedade b do dicionário jsonTitles.
Etapa 3: definir a mensagem "PWNED!"
Esta etapa é bem simples: chamamos setMessage: na instância de UIAlertController para definir a mensagem PWNED!.
Etapa 4: salvar uma referência à classe UIApplication
Esta etapa é parecida com a etapa 1. Precisamos salvar a referência à classe UIApplication em jsonTitles.x.
Etapa 5: exibir o alerta
Esta etapa parece complicada, mas apenas utiliza várias técnicas das etapas anteriores. Em código Objective-C, ficaria assim:
Neste ponto, mostramos como exibir um alerta por meio de execução remota de código. Você encontra o payload completo aqui. Para executar as etapas uma a uma, criamos um array de ações e executamos cada ação no callback window.WindVane.onSuccess (ou seja, após a conclusão da ação anterior).
Vídeo que demonstra como o conteúdo da área de transferência pode ser exposto quando o exploit é distribuído por meio de um anúncio malicioso.

Código-fonte do exploit em JavaScript
Já vimos como o SDK da Mintegral permite a execução remota de código nativo por meio de código JavaScript. No entanto, esse código JavaScript é totalmente controlado pela Mintegral. Mas, curiosamente, é possível fazer o mesmo por meio de anúncios interativos criados pelos próprios anunciantes. Os anúncios são páginas da web baseadas em JavaScript.
Em teoria, um anunciante pode direcionar com precisão um grupo específico de usuários ou determinados dispositivos, exibindo um anúncio malicioso que contém o exploit em JavaScript.
Conclusão
Só podemos especular por que a Mintegral incluiu no SDK a capacidade de invocar métodos nativos remotamente, mas, pelos nomes das classes, como MTGCommandDispatcher e MTGRemoteCommand, acreditamos que isso foi intencional. Além disso, a Mintegral removeu o código logo após nossa publicação, embora não soubéssemos disso na época.
Rastreamento de downloads no Android [outubro de 2020]
Visão geral
Nas duas seções anteriores deste artigo de pesquisa, mostramos como a equipe de segurança da Snyk descobriu comportamentos maliciosos no SDK da Mintegral que podem ser explorados em dispositivos iOS, levando a fraude publicitária, vazamento de dados e execução remota de código (RCE). Queríamos investigar mais a distribuição do SDK para Android, tema desta seção.
Em resumo, estas são nossas principais descobertas:
Rastreamento de URIs de download do Google, afetando downloads feitos pelo navegador e por aplicativos, incluindo downloads de arquivos comuns, anexos de e-mail e links do Google Docs.
Rastreamento de todos os downloads de APK, orgânicos ou não.
Esses dados são enviados aos servidores da Mintegral.
Comportamento observado
Ao baixar um link do Google Docs, observamos que o aplicativo enviava as seguintes solicitações para https://n.systemlog.me:

Este é o mesmo endpoint usado no SDK para iOS para enviar dados ao servidor da Mintegral. O payload é codificado, mas podemos usar a lógica de decodificação presente no binário do SDK para obter o seguinte:
Há dois parâmetros codificados adicionais, clever e dvi. Depois de decodificá-los também, notamos algo interessante:
Como podemos ver, a URL da planilha do Google que baixamos pelo aplicativo Google Drive é enviada ao backend no campo ul, e o nome do arquivo baixado, no campo kw, enquanto dvi contém dados sobre o dispositivo.
Possíveis usos
No cenário do iOS, cliques duplicados fraudulentos eram enviados do dispositivo do cliente aos servidores da Mintegral e, depois, ao provedor de atribuição (MMP). Neste caso, os APKs baixados ou instalados são enviados aos servidores e podem ser usados para gerar cliques no servidor. O diagrama a seguir mostra o fluxo de dados:

Módulo Alphab
O comportamento mencionado acima está no módulo alphab, descrito pela Mintegral como um “pacote de otimização”:

Após nossa publicação, o módulo foi removido do site da Mintegral e parece não fazer mais parte do SDK distribuído. Descompilamos o SDK e localizamos o código responsável por esse comportamento.
Classe AlphaCommonConst
Essa classe contém muitas definições de constantes codificadas diretamente no código. Algumas strings são ofuscadas com um esquema próprio de codificação baseado em Base64, localizado na classe AlphabBase64Util, semelhante ao que observamos na distribuição para iOS.
Após a decodificação, obtemos as seguintes strings:
Elas são usadas nas etapas de inicialização que veremos a seguir.
Receiver Alphab
No método init() da classe AlphabReceiver, o BroadcastReceiver é inicializado com algumas das strings anteriormente ofuscadas:
substituindo-as pelas strings decodificadas, o código fica assim:
Podemos ver que, usando a API de reflexão do Java, um novo receiver de broadcast é criado para escutar dois tipos de intents:
android.intent.action.PACKAGE_ADDED- uma intent do sistema que é acionada quando um pacote é instalado no dispositivo.alphab_net_debug_action- uma intent personalizada que parece detectar depuração de rede.
Ao receber a intent, a classe AlphabReceiver cria um método ParseAndLoad():
Esse campo é usado mais adiante em uma condição:
Ao descompilar os outros dois métodos dessa cláusula if, descobrimos que eles verificam se a conexão de rede atual passa por um proxy Wi-Fi ou por um cliente VPN. Isso serve para impedir a depuração do aplicativo e a captura do tráfego. Essa intent permite que os desenvolvedores do SDK contornem essa funcionalidade antidepuração.
Observer Alphab
De maneira semelhante, o bloco de inicialização deste ContentObserver também fica oculto por meio de reflexão e strings ofuscadas:
Após organizar o código, temos o seguinte:
Isso significa que o observer de conteúdo é registrado para escutar o URI content://downloads e é acionado sempre que um arquivo é baixado para o dispositivo.
Ele consulta o gerenciador de downloads do Android em busca de downloads públicos:
e, ao decodificar a string, obtemos o seguinte:
Se a URL do download atender a qualquer uma das condições a seguir, será enviado um relatório para https://n.systemlog.met/stlog:
Termina em
apk- para downloads manuais.Aponta para um pacote pertencente a
com.android.vendingou contém google.com - permite identificar qualquer aplicativo do Google ou até mesmo URLs de navegadores que atendam à condição.
Abaixo está o trecho de código que envia a solicitação ao servidor https://n.systemlog.met/stlog.
que equivale a:
E aqui podemos ver os parâmetros observados na solicitação capturada no nosso exemplo:
p- nome do pacote baixado, ou seja, o aplicativov- versão do aplicativoul- URL do arquivo baixadokw- nome do arquivo baixadofl- tamanho do arquivo
Aplicativo de demonstração

Para demonstrar esse comportamento, criamos um aplicativo de demonstração que nos permitiu:
1. Ativar a opção de depuração de rede por meio de reflexão para contornar a lógica antidepuração
2. Baixar um arquivo de uma URL que contém google.com
3. Baixar um arquivo de uma URL que termina em apk
Capturamos as solicitações de saída usando um proxy HTTP. Depois de clicar em um dos botões de download, vemos uma solicitação sendo enviada ao endpoint do servidor:

Confira este vídeo que demonstra o comportamento de rastreamento:

Linha do tempo
Data | |
|---|---|
5 de agosto | A equipe de pesquisa da Snyk identifica que o SDK da Mintegral para iOS coleta dados em excesso e sequestra cliques |
17 de agosto | A Snyk comunica as descobertas à Apple de forma responsável |
24 de agosto | A Snyk publica as descobertas sobre o Sour Mint para iOS |
25 de agosto | A Mintegral publica um comunicado negando as alegações sobre o SDK |
3 de setembro | A IronSource anuncia a remoção da Mintegral de sua plataforma de mediação |
3 de setembro | A Mintegral lança a versão 6.5.0.0 do SDK para iOS, removendo o componente malicioso e oculto _CXX_CXX_OperationPKTask |
4 de setembro | A plataforma de mediação MoPub (Twitter) anuncia a descertificação da Mintegral |
4 de setembro | A Mintegral anuncia planos para tornar o SDK open source |
4 de setembro | A equipe de pesquisa da Snyk identifica uma funcionalidade oculta de rastreamento de downloads na versão do SDK para Android |
9 de setembro | A Snyk comunica as descobertas sobre o SDK para Android ao Google de forma responsável |
10 de setembro | A Mintegral lança a versão 6.6.0.0 do SDK para iOS, removendo o componente backdoor MTGRemoteCommandParser |
22 de setembro | A Snyk obtém o código-fonte da versão 6.6.0.0 do SDK para iOS e realiza uma análise de diferenças |
23 de setembro | A Snyk identifica que a Mintegral removeu do SDK para Android o módulo de rastreamento de downloads do Google |
30 de setembro | Por meio de uma análise de diferenças, a Snyk identifica um backdoor na versão do SDK para iOS que permite RCE |
2 de outubro | A Snyk comunica as novas descobertas sobre iOS à Apple de forma responsável |
3 de outubro | A Apple notifica os publishers afetados e solicita que removam o código que permite RCE |
15 de outubro | A Snyk publica as descobertas mais recentes sobre iOS e Android |



