InfraFenceInfraFence

Live Security Operations

Empezar

Cómo detener un servidor que está enviando spam

Última actualización:

La primera señal rara vez es el spam en sí. Es un correo del proveedor por abuso, un cliente cuyas facturas acaban en la carpeta de spam, rebotes de mensajes que nunca enviaste o una cola de correo con diez mil mensajes. Para entonces la dirección del servidor suele estar ya en una lista negra, y todo el correo legítimo que sale de él lo sufre también.

El spam sale de un servidor de tres maneras: un buzón cuya contraseña se adivinó o se robó, un script PHP (un plugin hackeado o un formulario de contacto abusado) que llama a mail(), o un programa que habla SMTP directamente con otros servidores. Los pasos siguientes encuentran cuál es, lo detienen, limpian, cierran el agujero y sacan la dirección de las listas. Los comandos son para Postfix y Exim en Debian, Ubuntu y la familia RHEL; spammer@example.com, QUEUE_ID y 203.0.113.10 representan lo que encuentres.

Comprobar si el servidor envía spam

Empieza por la cola de correo. Un servidor sano tiene un puñado de mensajes esperando, a menudo ninguno. Miles de mensajes, o un remitente que acapara la mayoría, significa spam. El segundo comando lista los remitentes con más mensajes en cola.

Postfix
sudo postqueue -p | tail -n 1
sudo postqueue -p | awk '/^[0-9A-Za-z]/ {print $7}' | sort | uniq -c | sort -rn | head

Exim, como en cPanel y con el exim4 de Debian (el comando exim también existe), cuenta la cola con exim -bpc. Las líneas siguientes listan los principales remitentes y los principales dominios de destino:

Exim
sudo exim -bpc
sudo exim -bp | awk '/^ *[0-9]+[mhd] / {print $4}' | sort | uniq -c | sort -rn | head
sudo exim -bp | exiqsumm | sort -rn | head

Un remitente <> o MAILER-DAEMON es un rebote. Una cola llena de rebotes significa que el servidor aceptó o envió correo a direcciones que no existen: típico del spam enviado desde aquí, o del backscatter de un formulario que manda una copia a cualquier dirección que se escriba en él.

Qué cuenta está enviando

El spam enviado a través de un buzón aparece como un usuario autenticado con muchos más mensajes que los demás. Postfix lo registra como sasl_username, en los archivos de log o, sin rsyslog, en el journal:

Postfix
sudo sh -c "zgrep -h -o 'sasl_username=[^ ,]*' /var/log/mail.log* /var/log/maillog* 2>/dev/null" \
  | sort | uniq -c | sort -rn | head
sudo journalctl --since "24 hours ago" -t postfix/smtpd | grep -o 'sasl_username=[^ ,]*' \
  | sort | uniq -c | sort -rn | head

Exim registra el inicio de sesión como A= en cada mensaje que acepta, y la carpeta del script como cwd= para el correo enviado localmente (cPanel lo registra por defecto). Un cwd= dentro de un sitio web, como /home/user/public_html/wp-content/…, señala el script:

Exim
sudo grep -h ' <= ' /var/log/exim_mainlog /var/log/exim4/mainlog 2>/dev/null \
  | grep -o ' A=[^ ]*' | sort | uniq -c | sort -rn | head
sudo grep -h -o 'cwd=[^ ]*' /var/log/exim_mainlog /var/log/exim4/mainlog 2>/dev/null \
  | sort | uniq -c | sort -rn | head

Qué script PHP está enviando

El correo que envía la función mail() de PHP pasa por el sendmail local y no inicia sesión, así que no tiene usuario. Lee las cabeceras de un mensaje en cola: con mail.add_x_header activado, PHP añade X-PHP-Originating-Script, el ID de usuario y el nombre de archivo del script.

Postfix, luego Exim
sudo postcat -hq QUEUE_ID | grep -iE '^(From|To|Subject|X-PHP-Originating-Script):'
sudo exim -Mvh QUEUE_ID | grep -iE '(From|To|Subject|X-PHP-Originating-Script):'

Si la cabecera no está, actívala, y haz que PHP registre cada llamada a mail() con la ruta completa y la línea del script. Busca el php.ini que usa tu servidor web (PHP-FPM tiene el suyo propio en Debian y Ubuntu):

Cualquier distribución
php --ini | grep 'Loaded Configuration'
ls /etc/php/*/fpm/php.ini /etc/php.ini 2>/dev/null
php.ini
mail.add_x_header = On
mail.log = syslog

Reinicia PHP-FPM o el servidor web (sudo systemctl restart php8.3-fpm, php-fpm o httpd, según el sistema), espera unos minutos y lee el log:

Cualquier distribución
sudo journalctl --since "1 hour ago" | grep 'mail() on' | tail -n 20
sudo grep -h 'mail() on' /var/log/syslog /var/log/messages 2>/dev/null | tail -n 20

Programas que hablan SMTP directamente

Algunas herramientas de spam se saltan el servidor de correo y se conectan ellas mismas al puerto 25 de los servidores de los destinatarios, así que no dejan nada en la cola. Mira las conexiones SMTP salientes y los programas a los que pertenecen. Tu servidor de correo (master/smtp en Postfix, exim) es normal; php, perl, python o un nombre aleatorio no lo son.

Cualquier distribución
sudo ss -tnp state established '( dport = :25 or dport = :465 or dport = :587 )'
sudo ss -tnp state established '( dport = :25 )' | grep -o 'users:(("[^"]*"' | sort | uniq -c | sort -rn

Detener el spam ya

Detén primero el origen y luego la cola. Si es un buzón, cambia su contraseña en tu panel o en tu sistema de correo y cierra sus sesiones. Si es un script, guarda una copia como prueba y hazlo ilegible, para que el servidor web ya no pueda ejecutarlo:

Cualquier distribución
sudo mkdir -p /root/evidence
sudo cp -p /path/to/script.php /root/evidence/
sudo chmod 000 /path/to/script.php

Si es un proceso que habla SMTP directamente, busca su PID en la salida de ss anterior, comprueba de dónde viene y detenlo como en la guía del minero de criptomonedas: es malware, y tiene su propia persistencia.

Mientras limpias, evita que la cola salga. Con Postfix, defer_transports retiene todo lo destinado a entrega remota y sigue aceptando correo nuevo, así que no se pierde nada:

Postfix
sudo postconf -e 'defer_transports = smtp'
sudo postfix reload

Cuando la cola esté limpia (siguiente paso), libérala:

Postfix
sudo postconf -e 'defer_transports ='
sudo postfix reload
sudo postqueue -f

Con Exim, congela los mensajes del remitente que encontraste. Los mensajes congelados se quedan en la cola y no se entregan:

Exim
sudo exiqgrep -i -f 'spammer@example\.com' | xargs -r sudo exim -Mf

Atención: Mientras la entrega remota está en pausa, el correo legítimo también espera. No la dejes en pausa más de unas horas: pasada la vida máxima en cola (5 días por defecto en Postfix), los mensajes en espera rebotan.

Limpiar la cola de correo

Borra el spam por remitente, y los rebotes con él, para que los mensajes legítimos de la cola se queden. Repite antes el paso 1 para asegurarte de la dirección del remitente.

Postfix
sudo postqueue -p | awk '/^[0-9A-Za-z]/ && $7 == "spammer@example.com" {sub(/[*!]$/, "", $1); print $1}' \
  | sudo postsuper -d -
sudo postqueue -p | awk '/^[0-9A-Za-z]/ && $7 == "MAILER-DAEMON" {sub(/[*!]$/, "", $1); print $1}' \
  | sudo postsuper -d -

Con Exim, la primera línea borra los mensajes del remitente y la segunda los congelados, que tras un episodio de spam son sobre todo rebotes:

Exim
sudo exiqgrep -i -f 'spammer@example\.com' | xargs -r sudo exim -Mrm
sudo exiqgrep -z -i | xargs -r sudo exim -Mrm

Atención: postsuper -d ALL y vaciar toda la cola de Exim también borran mensajes legítimos, y los mensajes borrados no se pueden recuperar. Borra por remitente, salvo que la cola no contenga nada más.

Vuelve a contar la cola. Si crece otra vez, el origen sigue activo: vuelve al paso 1.

Averiguar cómo salió el spam

Cambiar una contraseña o borrar un script detiene esta ronda. La siguiente empieza si no sabes cómo comenzó.

Un buzón comprometido

Un buzón usado por un spammer inicia sesión desde muchas direcciones, a menudo de muchos países, a veces miles en un día. Cuenta las direcciones que lo usaron:

Postfix o Exim
sudo sh -c "zgrep -h 'user@example.com' /var/log/mail.log* /var/log/maillog* /var/log/exim_mainlog* /var/log/exim4/mainlog* 2>/dev/null" \
  | grep -oE '\[[0-9]{1,3}(\.[0-9]{1,3}){3}\]' | sort | uniq -c | sort -rn | head -20

La contraseña se adivinó (busca muchos inicios de sesión fallidos en ese buzón antes del primero correcto) o se robó del ordenador del usuario o de otro sitio. Elige una contraseña nueva y larga, y revisa todos los demás buzones que tengan una débil.

Un script PHP

Un script que envía lo que le pida una petición es o bien malware subido por un agujero, o bien un formulario legítimo sin protección. Busca mailers y archivos PHP modificados recientemente en los sitios:

Cualquier distribución
sudo grep -rlE 'mail\s*\(\s*\$_(POST|GET|REQUEST)|LeafMailer|eval\s*\(\s*base64_decode' \
  --include='*.php' /var/www /home 2>/dev/null | head -50
sudo find /var/www /home -name '*.php' -type f -mtime -7 2>/dev/null | head -50

Después mira quién llamó al script y con qué frecuencia. Un formulario de contacto enviado miles de veces por unas pocas direcciones está siendo abusado; un archivo que nadie debería conocer, llamado desde muchas direcciones, es una puerta trasera.

Logs del servidor web
sudo sh -c "grep -hI 'POST /path/to/script.php' /var/log/nginx/*access*.log /var/log/apache2/*access*.log /var/log/httpd/*access_log 2>/dev/null" \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head
  • Un script malicioso: elimínalo, luego averigua cómo se subió (un plugin o tema desactualizado, una contraseña de administrador débil, un formulario de subida) y ciérralo. La guía del minero de criptomonedas muestra cómo buscar el resto de lo que deja un atacante.
  • Un formulario abusado: añade un CAPTCHA o un campo oculto que rellenan los bots, no dejes nunca que el visitante elija el destinatario y no envíes una copia a la dirección escrita en el formulario.

Un relay abierto

Hoy es menos frecuente, pero compruébalo: un servidor de correo que entrega correo de cualquiera a cualquiera. En Postfix, mynetworks debe incluir solo el propio servidor y tus redes, y las restricciones de relay deben terminar con reject_unauth_destination:

Postfix
postconf mynetworks smtpd_relay_restrictions smtpd_recipient_restrictions

Evitar que vuelva a pasar

SPF, DKIM y DMARC

Estos tres registros DNS dicen a los demás servidores de correo qué servidores pueden enviar en nombre de tu dominio y si un mensaje viene realmente de ti. No impiden que un buzón hackeado envíe spam a través de tu servidor, pero impiden que otros falsifiquen tu dominio, y los grandes proveedores ya los exigen antes de entregar tu correo. Un ejemplo para un dominio cuyo correo sale desde 203.0.113.10:

Zona DNS
example.com.         TXT  "v=spf1 mx ip4:203.0.113.10 -all"
_dmarc.example.com.  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"

DKIM necesita una clave en el servidor de correo (OpenDKIM para Postfix, integrado en Exim; paneles como cPanel y Plesk lo hacen por ti) y su parte pública en el DNS. Comprueba lo que está publicado:

Cualquier distribución
dig +short TXT example.com
dig +short TXT _dmarc.example.com
dig +short TXT default._domainkey.example.com

Nota: dig está en el paquete dnsutils en Debian y Ubuntu (bind9-dnsutils en las versiones recientes) y en bind-utils en la familia RHEL. El selector DKIM, aquí default, depende de tu configuración.

Límites de envío

Un límite convierte una cuenta comprometida de cien mil mensajes en unos cientos. Postfix limita los mensajes por dirección de cliente; el correo que PHP envía mediante sendmail no pasa por ese límite, y los límites por usuario necesitan un servicio de políticas como postfwd.

Postfix
sudo postconf -e 'smtpd_client_message_rate_limit = 100' 'anvil_rate_time_unit = 3600s'
sudo postfix reload

Exim puede limitar a cada usuario autenticado en su ACL de RCPT. En cPanel, usa en su lugar **Max hourly emails per domain** en Tweak Settings de WHM.

Exim
# In the RCPT ACL (acl_check_rcpt), before the accept for authenticated users
deny  authenticated = *
      ratelimit     = 200 / 1h / strict / per_rcpt / $authenticated_id
      message       = Sending rate limit exceeded

Que solo el servidor de correo use el puerto 25

En un servidor web nada salvo el servidor de correo necesita conectarse al puerto 25 de otros servidores. Esta regla de nftables rechaza las conexiones salientes al puerto 25 de cualquier otro usuario, lo que detiene a los scripts y al malware que hablan SMTP directamente. Sustituye postfix por el usuario de tu servidor de correo: Debian-exim para Exim en Debian y Ubuntu, exim en la familia RHEL, mailnull en cPanel.

Cualquier distribución con nftables
sudo nft add table inet smtpguard
sudo nft 'add chain inet smtpguard out { type filter hook output priority 0; policy accept; }'
sudo nft add rule inet smtpguard out tcp dport 25 meta skuid != { root, postfix } reject

Atención: Asegúrate del nombre de usuario: con uno equivocado, el servidor deja de entregar todo el correo. Las aplicaciones que envían a través de un servidor SMTP externo en el puerto 25 también dejan de funcionar; de todos modos deberían usar el 587 con autenticación. La tabla desaparece al reiniciar: cuando funcione, añádela a la configuración de tu firewall. En cPanel, **SMTP Restrictions** en WHM hace lo mismo.

Muchos proveedores cloud bloquean el puerto 25 saliente por defecto y lo abren bajo petición. Si no envías correo desde el servidor, déjalo bloqueado y envía a través de un servicio de relay en el 587.

Y el refuerzo de siempre

  • Mantén WordPress, plugins y temas actualizados, y elimina los que no uses.
  • Protege los inicios de sesión del correo contra la fuerza bruta igual que SSH: consulta Cómo frenar los ataques de fuerza bruta SSH.
  • Deja activados mail.add_x_header y mail.log, para que la próxima vez sepas en segundos cuál es el script.

Sacar el servidor de las listas negras

Pide la exclusión solo cuando el spam se haya detenido y la causa esté cerrada: un servidor que vuelve a aparecer en la lista justo después de salir recibe un trato más duro la segunda vez. Comprueba las listas principales por DNS, con la dirección pública del servidor en IP:

Cualquier distribución
IP=203.0.113.10
REV=$(echo "$IP" | awk -F. '{print $4"."$3"."$2"."$1}')
for bl in zen.spamhaus.org bl.spamcop.net; do echo "$bl: $(dig +short "$REV.$bl" A)"; done
dig +short -x "$IP"

Una respuesta vacía significa que no está en la lista; una dirección como 127.0.0.2 significa que sí. Spamhaus rechaza las consultas enviadas a través de resolvers públicos y les responde 127.255.255.254: en ese caso usa su web. La última línea muestra el DNS inverso (PTR) de la dirección, que debería ser un nombre de host que resuelva de vuelta a ella.

  • Spamhaus: busca la dirección en check.spamhaus.org, que explica cada inclusión y cómo pedir la exclusión.
  • SpamCop: las inclusiones caducan solas cuando cesan las denuncias (spamcop.net).
  • Microsoft (Outlook, Hotmail): pide la exclusión en sender.office.com.
  • Gmail: no hay formulario de exclusión; Postmaster Tools muestra la reputación de tu dominio a medida que se recupera.

Nota: Procedimientos a noviembre de 2026, según las páginas de las propias listas. La recuperación lleva días, no horas: la reputación en los grandes proveedores solo mejora mientras sigues enviando correo limpio.

Qué hace InfraFence contra el spam de tu servidor

InfraFence actúa sobre las causas más que sobre el propio correo:

  • Fuerza bruta en el correo: el agente lee los logs de Postfix, Exim, Dovecot y Roundcube (o el journal de systemd) y banea una dirección tras 5 inicios de sesión fallidos o intentos de relay en 5 minutos, en SMTP, submission, IMAP, POP3 y webmail. Cada evento indica el buzón que se probó. Consulta SSH y fuerza bruta.
  • Scripts de envío: el escáner de malware tiene firmas para scripts PHP que envían lo que pida una petición (mail() alimentado directamente desde $_POST, LeafMailer), web shells y puertas traseras, reglas YARA, y señala los archivos PHP creados en carpetas de subida. Con los escaneos automáticos activados, los archivos PHP nuevos en carpetas de subida se escanean en menos de 30 segundos. Consulta Malware.
  • Amenazas salientes: las conexiones del servidor a direcciones de las listas Spamhaus DROP y Emerging Threats se notifican como críticas. Consulta Amenazas salientes y DNS.

Lo que no hace: InfraFence no lee la cola de correo, no cuenta ni limita el correo saliente, no bloquea el puerto 25 y no comprueba si tu dirección está en una lista negra. Un buzón usado con su contraseña correcta le parece un inicio de sesión normal. La cola, los límites y la exclusión de las listas de esta guía siguen siendo cosa tuya.

Preguntas

El servidor no tiene servidor de correo. ¿Cómo puede enviar spam?
La función mail() de PHP usa el sendmail que instala casi cualquier distribución, y el malware puede conectarse por su cuenta al puerto 25 de otros servidores. Revisa las conexiones salientes del paso 1 y la regla que reserva el puerto 25 al servidor de correo.
¿SPF, DKIM y DMARC detienen el spam?
No. Demuestran qué servidores pueden enviar en nombre de tu dominio, y el spam enviado a través de un buzón hackeado de tu servidor los supera. Protegen tu dominio de la falsificación y ayudan a que tu correo legítimo se entregue.
¿Cuánto se tarda en salir de una lista negra?
Depende de la lista. Las inclusiones de SpamCop caducan solas cuando cesan las denuncias; Spamhaus y Microsoft atienden una solicitud de exclusión una vez resuelto el problema. La reputación en Gmail y Outlook se recupera tras días de envíos limpios.

Pruébalo gratis en 1 servidor

Starter es gratuito para un servidor, con protección completa y bloqueo automático. Sin tarjeta de crédito.

Instala el agente como root, con tu token en lugar de <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

El token se crea en el panel, en Servidores › Añadir servidor.