InfraFenceInfraFence

Live Security Operations

Inizia

Come fermare un server che invia spam

Ultimo aggiornamento:

Il primo segnale raramente è lo spam in sé. È un'email di abuso dal provider, un cliente le cui fatture finiscono nella posta indesiderata, bounce di messaggi che non hai mai mandato, o una coda di posta con diecimila messaggi. A quel punto l'indirizzo del server di solito è già in una blocklist, e ne soffre anche ogni email legittima che parte da lì.

Lo spam esce da un server in tre modi: una casella di posta con la password indovinata o rubata, uno script PHP (un plugin bucato o un modulo di contatto abusato) che chiama mail(), o un programma che parla SMTP direttamente con altri server. I passi qui sotto trovano quale dei tre, lo fermano, ripuliscono, chiudono il buco e tolgono l'indirizzo dalle liste. I comandi sono per Postfix ed Exim su Debian, Ubuntu e la famiglia RHEL; spammer@example.com, QUEUE_ID e 203.0.113.10 stanno per quello che trovi.

Verificare se il server sta inviando spam

Parti dalla coda di posta. Un server sano ha pochi messaggi in attesa, spesso nessuno. Migliaia di messaggi, o un mittente che ne possiede la maggior parte, vuol dire spam. Il secondo comando elenca i mittenti con più messaggi in coda.

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

Exim, come su cPanel e con l'exim4 di Debian (c'è anche il comando exim), conta la coda con exim -bpc. Le righe successive elencano i mittenti principali e i domini di destinazione principali:

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 mittente <> o MAILER-DAEMON è un bounce. Una coda piena di bounce vuol dire che il server ha accettato o inviato posta verso indirizzi che non esistono: tipico dello spam inviato da qui, o del backscatter di un modulo che manda una copia a qualunque indirizzo venga digitato.

Quale account sta inviando

Lo spam inviato attraverso una casella compare come un utente autenticato con molti più messaggi degli altri. Postfix lo registra come sasl_username, nei file di log o, senza rsyslog, nel 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 il login come A= su ogni messaggio che accetta, e la cartella dello script come cwd= per la posta inviata in locale (cPanel la registra di default). Un cwd= dentro un sito, come /home/utente/public_html/wp-content/…, indica lo 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

Quale script PHP sta inviando

La posta inviata con mail() di PHP passa per il sendmail locale e non fa login, quindi non ha un utente. Leggi le intestazioni di un messaggio in coda: con mail.add_x_header attivo, PHP aggiunge X-PHP-Originating-Script, l'ID utente e il nome del file dello script.

Postfix, poi 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):'

Se l'intestazione non c'è, attivala, e fai registrare a PHP ogni chiamata a mail() con il percorso completo e la riga dello script. Trova il php.ini usato dal web server (PHP-FPM ha il suo su Debian e Ubuntu):

Qualsiasi distribuzione
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

Riavvia PHP-FPM o il web server (sudo systemctl restart php8.3-fpm, php-fpm o httpd, a seconda del sistema), aspetta qualche minuto e leggi il log:

Qualsiasi distribuzione
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

Programmi che parlano SMTP direttamente

Alcuni strumenti di spam saltano il server di posta e si collegano da soli alla porta 25 dei server dei destinatari, quindi non lasciano niente in coda. Guarda le connessioni SMTP in uscita e i programmi a cui appartengono. Il tuo server di posta (master/smtp per Postfix, exim) è normale; php, perl, python o un nome casuale no.

Qualsiasi distribuzione
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

Fermare subito lo spam

Ferma prima la fonte, poi la coda. Per una casella, cambiane la password nel pannello o nel sistema di posta e chiudi le sue sessioni. Per uno script, tienine una copia come prova e rendilo illeggibile, così il web server non può più eseguirlo:

Qualsiasi distribuzione
sudo mkdir -p /root/evidence
sudo cp -p /path/to/script.php /root/evidence/
sudo chmod 000 /path/to/script.php

Per un processo che parla SMTP direttamente, trova il suo PID nell'output di ss qui sopra, verifica da dove arriva e fermalo come nella guida sui crypto miner: è un malware, e ha una sua persistenza.

Mentre fai pulizia, impedisci alla coda di partire. Con Postfix, defer_transports trattiene tutto ciò che va consegnato all'esterno e continua ad accettare nuova posta, quindi non si perde niente:

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

Quando la coda è pulita (passo successivo), rilasciala:

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

Con Exim, congela i messaggi del mittente che hai trovato. I messaggi congelati restano in coda e non vengono consegnati:

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

Attenzione: Mentre la consegna esterna è in pausa, aspetta anche la posta legittima. Non lasciarla in pausa per più di qualche ora: superata la durata massima in coda (5 giorni di default in Postfix) i messaggi in attesa tornano indietro come bounce.

Pulire la coda di posta

Cancella lo spam per mittente, e i bounce insieme, così i messaggi legittimi in coda restano. Ripeti prima il passo 1, per essere sicuro dell'indirizzo del mittente.

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 prima riga cancella i messaggi del mittente, la seconda quelli congelati, che dopo uno spam sono per lo più bounce:

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

Attenzione: postsuper -d ALL e la cancellazione dell'intera coda di Exim eliminano anche i messaggi legittimi, e i messaggi cancellati non si recuperano. Cancella per mittente, a meno che la coda non contenga nient'altro.

Conta di nuovo la coda. Se torna a crescere, la fonte è ancora attiva: torna al passo 1.

Trovare da dove è uscito lo spam

Cambiare una password o cancellare uno script ferma questo giro. Il prossimo parte, a meno che tu non sappia come è cominciato.

Una casella compromessa

Una casella usata da uno spammer fa login da molti indirizzi, spesso da molti paesi, a volte migliaia in un giorno. Conta gli indirizzi che l'hanno usata:

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 password è stata indovinata (cerca molti login falliti su quella casella prima del primo riuscito) o rubata dal computer dell'utente o da un altro sito. Scegli una nuova password lunga, e controlla ogni altra casella con una password debole.

Uno script PHP

Uno script che invia qualunque cosa gli chieda una richiesta è o un malware caricato attraverso un buco, o un modulo legittimo senza protezione. Cerca mailer e file PHP modificati di recente nei siti:

Qualsiasi distribuzione
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

Poi guarda chi ha chiamato lo script, e quanto spesso. Un modulo di contatto inviato migliaia di volte da pochi indirizzi viene abusato; un file che nessuno dovrebbe conoscere, chiamato da molti indirizzi, è una backdoor.

Log del web server
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
  • Uno script malevolo: rimuovilo, poi trova come è stato caricato (un plugin o un tema non aggiornato, una password di amministratore debole, un modulo di upload) e chiudi quella strada. La guida sui crypto miner mostra come cercare il resto di quello che un attaccante lascia.
  • Un modulo abusato: aggiungi un CAPTCHA o un campo nascosto che i bot compilano, non lasciare mai che sia il visitatore a scegliere il destinatario, e non inviare una copia all'indirizzo digitato nel modulo.

Un open relay

Oggi è più raro, ma controllalo: un server di posta che consegna la posta di chiunque a chiunque. In Postfix, mynetworks deve contenere solo il server stesso e le tue reti, e le restrizioni sul relay devono finire con reject_unauth_destination:

Postfix
postconf mynetworks smtpd_relay_restrictions smtpd_recipient_restrictions

Evitare che succeda di nuovo

SPF, DKIM e DMARC

Questi tre record DNS dicono agli altri server di posta quali server possono inviare per il tuo dominio e se un messaggio viene davvero da te. Non impediscono a una casella bucata di inviare spam attraverso il tuo server, ma impediscono ad altri di falsificare il tuo dominio, e i grandi provider ormai li richiedono prima di consegnare la tua posta. Un esempio per un dominio la cui posta parte da 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 richiede una chiave sul server di posta (OpenDKIM per Postfix, integrato in Exim; pannelli come cPanel e Plesk lo fanno per te) e la sua parte pubblica nel DNS. Controlla cosa è pubblicato:

Qualsiasi distribuzione
dig +short TXT example.com
dig +short TXT _dmarc.example.com
dig +short TXT default._domainkey.example.com

Nota: dig è nel pacchetto dnsutils su Debian e Ubuntu (bind9-dnsutils nelle versioni più recenti) e in bind-utils sulla famiglia RHEL. Il selettore DKIM, qui default, dipende dalla tua configurazione.

Limiti di invio

Un limite trasforma un account compromesso da centomila messaggi in qualche centinaio. Postfix limita i messaggi per indirizzo del client; la posta che PHP invia tramite sendmail non ci passa, e i limiti per utente richiedono un servizio di policy come postfwd.

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

Exim può limitare ogni utente autenticato nella sua ACL RCPT. Su cPanel usa invece **Max hourly emails per domain** nelle Tweak Settings di 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

Solo il server di posta può usare la porta 25

Su un web server niente, tranne il server di posta, ha bisogno di collegarsi alla porta 25 di altri server. Questa regola nftables rifiuta le connessioni in uscita verso la porta 25 di ogni altro utente, e ferma script e malware che parlano SMTP direttamente. Sostituisci postfix con l'utente del tuo server di posta: Debian-exim per Exim su Debian e Ubuntu, exim sulla famiglia RHEL, mailnull su cPanel.

Qualsiasi distribuzione 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

Attenzione: Scrivi giusto il nome utente: con quello sbagliato il server smette di consegnare qualunque messaggio. Si fermano anche le applicazioni che inviano tramite un server SMTP esterno sulla porta 25; dovrebbero comunque usare la 587 con login. La tabella sparisce al riavvio: quando funziona, aggiungila alla configurazione del firewall. Su cPanel, **SMTP Restrictions** in WHM fa la stessa cosa.

Molti provider cloud bloccano di default la porta 25 in uscita e la aprono su richiesta. Se dal server non invii affatto posta, lasciala bloccata e invia tramite un servizio di relay sulla 587.

E il solito hardening

  • Tieni aggiornati WordPress, plugin e temi, e rimuovi quelli che non usi.
  • Proteggi i login della posta dal brute force come SSH: vedi Come bloccare gli attacchi brute force SSH.
  • Lascia attivi mail.add_x_header e mail.log, così la prossima volta lo script si conosce in pochi secondi.

Togliere il server dalle blocklist

Chiedi la rimozione solo dopo che lo spam si è fermato e la causa è chiusa: un server che torna in lista subito dopo il delisting viene trattato più duramente la seconda volta. Controlla le liste principali via DNS, con l'indirizzo pubblico del server in IP:

Qualsiasi distribuzione
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 risposta vuota vuol dire non in lista; un indirizzo come 127.0.0.2 vuol dire in lista. Spamhaus rifiuta le query inviate tramite resolver pubblici e risponde 127.255.255.254: in quel caso usa il suo sito. L'ultima riga mostra il DNS inverso (PTR) dell'indirizzo, che dovrebbe essere un nome host che risolve di nuovo a quell'indirizzo.

  • Spamhaus: cerca l'indirizzo su check.spamhaus.org, che spiega ogni inserimento e come chiederne la rimozione.
  • SpamCop: gli inserimenti scadono da soli quando le segnalazioni si fermano (spamcop.net).
  • Microsoft (Outlook, Hotmail): chiedi il delisting su sender.office.com.
  • Gmail: nessun modulo di delisting; Postmaster Tools mostra la reputazione del tuo dominio mentre si riprende.

Nota: Procedure aggiornate a novembre 2026, dalle pagine delle liste stesse. Il recupero richiede giorni, non ore: la reputazione presso i grandi provider migliora solo mentre continui a inviare posta pulita.

Cosa fa InfraFence contro lo spam dal tuo server

InfraFence lavora sulle cause più che sulla posta in sé:

  • Brute force sulla posta: l'agent legge i log di Postfix, Exim, Dovecot e Roundcube (o il journal di systemd) e banna un indirizzo dopo 5 login falliti o tentativi di relay in 5 minuti, su SMTP, submission, IMAP, POP3 e webmail. Ogni evento indica la casella tentata. Vedi SSH e forza bruta.
  • Script mailer: lo scanner malware ha firme per gli script PHP che inviano ciò che chiede una richiesta (mail() alimentata direttamente da $_POST, LeafMailer), web shell e backdoor, regole YARA, e segnala i file PHP creati nelle cartelle di upload. Con le scansioni automatiche attive, i nuovi file PHP nelle cartelle di upload vengono scansionati entro 30 secondi. Vedi Malware.
  • Minacce in uscita: le connessioni dal server verso indirizzi delle liste Spamhaus DROP ed Emerging Threats vengono segnalate come critiche. Vedi Minacce in uscita e DNS.

Cosa non fa: InfraFence non legge la coda di posta, non conta né limita la posta in uscita, non blocca la porta 25 e non controlla se il tuo indirizzo è in una blocklist. Una casella usata con la sua password corretta, per lui, è un login normale. La coda, i limiti e il delisting di questa guida restano da fare a te.

Domande

Il server non ha un server di posta. Come può inviare spam?
La mail() di PHP usa il sendmail che quasi ogni distribuzione installa, e un malware può collegarsi da solo alla porta 25 di altri server. Controlla le connessioni in uscita del passo 1 e la regola che riserva la porta 25 al server di posta.
SPF, DKIM e DMARC fermano lo spam?
No. Dimostrano quali server possono inviare per il tuo dominio, e lo spam inviato tramite una casella bucata sul tuo server li supera. Proteggono il tuo dominio dalla falsificazione e aiutano la consegna della tua posta legittima.
Quanto ci vuole per uscire da una blocklist?
Dipende dalla lista. Gli inserimenti di SpamCop scadono da soli quando le segnalazioni si fermano; Spamhaus e Microsoft agiscono su una richiesta di rimozione una volta risolto il problema. La reputazione presso Gmail e Outlook si riprende in giorni di invii puliti.

Provalo gratis su 1 server

Starter è gratuito per un server, con protezione completa e blocco automatico. Senza carta di credito.

Installa l'agent come root, con il tuo token al posto di <TOKEN>:

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

Il token si crea nella dashboard, in Server › Aggiungi server.