Reconstruir las macros y capas de codificación del documento sin activar su contenido.
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.
Prepara el análisis con el agente
Comparte esta lección y sus evidencias con tu agente. Pídele que te ayude a organizar la lectura y que justifique cada conclusión con una observación concreta.
Estoy estudiando «Emotet: análisis de un documento malicioso» del curso de Lobera. Ayúdame a interpretar las funciones, estructuras y capturas de esta lección. Distingue las observaciones del caso de las hipótesis y cita la evidencia que sostiene cada conclusión.
El análisis se apoya en las evidencias disponibles para este caso. Preparación y funcionamiento.
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.

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.

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

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

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

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.

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:
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:
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.
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:
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:
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.
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:
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:
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:
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.
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.
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 recuperado | Función en el comando analizado |
|---|---|
| Ruta temporal y nombre de archivo | Preparan el destino local de la etapa descargada. |
| Lista de direcciones | Proporciona varios orígenes que el código recorre. |
| Cliente de descarga | Solicita el archivo y lo guarda en el destino. |
| Creación de proceso | Intenta 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.
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.