A finales de abril, Microsoft anunció que se había encontrado una vulnerabilidad en Word que estaba siendo aprovechada en forma activa. Tenía lugar durante el análisis de archivos RTF y se identificó como CVE-2014-1761; su estudio detallado se puede encontrar en el blog HP Security Research. Desde entonces, fuimos encontrando varios casos donde se usa este exploit para distribuir malware, y uno de ellos es particularmente interesante porque contiene una nueva variante de MiniDuke (también conocido como Win32/SandyEva).

MiniDuke se discutió por primera vez en marzo de 2013 en el artículo de Kaspersky The MiniDuke Mystery: PDF 0-day Government Spy Assembler 0x29A Micro Backdoor y poco después en un artículo publicado por Bitdefender. Algunas de las características de MiniDuke, como su tamaño pequeño (20 KB), el uso inteligente de programación con lenguaje ensamblador y el uso de exploits 0-day para la distribución, lo convirtieron en una amenaza enigmática.

A pesar de que el backdoor aún sigue siendo bastante similar a sus versiones anteriores, se hicieron algunos cambios importantes desde el año pasado, el más notable de los cuales fue la introducción de un componente secundario escrito en JScript para contactar un Centro de Comando y Control (C&C) a través de Twitter.

El documento con el exploit se llamó Proposal-Cover-Sheet-English.rtf y es bastante insípido al compararlo con los documentos utilizados en 2013, de naturaleza política. Lo recibimos el 8 de abril, tan solo tres días después de la compilación de la carga de MiniDuke, que lleva fecha 5 de abril en el encabezado PE. La carga sigue siendo bastante pequeña, con tan solo 24 KB. A continuación podemos ver el documento:

documento-exploit
La funcionalidad del código de Shell que se ejecuta al accionar la vulnerabilidad es un tanto simple y directa. Luego de descifrarse a sí mismo y de obtener las direcciones de algunas funciones exportadas por kernel32.dll, se descifra y coloca la carga en el directorio %TEMP% en un archivo llamado “a.l”, que subsecuentemente se carga cuando llama a  kernel32!LoadLibraryA.

Un dato interesante sobre el código de shell es que, antes de transferir el control a cualquier función de la API, verifica los primeros bytes de la función para detectar posibles anclajes y puntos de interrupción del depurador, que pueden haber sido configurados por programas de software de seguridad y herramientas de monitoreo. En caso de encontrarlos, el código de shell saltea los primeros 5 bytes de la función que se está llamando; para ello, ejecuta manualmente las instrucciones de prólogo (mov edi, edi; push ebp; mov ebp, esp) y luego salta al código de la función, como se ilustra debajo.

codigo-funcion
Como se mencionó anteriormente, esta versión de la carga de MiniDuke incluye dos módulos, a los que nos referimos como el módulo principal y el módulo TwitterJS. El siguiente gráfico presenta el flujo de la ejecución de este malware cuando la infección se realiza con éxito:

ejeucion-miniduke

Componente principal

Instalación

Una vez que MiniDuke obtiene el control, verifica que el proceso del host no sea rundll32.exe y si el directorio actual es %TEMP%. Si se cumple cualquiera de esas dos condiciones, el malware asume que se está ejecutando por primera vez y procede con su instalación en el sistema. MiniDuke recopila información sobre el sistema y cifra su configuración basándose en dicha información, un método también utilizado por OSX/Flashback (Bitdefender llama a este proceso marca de agua). El resultado final es que es imposible recuperar la configuración de una carga cifrada si se analiza en un equipo distinto.

La información recopilada sobre la infección no varió desde la versión anterior y está conformada por los siguientes valores:

  • número de serie del volumen (obtenido de kernel32!GetVolumeInformationA)
  • información sobre la CPU (obtenida con cpuidinstruction)
  • nombre del equipo (obtenido de kernel32!GetComputerNameA)

Una vez creada la versión cifrada del malware, se escribe en un archivo en el directorio %ALLUSERSPROFILE%\Application Data. El nombre del archivo se elige en forma aleatoria de entre los siguientes valores (se puede encontrar este listado y los de las siguientes capturas de pantalla en la descripción de VirusRadar):

virus-radar-1
La extensión del nombre del archivo también se escoge aleatoriamente desde la siguiente lista:

virus-radar-2
Para tener persistencia en el sistema infectado tras los reinicios del sistema, el malware crea un archivo .LNK oculto en el directorio “Startup” asociado al módulo principal modificado. El nombre del archivo .LNK se extrae en forma aleatoria de los siguientes valores:

virus-radar-3
Para crear el archivo .LNK, se usa un objeto COM con la interfaz IShellLinkA que contiene el siguiente comando: “C:\Windows\system32\rundll32.exe %path_to_main_module%export_function” que da algo como:C:\Windows\system32\rundll32.exe C:\DOCUME~1\ALLUSE~1\APPLIC~1\data.cat, IlqUenn.

Funcionamiento

Cuando rundll32.exe carga el malware y el directorio actual no es %TEMP%, el malware comienza a recopilar la misma información del sistema descrita en la sección "Instalación” para descifrar los datos de configuración. Al igual que en las versiones anteriores de MiniDuke, verifica la presencia de los siguientes procesos en el sistema:

virus-radar-4
Si encuentra alguno de estos procesos en el sistema, la información de la configuración se descifra incorrectamente; en otras palabras, el malware se ejecutará en el sistema sin ninguna comunicación con los servidores de Comando y Control. Si los datos de configuración se descifran en forma correcta, MiniDuke recupera la página de Twitter de @FloydLSchwartz en busca de direcciones URL desde las que pueda establecer una conexión con el servidor de Comando y Control. Busca la etiqueta “X)))” en la página (en muestras anteriores, MiniDuke buscaba “uri!”) y, si la encuentra, descifra una URL desde los datos que la siguen. La cuenta de Twitter @FloydLSchwartz existe, pero solo tiene retweets y no cadenas de texto con la etiqueta especial. La siguiente es una captura de dicha cuenta:

tweet-floydschwartz
Como paso siguiente, MiniDuke recopila la siguiente información desde los sistemas infectados:

  • Nombre del equipo y nombre de dominio del usuario
  • Código del país de la dirección IP del host infectado, obtenido desde http://www.geoiptool.com
  • Información de la versión del sistema operativo
  • Nombre del controlador de dominio, nombre del usuario, grupos a los que pertenece el usuario
  • Una lista de los productos antivirus instalados en el sistema
  • Configuración del proxy de Internet
  • Versión de MiniDuke

La información luego se envía al servidor de Comando y Control junto con la solicitud para descargar una carga. La URL final utilizada para comunicarse con el servidor se ve así:  <url_start>/create.php?<rnd_param>=<system_info>

Los tokens se derivan de la siguiente forma:

  • url_start: la URL recuperada desde la cuenta de Twitter
  • rnd_param: nombre de parámetro generado aleatoriamente con caracteres alfabéticos en minúsculas, en la cadena de texto de búsqueda de la URL
  • system_info: información del sistema codificada y cifrada en base64

Abajo se muestra un ejemplo de una URL de este tipo:

url
La carga se descarga en el archivo llamado “fdbywu” mediante el uso la API urlmon!URLDownloadToFileA:

api
La carga descargada es un archivo GIF8 falso que contiene el ejecutable cifrado. El malware procesa el archivo descargado de la misma manera que las muestras anteriores de MiniDuke: verifica la integridad del archivo utilizando RSA-2048, luego lo descifra, lo almacena en un archivo y finalmente lo ejecuta. La clave pública RSA-2048 para verificar la integridad del ejecutable dentro del archivo GIF es la misma que en la versión anterior de MiniDuke.

Algoritmo de generación para Twitter

En caso de que MiniDuke sea incapaz de recuperar una URL de Comando y Control desde esta cuenta, genera un nombre de usuario para la búsqueda basándose en la fecha actual. La consulta de búsqueda cambia a grandes rasgos cada siete días y es similar al mecanismo de creación de copias de seguridad de las versiones anteriores, que utilizaba búsquedas de Google.

Componente TwitterJS

El módulo TwitterJS se extrae mediante la creación de una copia del archivo DLL cryptdll.dll de Windows; para ello, se le inyecta un bloque de código y se redirigen las funciones exportadas a este código. A continuación se muestra cómo queda la tabla de direcciones para exportar de los archivos binarios revisados, después de las modificaciones:

twitter.js
En el paso siguiente, se almacena este archivo en las Secuencias de datos alternativas (ADS, por sus siglas en inglés) en NTUSER.DAT en la carpeta %USERPROFILE%. Finalmente, este archivo DLL se registra como comando Open cuando se abre una unidad, lo que tiene el efecto de iniciar el bot cada vez que el usuario abre una unidad de disco. Abajo se puede encontrar el contenido del script init.cmd utilizado por MiniDuke para instalar el módulo TwitterJS en el sistema:script-minidukeCuando se carga, TwitterJS crea una instancia del objeto JScript COM y descifra un archivo de JScript que contiene la lógica principal del módulo. Veamos la siguiente captura:

jscript
Antes de ejecutarlo, MiniDuke aplica una codificación ligera al script. Las siguientes imágenes muestran el resultado de dos ofuscaciones separadas, donde se puede ver que las variables tienen distintos valores. Esto probablemente sea para evadir los sistemas de seguridad que exploran los puntos de entrada del motor de JScript.

ofuscacion-1

ofuscacion-2
El propósito de este script es utilizar Twitter para encontrar un servidor de Comando y Control y recuperar el código de JScript para ejecutar. En primer lugar genera un usuario de Twitter para la búsqueda; el término de la búsqueda cambia cada 7 días y en realidad coincide con el nombre de la cuenta real, no con el nombre de la cuenta de Twitter. Luego, el bot visita los perfiles de Twitter arrojados por la búsqueda y busca vínculos que terminen en ".xhtml".

Cuando encuentra uno, remplaza “.xhtml” por “.php” y recupera ese vínculo.  La información sobre el equipo se encuentra integrada en el encabezado de HTTP Accept:

http-accept
El primer vínculo de la página recuperada debería contener datos codificados en base64; el atributo del vínculo se usa como clave XOR móvil para descifrar el código de JScript. Finalmente, MiniDuke calcula un hash del script recuperado y lo compara con un hash codificado en forma rígida del script de TwitterJS. Si coinciden, el script recuperado se ejecuta cuando llama a eval():

hash
Algoritmo SHA-1 roto

El algoritmo hash del código usado por el componente se asemeja mucho a SHA-1, pero tiene como salida distintos resultados de hash. Decidimos buscar lo que se había modificado en el algoritmo, ya que una de nuestras hipótesis de trabajo era que el algoritmo se había alterado para que las colisiones fueran posibles. No pudimos encontrar una diferencia evidente: todas las constantes y los pasos del algoritmo eran los esperados.

Luego notamos que, en los mensajes cortos, solo la segunda palabra de 32 bits era diferente al compararla al SHA-1 original.

SHA1(‘test’) : a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
TwitterJS_SHA1(‘test’) : a94a8fe5dce4f01c1c4c0873d391e987982fbbd3

Al analizar cómo se generaba esta segunda palabra, finalmente descubrimos que era causada por un problema de alcance. Como se muestra abajo, la función SHA-1 usaba una variable llamada f: luego se llama la función Z(), donde también se usa una variable llamada sin la palabra clave var, lo que provoca que se trate como si fuera una variable global en lugar de una variable local de la función. El resultado final es que el valor de f también se cambia en la función SHA-1, lo que afecta el valor de la segunda palabra en esa ronda y termina afectando al hash completo en los mensajes extensos:

hash-2Una explicación probable de cómo surgió este problema es que los nombres de la variable se cambiaron a una sola letra mediante una herramienta automatizada antes de insertarse en la carga. Las 2 variables f probablemente hayan tenido nombres distintos en el script original, de modo que seguramente no causaba problemas. Por lo tanto, esto nos deja dos conclusiones:

  1. La diferencia en el algoritmo hash no fue intencional
  2. Siempre hay que declarar las variables locales con la valabra clave var

Algoritmo de generación de dominios para cuentas de Twitter

Generamos la lista de términos de búsqueda en Twitter de 2013-2014 y verificamos si alguno de ellos estaba registrado. En este momento solo existe uno, @AA2ADcAOAA, que es la cuenta de TwitterJS generada entre el 21 y el 27 de agosto de 2013. Esta cuenta no tiene ningún tweet.

En un esfuerzo por descubrir víctimas potenciales, registramos las cuentas de Twitter correspondientes a la semana actual tanto para el componente principal como para el componente TwitterJS y puso tweets con direcciones URL cifradas para que los equipos infectados pudieran conectarse con nuestro servidor. Hasta ahora recibimos conexiones a través de las cuentas de TwitterJS desde cuatro equipos ubicados en Bélgica, Francia y Reino Unido. Nos pusimos en contacto con los CERT nacionales para notificar a las partes afectadas. Nosotros detectamos el documento RTF con el exploit como Win32/Exploit.CVE-2014-1761.D y los componentes de MiniDuke como Win32/SandyEva.G.