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.
sudo postqueue -p | tail -n 1
sudo postqueue -p | awk '/^[0-9A-Za-z]/ {print $7}' | sort | uniq -c | sort -rn | headExim, 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:
sudo exim -bpc
sudo exim -bp | awk '/^ *[0-9]+[mhd] / {print $4}' | sort | uniq -c | sort -rn | head
sudo exim -bp | exiqsumm | sort -rn | headUn 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:
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 | headExim 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:
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 | headQuale 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.
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):
php --ini | grep 'Loaded Configuration'
ls /etc/php/*/fpm/php.ini /etc/php.ini 2>/dev/nullmail.add_x_header = On
mail.log = syslogRiavvia 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:
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 20Programmi 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.
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 -rnFermare 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:
sudo mkdir -p /root/evidence
sudo cp -p /path/to/script.php /root/evidence/
sudo chmod 000 /path/to/script.phpPer 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:
sudo postconf -e 'defer_transports = smtp'
sudo postfix reloadQuando la coda è pulita (passo successivo), rilasciala:
sudo postconf -e 'defer_transports ='
sudo postfix reload
sudo postqueue -fCon Exim, congela i messaggi del mittente che hai trovato. I messaggi congelati restano in coda e non vengono consegnati:
sudo exiqgrep -i -f 'spammer@example\.com' | xargs -r sudo exim -MfAttenzione: 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.
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:
sudo exiqgrep -i -f 'spammer@example\.com' | xargs -r sudo exim -Mrm
sudo exiqgrep -z -i | xargs -r sudo exim -MrmAttenzione: 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:
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 -20La 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:
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 -50Poi 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.
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:
postconf mynetworks smtpd_relay_restrictions smtpd_recipient_restrictionsEvitare 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:
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:
dig +short TXT example.com
dig +short TXT _dmarc.example.com
dig +short TXT default._domainkey.example.comNota: 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.
sudo postconf -e 'smtpd_client_message_rate_limit = 100' 'anvil_rate_time_unit = 3600s'
sudo postfix reloadExim può limitare ogni utente autenticato nella sua ACL RCPT. Su cPanel usa invece **Max hourly emails per domain** nelle Tweak Settings di WHM.
# 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 exceededSolo 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.
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 } rejectAttenzione: 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_headeremail.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:
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 ilsendmailche 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.
