Análisis de Flame parte II. La primera ejecución

Estándar

Hola a tod@s!

En el anterior artículo hablábamos de cómo NO habíamos podido ejecutar la muestra de Flame debido a algún problema técnico. La pregunta que terminé haciéndome era que por qué otros sí habían conseguido ejecutarla y yo no. Tocaba tirar de recursos!

En toda la documentación que he leído, se comenta acerca de los diferentes cifrados que utiliza Flame. Debido a que mis nociones de ingeniería inversa y reversing de Malware son bastante pobres, opté por analizar la información que se encontraba en el momento de la ejecución de Flame. Así que recurrí a la vía forense, y realicé un volcado de memoria segundos después de la carga de Flame a través de rundll32.

Como no quería errar en el intento, provoqué un BSOD en la máquina, a través de la herramienta de SysInternals NotMyFault.

El porqué de utilizar esta herramienta, y no otra, es debido a que quería “simular”, en la medida de lo posible, un error a través de un controlador, y no realizar una petición de volcado directamente desde alguna herramienta forense. Con esta acción, lo que intento es pasar desapercibido ante controles internos monitorizados por el Malware.

Una vez extraído el volcado de memoria, utilicé la archiconocida Volatility, para extraer el contenido de la memoria del proceso RUNDLL32, y rezar para ver algún contenido que me hiciese comprender el porqué de mi error.

Analizando el espacio de memoria utilizado por RUNDLL32, se hizo la luz…..

Parece ser, que en el código de Flame se encuentra una lista de aplicaciones consideradas “peligrosas” para el Malware. Si alguna de estas aplicaciones se encuentra en ejecución en el sistema, éste automáticamente se para.

Este control, parece que se establece a través de varias órdenes. Una de ellas se puede visualizar a través de la siguiente imagen:

Imagen 1.- Código malicioso

Existen otras clases muy interesantes. Algunas de ellas son las siguientes:

  • LUA.CLAN.THREATENING_PROGRAMS
  • HEADACHE.BoostConsumer
  • GADGET.BEETLEJUICE_DATA_COLLECTOR_CONSUMER

La lista de aplicaciones es importante. Como podéis ver en la imagen siguiente, se encuentran numerosas aplicaciones conocidas por analistas y administradores de sistemas.

Imagen 2.- Algunas aplicaciones listadas por Flame

Como curiosidad, en una de las listas aparecen algunas soluciones de Antimalware. Imagino que Flame hace uso de estas rutinas para poder explotar mejor algunas de las vías de infección que utiliza.

Imagen 3.- Soluciones Antimalware listadas por Flame

Qué fallaba al intentar analizar la muestra?. Fallaba en uno de los trucos más viejos utilizado por el Malware, ya que yo tenía corriendo en la máquina Wireshark para capturar paquetes, y Process Monitor (procmon.exe) para monitorizar llamadas de sistema. Todo ello arrancado y esperando a la ejecución de Flame. FAIL!

Por otra parte, si se detecta algo “extraño”, Flame tiene opciones de auto destrucción. Según los analistas, esta clase es ejecutada de forma remota, y se concentra todo en una función llamada SUICIDE, la cual parece que está destinada a parar las acciones del Malware, así como a destruir posibles evidencias futuras.

Imagen 4.- Código SUICIDE

Una vez revisada de nuevo toda la información, me dispuse a renombrar toda aplicación que tuviese en la máquina para monitorizar la muestra, y así sí…. Flame inicia el vuelo sin importarle el idioma ni el sistema operativo.

Una vez arrancado, éste comprueba si existe el directorio MSSecurityMgr, situado en el directorio Program Files\Common Files. Si no existe, crea este directorio.

Imagen 5.- Creación del directorio Shared

Una vez creado el directorio, genera una serie de ficheros, los cuales se muestran en la siguiente imagen:

Imagen 6.- Ficheros generados por Flame

Para poder ver con mayor claridad quien se encuentra tocando estos ficheros, he utilizado la herramienta de Sysinternals Process Explorer, buscando las referencias (handle) al mismo. Para este paso, también se podría haber utilizado la herramienta, también de Sysinternals, Handle.

Imagen 7.- Proceso services.exe con handle a mscrypt.dat

Una vez generado el directorio y los ficheros, se empiezan a generar consultas al árbol de registro HKLM, en concreto a la siguiente clave:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SeCEdit

Después de realizar varias consultas, carga bibliotecas específicas relacionadas con la configuración de seguridad del sistema, tales como NTMARTA.DLL y SAMLIB.DLL, y modifica las claves de registro DefaultIdentifier y LastUsedIdentifier.

Imagen 8.- Modificación de la configuración de seguridad

A los pocos minutos de la ejecución, y viendo la cantidad de información que va «depositando» el bicho, intento identificar algunos ficheros generados por Flame, utilizando para ello la herramienta de Sysinternals sigcheck. Un extracto de la salida se puede ver en la siguiente imagen:

Imagen 9.- Verificación de firma con Sigcheck

Durante todo el tiempo que se estuvo ejecutando Flame, éste generó multitud de ficheros temporales en el directorio TEMP del sistema (C:\Windows). Estos ficheros, en un principio, no se encuentran manejados por ningún proceso en particular, y sólo se utilizan en un instante determinado.

Imagen 10.- Creación de ficheros temporales utilizados por Flame

Según el documento inicial de análisis de Flame, uno de los ficheros temporales, concretamente el fichero ~HLV473.tmp, contiene una lista de los procesos que se encuentran en ejecución. En el documento, se muestran secuencias de datos que hacen alusión a un formato de compresión llamado ZLIB.

Analizando este fichero, efectivamente se encuentran este tipo de secuencia de datos, por lo que me pongo a jugar con la biblioteca ZLIB de Python.

A la hora de generar un fichero con ZLIB en python, es posible indicar el grado de compresión con un valor numérico que va desde el 0 al 9. Generando un fichero con el valor 9 (Compresión máxima), las secuencias de datos que se muestran en el nuevo fichero, coinciden con las del fichero ~HLV473.tmp.

Aplicando un sencillo script en Python (En batch no he podido! :P), es posible «ver» ciertos datos almacenados en este fichero.

Imagen 11.- Extracción de información comprimida en ZLIB

La forma de implementarlo ha sido bastante sencilla. Para extraer todas las secuencias de datos que coincidan con ZLIB y los métodos de compresión (Mínimo al Máximo) he implementado un FOR del 0 al 9 y generado 10 ficheros. Una vez realizado este paso, he extraído la secuencia inicial (Magic), y he implementado un cutre-script para poder leerlo. El cutre código, aquí:

#-------------------------------------------------------------------------------
# Name:        Flame Zlib
# Purpose:
#
# Author:      Silverhack
#
# Created:     11/06/2012
# Blog:   https://windowstips.wordpress.com
# Reference: www.crysys.hu/skywiper/skywiper.pdf
#-------------------------------------------------------------------------------
import zlib
import sys
from optparse import OptionParser
from optparse import OptionGroup

magic = ["\x78\x01","\x78\x5e","\x78\xda","\x78\x9c"]
offset = 0

def flame(fich):
    try:
        fread = open(fich,'rb').read()
        for i in reversed(magic):
            try:
                init_offset = offset
                while 1:
                    init_offset+=fread[init_offset:].index(i)

                    if init_offset >=0:
                        try:
                            print zlib.decompress(fread[init_offset:])
                            break
                        except:
                            init_offset+=1
            except:
                pass

    except IOError:
        print "No such file or directory...."
        sys.exit()

def main():
    #set up command-line options
    parser = OptionParser(description="Flame Zlib file read | https://windowstips.wordpress.com", version="FlameZlibRead 0.1")
    StandardExtractGroup = OptionGroup(parser, "Read Section", "Read files and search common ZLIB payloads")
    StandardExtractGroup.add_option("-f","--file",default=False,help="File name to perform search", action="store_true",dest="filename")
    parser.add_option_group(StandardExtractGroup)
    #grab options
    (options, args) = parser.parse_args()
    if options.filename:
        fflame =  args[0]
        flame(fflame)

if __name__ == '__main__':
    main()

Hasta la próxima!
Referencias

http://msdn.microsoft.com/en-us/library/bb499271(v=winembedded.51).aspx