Salta al contenuto principale
Sistemi Attivi
WP Planet — WordPress Cloud & Managed Services
Torna al MagazineSicurezza

Shell PHP in WordPress: come entra il web shell, come trovarlo e come blindare il server prima del peggio

22 Ott 2026 — 09:30 9 min di lettura
Shell PHP in WordPress: come entra il web shell, come trovarlo e come blindare il server prima del peggio

Una shell PHP è un singolo file caricato nella cartella uploads che dà all'attaccante il controllo completo del server. Come ci arriva, perché l'antivirus del plugin non la ferma sempre, e i tre controlli che chiudono davvero la porta: disabilitare PHP in uploads, verificare i file core, bloccare l'esecuzione di codice arbitrario.

Quando un sito WordPress viene compromesso, nella stragrande maggioranza dei casi non è perché qualcuno ha bucato il core. È perché un plugin non aggiornato, un tema abbandonato o una password rubata hanno permesso a qualcuno di caricare un singolo file PHP nella cartella wp-content/uploads. Quel file è una shell — un web shell — e da quel momento il server non è più tuo.

La shell non deve essere sofisticata. Spesso è una decina di righe di codice che accettano un parametro via POST e lo eseguono con eval() o system(). Basta quello: l'attaccante ha un terminale sul tuo server, può leggere il wp-config.php con le credenziali del database, scaricare i dati dei clienti, caricare altre shell in posizioni meno ovvie, e restarci per settimane senza che nessuno se ne accorga. Il danno economico, su un e-commerce, può essere superiore al costo di tutta la manutenzione preventiva dell'anno.

Come ci arriva una shell nella cartella uploads

Il percorso più comune è un plugin con una vulnerabilità di tipo arbitrary file upload. Un plugin di form contatti, un plugin di gestione allegati, un plugin che permette agli utenti di caricare file senza validare l'estensione. L'attaccante invia una richiesta POST con un file chiamato, che so, backup.php — l'estensione sembra innocua, il plugin lo salva nella cartella uploads dell'anno corrente, e da lì basta richiamarlo dal browser per eseguirlo.

Il secondo percorso è l'accesso diretuto: una password admin rubata via phishing, o una password FTP debole. Se l'attaccante ha accesso FTP o al pannello di hosting, non ha bisogno di una vulnerabilità: carica la shell direttamente via protocollo file. Per questo il primo controllo non è tecnico, è operativo — password complesse, 2FA su ogni account admin, e FTP disabilitato se non lo usi (usa SFTP o SSH).

Perché l'antivirus del plugin non la ferma sempre

Molti plugin di sicurezza scansionano i file con un database di firme noto. Funziona per le shell più comuni, quelle scaricate da toolkit pubblici. Ma le shell personalizzate — quelle scritte su misura per il tuo sito, o offuscate con codifica base64 — spesso passano la scansione. Il motivo è semplice: un antivirus basato su firme riconosce solo ciò che ha già visto. Una shell nuova, o una variante con variabili rinominate, non è nel database.

La difesa non sta in un antivirus migliore. Sta nel rendere la shell inutile anche se riesce a entrare. Se il server non può eseguire PHP nella cartella uploads, il file caricato è solo un file inerte — un pezzo di testo che non fa niente. È il controllo più importante e si fa con una riga di .htaccess.

.htaccess
# Disabilita l'esecuzione di PHP in wp-content/uploads
# Crea il file wp-content/uploads/.htaccess con questo contenuto:
<Files *.php>
    Require all denied
</Files>

# Per Nginx (nel blocco server):
# location ~* /wp-content/uploads/.*\.php$ {
#     deny all;
# }
Nota: Questo blocca ogni esecuzione di PHP nella cartella uploads. Verifica che nessun plugin legittimo richieda di eseguire PHP negli uploads (raro ma possibile, alcuni plugin di caching o di ottimizzazione lo fanno). In caso, sposta il file del plugin fuori dalla cartella uploads.

Trovare le shell già presenti

Se il sito è già compromesso, disabilitare l'esecuzione PHP in uploads non basta: la shell potrebbe essere altrove — nella root, in un tema, in un MU plugin iniettato. La ricerca parte dai segnali: file con nomi casuali (x9k2.php, config.bak.php), file modificati di recente che non dovresti aver toccato, stringhe sospette nel codice come eval(), base64_decode(), gzinflate(), system(), shell_exec(), passthru().

Il primo strumento è WP-CLI, che permette di cercare nei file del tema e dei plugin senza accedere al pannello admin (che potrebbe essere compromesso):

Terminale
# Cerca funzioni sospette nei file PHP del tema attivo
wp eval-file <<'PHP'
$dir = get_stylesheet_directory();
$it = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
);
$patterns = [
    '/eval\s*\(/i',
    '/base64_decode\s*\(/i',
    '/gzinflate\s*\(/i',
    '/shell_exec\s*\(/i',
    '/system\s*\(/i',
    '/passthru\s*\(/i',
];
foreach ($it as $file) {
    if ($file->getExtension() !== 'php') continue;
    $content = file_get_contents($file->getPathname());
    foreach ($patterns as $p) {
        if (preg_match($p, $content)) {
            echo "SOSPETTO: " . $file->getPathname() . " — pattern $p\n";
        }
    }
}
PHP
Nota: Questo cerca funzioni comunemente usate nelle shell. Non ogni match è malevolo — base64_decode è usato anche da plugin legittimi per dati codificati — ma ogni match va verificato manualmente. Un file di tema con system() quasi sempre è una shell.

Verificare l'integrità dei file core

Un'altra tecnica comune è modificare un file core — wp-login.php, wp-cron.php, o un file della cartella wp-includes — per iniettare codice malevolo che si attiva a ogni page load. La shell non è un file nuovo: è dentro un file esistente. WordPress ha uno strumento nativo per verificare che i file core corrispondano ai checksum ufficiali:

Terminale
# Verifica l'integrità dei file core contro i checksum ufficiali
wp core verify-checksums

# Output atteso su installazione pulita:
# Success: WordPress installation verifies against checksums.

# Se c'è un mismatch, un file core è stato modificato.
# Confronta con un'installazione pulita della stessa versione
# o ripristina i file core dal pacchetto ufficiale.
Nota: verify-checksums controlla solo i file core, non plugin e temi. Per quelli, il confronto è manuale o con strumenti dedicati. Un mismatch nei checksum core è un segnale di compromissione serio: agisci subito.

Dopo la bonifica: i tre controlli che chiudono la porta

Trovare e rimuovere la shell è metà del lavoro. L'altra metà è assicurarsi che non rientri — e che l'attaccante non abbia lasciato altre porte. I tre controlli che facciamo sempre dopo una bonifica: primo, cambiare ogni password (database, admin, FTP, hosting) perché una shell dà accesso al wp-config.php con le credenziali in chiaro. Secondo, disabilitare l'esecuzione PHP in uploads come visto sopra. Terzo, ripristinare i file core dai checksum ufficiali e reinstallare i plugin da repository pulita, perché una shell spesso ne nasconde altre.

La prevenzione costa meno della bonifica. Un WAF a livello server ferma le richieste malevole prima che raggiungano WordPress, l'hardening riduce la superficie d'attacco, e un monitoraggio dei file con verifica checksum periodica individia le modifiche non autorizzate quando succedono — non settimane dopo. Su un sito gestito, la shell PHP non dovrebbe mai arrivare. Quando arriva, il tempo di reazione è ciò che separa un incidente minore da un danno reputazionale serio.

Audit di sicurezza

Verifica la sicurezza del tuo WordPress prima che diventi un'emergenza.

Un audit di sicurezza individua le falle, i plugin vulnerabili e le configurazioni deboli prima che qualcuno le sfrutti.

Audit di sicurezza
Condividi