Triggers de MySQL maliciosos: la puerta trasera dentro de tu base de datos
Un trigger MySQL malicioso recrea usuarios admin y contenido spam sin tocar archivos PHP. Explicamos cómo funciona esta puerta trasera y cómo detectarla y eliminarla.

Uno de los escenarios más frustrantes de un incidente es este: el equipo revisa hasta el último archivo PHP, reinstala el CMS, cambia contraseñas… y a los pocos días vuelve a aparecer un usuario administrador que nadie creó. Cuando eso pasa, el problema casi nunca está en los archivos: está en la base de datos. Un trigger MySQL malicioso es una de las formas de persistencia más limpias y difíciles de detectar, porque no deja rastro en el sistema de ficheros. Este artículo profundiza en un mecanismo que documentamos dentro de nuestra investigación pilar Anatomía del hackeo: persistencia, backdoors y SEO-spam.
Anatomía de un trigger MySQL malicioso
Un trigger es una funcionalidad legítima de MySQL: un bloque de código que se ejecuta automáticamente cuando ocurre un evento sobre una tabla, como un INSERT, un UPDATE o un DELETE. Los desarrolladores los usan para auditoría, integridad referencial o cálculos derivados. El atacante toma ese mismo mecanismo y lo convierte en una puerta trasera que se dispara sola.
Un patrón habitual funciona así: se crea un trigger asociado a la tabla de opciones o de usuarios de WordPress (wp_options, wp_users, wp_usermeta) que, cada vez que se produce cierta actividad normal del sitio, vuelve a insertar un usuario administrador o restablece una opción que reactiva la inyección. El resultado es demoledor para el defensor:
- Borras el usuario admin fraudulento; la siguiente visita normal lo recrea.
- Restauras una opción manipulada; el trigger la vuelve a corromper.
- Escaneas archivos con cualquier plugin de seguridad y sale limpio, porque el código no vive en un archivo.
Esta técnica es primo hermano de la creación de cuentas ocultas que analizamos en Phantom Admin: el objetivo es el mismo (recuperar privilegios de administrador), pero el escondite es la propia base de datos.
Por qué es tan difícil de detectar
La mayoría de herramientas de seguridad para WordPress se centran en el sistema de ficheros: comparan hashes de core, buscan patrones de ofuscación en PHP o revisan permisos. Un trigger no aparece en ninguno de esos escaneos porque es un objeto de la base de datos, no un archivo. Para verlo hay que ir a mirarlo específicamente. En la práctica, esto significa que la persistencia sobrevive a:
- Reinstalaciones del core de WordPress.
- Sustitución completa de temas y plugins.
- Restauraciones parciales que solo tocan archivos y no la base de datos.
Un trigger malicioso encaja conceptualmente en la familia de componentes de servidor persistentes que MITRE cataloga en MITRE ATT&CK T1505.003: mecanismos que aprovechan funcionalidad legítima del software de servidor para garantizar la reentrada. Y, como ese acceso se suele monetizar mediante inyección de spam, acaba chocando de frente con las políticas de spam de Google.
Cómo encontrar un trigger sospechoso
La revisión no es complicada si se sabe dónde mirar. El primer paso es enumerar todos los triggers de la base de datos. En un entorno donde tengas acceso a MySQL, una consulta directa sobre el catálogo de información revela cada trigger, la tabla a la que está asociado y el código que ejecuta:
- Listar todos los triggers definidos y revisar su cuerpo (
SHOW TRIGGERS;o una consulta ainformation_schema.triggers). - Desconfiar de cualquier trigger sobre
wp_users,wp_usermetauwp_optionsque contenga sentenciasINSERTcon datos de usuario, correos desconocidos o cadenas codificadas en base64. - Cruzar la fecha de creación del trigger con la línea temporal del incidente: si apareció el día del compromiso, es una señal fuerte.
Un exportado completo de la base de datos (con mysqldump incluyendo la opción de rutinas y triggers) permite auditar en frío todo lo que se ejecuta automáticamente. Investigadores como los de Sucuri han documentado repetidamente campañas que combinan triggers con otras puertas traseras precisamente porque la base de datos es el último sitio donde mira un administrador.
Eliminación y limpieza segura
Borrar un trigger malicioso es técnicamente sencillo (DROP TRIGGER), pero hacerlo bien exige método, porque casi nunca está solo:
- Haz una copia forense de la base de datos antes de tocar nada, para poder analizar la línea temporal después.
- Elimina el trigger y, en la misma sesión, revierte lo que ese trigger reintroducía: usuarios admin fantasma, opciones alteradas, entradas de spam.
- Busca compañía: un trigger suele convivir con web shells en el sistema de ficheros. Cierra también esa vía; nuestra guía sobre webshells explica dónde se esconden.
- Cierra el vector de entrada (credencial filtrada, plugin vulnerable) y rota todas las credenciales, incluida la del propio usuario de base de datos.
En entornos exigentes (banca, comercios que procesan datos de tarjeta), una puerta trasera en la base de datos es especialmente crítica: convive con datos sensibles y puede convertir un incidente de spam en un problema de exposición de datos y de cumplimiento. En esos casos tratamos el trigger como parte de una investigación completa, no como un borrado aislado. Si sospechas que tu base de datos se reinfecta sola, contáctanos desde nuestra página de contacto.
La lección de fondo
Si has limpiado una web «a fondo» y vuelve a caer, asume que la persistencia no está donde miraste. La base de datos es el punto ciego clásico, y un trigger MySQL malicioso es la razón por la que muchos incidentes se declaran cerrados cuando en realidad siguen abiertos. Auditar los triggers debería ser un paso obligatorio en cualquier limpieza que se tome en serio.
¿La web se reinfecta después de cada limpieza? La causa suele estar en la base de datos, no en los archivos. Deja que lo revisemos a fondo.
Cada semana, las vulnerabilidades de plugins de WordPress que de verdad importan y un caso real de investigación, en español. Sin ruido, sin spam.