Paper

De la falsa imagen al TDS: un año de plugins falsos (SMILODON) en 8 WordPress

13 plugins falsos con payload cifrado en falsas imágenes, un año sin ser detectados… y muertos sin saberlo. Anatomía de SMILODON: vector real (FTP + infostealer), el dinero y el techo honesto de la atribución. Con IoCs TLP:CLEAR.

Durante unos doce meses, 13 plugins falsos vivieron repartidos en 8 WordPress de dos cuentas de un hosting compartido que administro. El stack de seguridad comercial del servidor no los detectó. Los encontró un barrido manual, buscando otra cosa.

Este es el análisis completo: cómo se esconden, por qué el malware llevaba tiempo muerto sin que nadie lo supiera, por dónde entraron de verdad, a dónde iba el dinero y dónde se acaba —honestamente— la atribución.

Anatomía de un plugin que no existe

Cada plugin falso sigue la misma plantilla, generada en serie:

  • Nombre aleatorio consonante-vocal (amodoxoha) o genérico plausible (wpstatsapi, newslettergo, autoupdater).
  • Cabecera autogenerada: autor inventado («Hong Harlan», «Everette Jason»), versión 2.14.8, y una descripción de relleno raspada de Wikipedia — literalmente frases sobre «former coal, petroleum, and natural…».
  • El payload no es un .php: es una falsa imagen. Un .png o .gif que en realidad es una sola línea de texto ASCII con los magic bytes falsificados (PNGc…, GIFf…). Ningún visor la abre; ningún escáner de firmas la mira.
  • El cargador la incluye ofuscando la ruta por concatenación: include __DIR__."/ryni"."di.ph"."p"; — suficiente para esquivar detección estática simple.

La familia es SMILODON, documentada por Sucuri en 2022 y reidentificada en 2026: una familia de origen Magecart/skimmer que evolucionó al empaquetado fake-plugin. Emparentada con la oleada de plugins falsos que Wordfence documentó en más de 6.000 sitios. El payload de la familia (~50 KB) trae de todo: admin oculto autorreparable que se excluye de las consultas de usuarios, webshell, skimmer de tarjetas en checkout WooCommerce, C2 por cookie y exfiltración por correo cifrado.

El giro: el malware estaba muerto (y nadie lo sabía)

Aquí lo interesante. En 7 de los 8 sitios, los cargadores estaban a 0 bytes o destripados. Y eso importa por un detalle de diseño del propio malware:

El payload va cifrado con una sustitución de 65 caracteres cuya clave es única por instancia y vive en el cargador. Sin cargador, el payload es irrecuperable — lo intenté con ataque de texto conocido y hill-climbing (60.000 iteraciones): no converge. Pero por el mismo motivo, el propio malware tampoco podía ejecutarse: su include apuntaba a un fichero vacío, así que el payload nunca se descifraba. Estaba plantado, replicado… e inerte.

La verificación en vivo lo confirmó: sin admin oculto, sin C2, sin JS inyectado, sin exfiltración. Las cuatro vías de persistencia de esta familia (usuario oculto, trigger de BD, cron malicioso, wp-config) — ausentes en los 8 sitios tras la limpieza.

Una tienda WooCommerce real de la cartera tenía el único cargador vivo. ¿Riesgo de tarjetas? Bajo, y no por suerte: cobra por pasarelas de iframe y redirección al banco, así que el número de tarjeta nunca toca el DOM que un skimmer podría leer. Esa decisión de arquitectura —tomada mucho antes del incidente— fue la defensa real.

La puerta no fue un exploit: fue una llave robada

Ni CVE, ni SSH (sin logins ajenos, sin claves plantadas, root intacto). Lo que sí había en los logs: fuerza bruta activa contra FTP — un protocolo en texto plano, sin bloqueo de intentos ni segundo factor — desde infraestructura desechable, y el patrón clásico del pipeline infostealer: el equipo de un proveedor se infecta, el stealer se lleva el gestor FTP con sus contraseñas guardadas, los logs se venden en mercados, y quien los compra entra con un login limpio de un solo intento. Con la credencial de una cuenta, el kit se replica web a web dentro de esa cuenta.

La respuesta estructural: FTP desactivado en todo el servidor (SFTP se queda), rotación de credenciales y 2FA. Dos familias distintas de malware habían entrado ya por esa misma cerradura; no hay limpieza que aguante con la puerta abierta.

Los señuelos: cuando los IoC mienten

Los plugins declaran Author URI y Plugin URI en dos dominios. Investigados en pasivo:

  • Uno no está registrado. Nunca lo estuvo: sin RDAP, sin certificados, sin histórico. No resuelve ni resolvió.
  • El otro es una web legítima con casi 20 años, de un tercero absolutamente ajeno — víctima del nombre, nada más. El subdominio que usa el kit jamás existió.

Son metadatos decorativos que el generador inserta para dar verosimilitud. No son C2, no hay nada que sinkholear y no pivotan a nadie. Primera lección de atribución: en un kit generado en serie, el «dominio del autor» es atrezzo.

El dinero: tres cajas del mismo sitio

Con material de la familia y fuentes públicas, un WordPress comprometido así monetiza por tres vías a la vez:

  1. Reventa del acceso (initial access broker): una PYME WordPress cotiza en banda baja — según informes del sector de 2024, la gran mayoría de accesos se venden por debajo de los 3.000 $, y un dump de panel de hosting va a precio de granel.
  2. Skimming de tarjetas — lo propio de SMILODON como familia Magecart.
  3. Redirecciones a TDS y SEO parásito: según la investigación de GoDaddy (2024), el ecosistema VexTrio/LosPollos capta en torno al 40 % de todos los WordPress hackeados del mundo, y lo convierte en afiliación de casino y farmacia.

Que en el mismo servidor convivieran dos familias distintas de malware no es rareza: es que la misma llave robada tuvo varios inquilinos.

El techo honesto de la atribución

Con OSINT propio se llega a la infraestructura, no a la persona. La fuerza bruta salía de espacio IPv4 realquilado sin control de abuso; el acceso fino, de VPN comerciales de un clic. Todo desechable por diseño.

La única desanonimización nominal en este ecosistema que conozco —el caso VexTrio→Adspro, publicado por Qurium e Infoblox— no se logró analizando malware, sino siguiendo la capa del dinero y la adtech. Ese es el patrón: el nombre humano, si llega, llega por vía legal y fallos de OPSEC, no por un hash.

Y de ahí la conclusión operativa de este caso: no gastes el esfuerzo en cazar al operador; gástalo en quitarle el incentivo. Credencial rotada y con 2FA: el acceso ya no se revende. Pasarela por iframe/redirección: no hay tarjeta que robar. Vigilancia del índice de Google: no hay ranking que parasitar. El atacante no se va porque lo encuentres; se va porque tu sitio deja de darle de comer.

IoCs (TLP:CLEAR)

TipoValor
Nombres de plugin fakeamodoxoha, cleanpostformatter, multilingual-export-ultimate, customfieldsx, shareboost, gallerysliderlite, rssfeedparserlite, robot-key-max, wpstatsapi, newslettergo, autoupdater, commentsync, typography-core-fusion
Autores falsos«Hong Harlan», «Everette Jason»
Firma del payloadfichero .png/.gif que empieza por PNGc/GIFf + una sola línea ASCII larga
Cargadoresrynidi.php, tetyzhu.php, ogaduwi.txt, pyhozha.php, vipuke.php
Patrón de includeconcatenación de ruta: include __DIR__."/xx"."yy.ph"."p";
Detección (Imunify)SMW-SA-<num>-php.bkdr.b64
Infra de fuerza bruta156.224.0.0/11 y VPN comerciales (AS9009 M247, AS212238 Datacamp, AS44559, AS17561) — infra desechable, no el operador
⚠️ NO bloquearlos dominios de Author URI del kit: uno no existe y el otro es una web legítima ajena (señuelo)

Comprobación rápida si administras WordPress: busca en wp-content/plugins/ imágenes que no abren y empiezan por texto (head -c 16 de cada .png/.gif sospechoso), plugins que no recuerdas haber instalado con autores que no existen, e includes con rutas concatenadas. O pásalo por el escáner de PathSentinel.

Reglas listas para usar: las reglas YARA/Sigma, las queries SQL de hunting y los IoCs de este caso están publicados en github.com/PathSentinel/cms-detection-rules (TLP:CLEAR, licencia MIT).

Jesús Macías (PathSentinel). Investigación sobre un incidente real en infraestructura propia gestionada, con autorización. Más casos en Investigaciones. Un milímetro más.

Lecturas relacionadas: Web hackeada: guía de respuesta · comprueba gratis si tu web está comprometida · El iceberg de internet está al revés.