2026年11月12日

2026年11月12日

Як заборонити виконання PHP у каталозі uploads WordPress

Ця стаття — локалізована версія японського оригіналу. Читати японський оригінал

Вступ

wp-content/uploads/ — це каталог, де WordPress зберігає зображення й інші медіафайли. Якщо в ньому можуть опинитися PHP-файли, які сервер здатен виконувати, зловмисник може завантажити веб-шел (бекдор) і виконати довільний код.

Симптоми та причини

  • Сканування на шкідливий код виявило PHP-файли в wp-content/uploads/
  • Плагін безпеки попередив, що «у каталозі uploads можливе виконання PHP»
  • Підозрілий файл знайшли за шляхом на кшталт wp-content/uploads/2024/01/shell.php
  • Веб-шел потрапив на сервер через вразливість у функції завантаження файлів

Порядок розв’язання

Крок 1. Знайдіть наявні підозрілі PHP-файли

# Знайти всі PHP-файли в каталозі 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

# Переглянути PHP-файли, створені чи змінені нещодавно (протягом 7 днів)
find /var/www/html/wp-content/uploads -name "*.php" -mtime -7

# Перевірити вміст файлів (характерні шаблони шкідливого коду)
grep -rl "eval(base64_decode" /var/www/html/wp-content/uploads/
grep -rl "system\|exec\|passthru\|shell_exec" /var/www/html/wp-content/uploads/

# Видалити підозрілі PHP-файли
find /var/www/html/wp-content/uploads -name "*.php" -delete
find /var/www/html/wp-content/uploads -name "*.phtml" -delete

Крок 2. Заборонте виконання PHP в Apache (.htaccess)

# Створити wp-content/uploads/.htaccess
cat > /var/www/html/wp-content/uploads/.htaccess << 'EOF'
# Повністю заборонити виконання PHP-файлів
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|phar|shtml)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

# Вимкнути сам рушій PHP (якщо використовується mod_php)
<IfModule mod_php.c>
    php_flag engine off
</IfModule>

# Заборонити також виконання CGI
Options -ExecCGI
RemoveHandler .php .phtml .php5 .phar

# Вимкнути також перегляд вмісту каталогу
Options -Indexes
EOF

chmod 644 /var/www/html/wp-content/uploads/.htaccess
# Перевірка після налаштування
# Створити тестовий PHP-файл і спробувати відкрити його
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
# Якщо повертається 403 — усе вдалося
rm /var/www/html/wp-content/uploads/test_block.php

Крок 3. Заборонте виконання PHP в Nginx

# /etc/nginx/sites-available/example.com
server {
    # ... наявні налаштування ...

    # Заборонити виконання PHP в каталозі uploads
    location ~* /wp-content/uploads/.*\.(php|phtml|php5|phar)$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Записувати перед location для PHP-FPM
    location ~ \.php$ {
        # Звичайна обробка 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;
    }
}
# Перевірити конфігурацію Nginx і застосувати її
sudo nginx -t && sudo systemctl reload nginx

# Перевірка
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/shell.php
# Якщо повертається 403 — усе вдалося

Крок 4. Заблокуйте завантаження PHP і на боці WordPress

// functions.php: заборонити саме завантаження PHP-файлів

// ① Додати PHP-розширення до списку заборонених для завантаження
add_filter('upload_mimes', function(array $mimes): array {
    // Прибрати MIME-типи, пов’язані з PHP (про всяк випадок)
    unset($mimes['php'], $mimes['phtml'], $mimes['phar']);
    return $mimes;
});

// ② Виявлення PHP у завантажуваних файлах і відмова
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'] = 'Завантаження PHP-файлів заборонено.';
    }

    // Перевірити також за MIME-типом
    if (str_contains($file['type'], 'php')) {
        $file['error'] = 'Завантаження PHP-файлів заборонено.';
    }

    return $file;
});

Крок 5. Налаштуйте регулярний моніторинг

# Скрипт для регулярного моніторингу PHP-файлів в 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 "Попередження: у каталозі uploads виявлено PHP-файли:
$PHP_FILES" | mail -s "[ТЕРМІНОВО] Імовірно, у WordPress встановлено веб-шел" "$ADMIN_EMAIL"

    # Автоматичне видалення (використовуйте обережно)
    # find "$UPLOADS_DIR" -name "*.php" -delete
fi
EOF
chmod +x /usr/local/bin/check-uploads-php.sh

# Перевіряти щогодини
echo "0 * * * * root /usr/local/bin/check-uploads-php.sh" > /etc/cron.d/wp-uploads-php-check

Важливі зауваження

  • php_flag engine off у .htaccess діє лише тоді, коли використовується mod_php. Якщо ви працюєте з php-fpm (FastCGI), скористайтеся директивою <FilesMatch> або блоком location в Nginx
  • В Nginx, якщо правило-блокування для uploads не записати перед location ~ \.php$, пріоритет може отримати друге, і PHP виконуватиметься. Обов’язково ставте правило-блокування вище
  • Деякі плагіни (наприклад, Slider Revolution) можуть розміщувати .php-файли всередині uploads. Перш ніж видаляти, з’ясуйте призначення файлів, видаліть непотрібні плагіни, а вже потім діймайте решти

Підсумок

Заборона виконання PHP в каталозі uploads складається з п’яти кроків: ① знайти й видалити наявні підозрілі файли за допомогою find wp-content/uploads -name ".php"; ② в Apache додати в uploads/.htaccess блок <FilesMatch "\.(php|phar)$"> Deny from all; ③ в Nginx застосувати deny all у location ~ /wp-content/uploads/.*\.php$; ④ відхиляти саме завантаження PHP за допомогою хука wp_handle_upload_prefilter; ⑤ щогодини перевіряти cron-завданням PHP-файли в uploads.

Маєте запитання щодо WordPress? Видавець сайту перебуває в Японії й відповідає японською. Написати нам (японською)

お気軽にご相談ください

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