2026年11月12日

2026年11月12日

Bloccare l’esecuzione di PHP nella cartella uploads di WordPress

Questo articolo è un'edizione localizzata dell'originale giapponese. Leggi l'originale in giapponese

Introduzione

wp-content/uploads/ è la cartella in cui WordPress salva i file multimediali, come le immagini. Se in questa cartella finiscono file PHP eseguibili, un attaccante può caricare una web shell (backdoor) ed eseguire codice arbitrario.

Sintomi e cause

  • Una scansione antimalware ha rilevato file PHP dentro wp-content/uploads/
  • Un plugin di sicurezza ha segnalato «PHP è eseguibile nella cartella uploads»
  • È stato trovato un file sospetto con un percorso come wp-content/uploads/2024/01/shell.php
  • Una web shell è stata installata sfruttando una vulnerabilità della funzione di caricamento dei file

Procedura di risoluzione

Passo 1: individua i file PHP sospetti già presenti

# Cerca tutti i file PHP nella cartella uploads
find /var/www/html/wp-content/uploads -name "*.php" -type f
find /var/www/html/wp-content/uploads -name "*.phtml" -type f
find /var/www/html/wp-content/uploads -name "*.php5" -type f

# Controlla i file PHP creati o modificati di recente (negli ultimi 7 giorni)
find /var/www/html/wp-content/uploads -name "*.php" -mtime -7

# Controlla il contenuto dei file (schemi tipici dei malware)
grep -rl "eval(base64_decode" /var/www/html/wp-content/uploads/
grep -rl "system\|exec\|passthru\|shell_exec" /var/www/html/wp-content/uploads/

# Elimina i file PHP sospetti
find /var/www/html/wp-content/uploads -name "*.php" -delete
find /var/www/html/wp-content/uploads -name "*.phtml" -delete

Passo 2: blocca l’esecuzione di PHP con Apache (.htaccess)

# Crea wp-content/uploads/.htaccess
cat > /var/www/html/wp-content/uploads/.htaccess << 'EOF'
# Vieta completamente l'esecuzione dei file PHP
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|phar|shtml)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

# Disattiva il motore PHP stesso (con mod_php)
<IfModule mod_php.c>
    php_flag engine off
</IfModule>

# Vieta anche l'esecuzione di CGI
Options -ExecCGI
RemoveHandler .php .phtml .php5 .phar

# Disattiva anche l'elenco del contenuto delle cartelle
Options -Indexes
EOF

chmod 644 /var/www/html/wp-content/uploads/.htaccess
# Verifica dopo la configurazione
# Crea un file PHP di prova e prova ad accedervi
echo "<?php echo 'test'; ?>" > /var/www/html/wp-content/uploads/test_block.php
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/test_block.php
# Se risponde 403, ha funzionato
rm /var/www/html/wp-content/uploads/test_block.php

Passo 3: blocca l’esecuzione di PHP con Nginx

# /etc/nginx/sites-available/example.com
server {
    # ... configurazione esistente ...

    # Vieta l'esecuzione di PHP nella cartella uploads
    location ~* /wp-content/uploads/.*\.(php|phtml|php5|phar)$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Scrivilo prima della location di PHP-FPM
    location ~ \.php$ {
        # Normale gestione di PHP
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
# Verifica la configurazione di Nginx e applicala
sudo nginx -t && sudo systemctl reload nginx

# Verifica
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/shell.php
# Se risponde 403, ha funzionato

Passo 4: blocca il caricamento di PHP anche da WordPress

// functions.php: vieta il caricamento stesso dei file PHP

// ① Aggiungi le estensioni PHP all'elenco dei caricamenti vietati
add_filter('upload_mimes', function(array $mimes): array {
    // Rimuovi i tipi MIME legati a PHP (per sicurezza)
    unset($mimes['php'], $mimes['phtml'], $mimes['phar']);
    return $mimes;
});

// ② Rileva e rifiuta i file PHP caricati
add_filter('wp_handle_upload_prefilter', function(array $file): array {
    $dangerous_extensions = ['php', 'phtml', 'php3', 'php4', 'php5', 'phar', 'shtml'];
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

    if (in_array($ext, $dangerous_extensions, true)) {
        $file['error'] = 'Il caricamento di file PHP è vietato.';
    }

    // Controlla anche il tipo MIME
    if (str_contains($file['type'], 'php')) {
        $file['error'] = 'Il caricamento di file PHP è vietato.';
    }

    return $file;
});

Passo 5: imposta un controllo periodico

# Script che controlla periodicamente i file PHP dentro uploads
cat > /usr/local/bin/check-uploads-php.sh << 'EOF'
#!/bin/bash
UPLOADS_DIR="/var/www/html/wp-content/uploads"
ADMIN_EMAIL="admin@example.com"

PHP_FILES=$(find "$UPLOADS_DIR" -name "*.php" -o -name "*.phtml" -o -name "*.phar" 2>/dev/null)

if [ -n "$PHP_FILES" ]; then
    echo "Attenzione: rilevati file PHP nella cartella uploads:
$PHP_FILES" | mail -s "[URGENTE] Possibile web shell installata su WordPress" "$ADMIN_EMAIL"

    # Eliminazione automatica (da usare con cautela)
    # find "$UPLOADS_DIR" -name "*.php" -delete
fi
EOF
chmod +x /usr/local/bin/check-uploads-php.sh

# Controllo ogni ora
echo "0 * * * * root /usr/local/bin/check-uploads-php.sh" > /etc/cron.d/wp-uploads-php-check

Avvertenze

  • php_flag engine off in .htaccess funziona solo con mod_php. Se usi php-fpm (FastCGI), gestisci il caso con la direttiva oppure con un blocco location di Nginx
  • In Nginx, se la regola di blocco per uploads non viene scritta prima di location ~ \.php$, può avere la precedenza quest'ultima e l'esecuzione resta possibile. Metti sempre le regole di blocco più in alto
  • Alcuni plugin (per esempio Slider Revolution) possono mettere file .php dentro uploads. Prima di eliminarli verifica a cosa servono ed elimina i plugin non necessari, poi procedi

Riepilogo

Per bloccare l'esecuzione di PHP nella cartella uploads: ① trova ed elimina i file sospetti già presenti con find wp-content/uploads -name ".php"; ② con Apache aggiungi Deny from all in uploads/.htaccess; ③ con Nginx usa deny all in location ~ /wp-content/uploads/.*\.php$; ④ rifiuta il caricamento stesso dei file PHP con l'hook wp_handle_upload_prefilter; ⑤ controlla ogni ora con cron i file PHP dentro uploads.

Domande su WordPress? Chi pubblica questo sito ha sede in Giappone e risponde in giapponese. Contatti (in giapponese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲