Гид по технологиям

Как найти устаревшие версии WordPress на сервере

• 4 min read • Security • Обновлено 20 Nov 2025
Найти устаревшие версии WordPress на сервере
Найти устаревшие версии WordPress на сервере

Зачем это важно

Устаревшие установки WordPress — частая точка входа для атак на общедоступные и шаред-хостинги. Как только уязвимость публикуется, злоумышленники массово сканируют сервера в поисках уязвимых версий. Этот метод помогает быстро найти такие установки и снизить риск компрометации.

Предпосылки

  • Установлен php-cli и есть права чтения каталога(ов), которые вы собираетесь сканировать (обычно root или sudo).
  • Базовое понимание PHP и доступа к командной строке.

Как WordPress хранит номер версии

WordPress хранит строку версии в файле wp-includes/version.php. В нём обычно есть строка вида:

$wp_version = ‘3.8.1’;

Мы не будем включать (include) этот файл в код, чтобы избежать исполнения потенциально вредоносного PHP-кода — вместо этого читаем содержимое как текст и распознаём строку с помощью регулярного выражения.

Идея скрипта

  1. Рекурсивно обойти базовую папку (например, /var/www).
  2. Найти каталоги, характерные для установки WordPress: wp-content, wp-admin или wp-includes.
  3. Если найдены — попытаться прочитать wp-includes/version.php как текст.
  4. Извлечь $wp_version с помощью preg_match.
  5. Сравнить найденную версию с константой LATEST_VERSION через version_compare.
  6. Собрать статистику и опционально записать в CSV.

Минимальный пример: обход директорий

Этот код рекурсивно обходит каталог, обнаруживает подпапки и отмечает потенциальные установки WordPress по наличию ключевых папок.

Чтение версии безопасным способом

Вместо include мы читаем файл как текст и ищем шаблон версии:

Примечание: регулярное выражение ищет простую цифровую точечную нотацию, например «3.8.1». Если в вашей версии есть суффиксы (RC, alpha), шаблон придётся расширить.

Important: никогда не include-ите произвольные PHP-файлы, найденные в чужих директориях — они могут содержать вредоносный код (например, отправку файлов или запуск команды). Чтение как текста безопаснее.

Сравнение версий и итоговый отчёт

PHP-функция version_compare() корректно сравнивает строковые версии. Вставляем сравнение и статистику:

 $version) {
    // is the found version lower than latest one?
    if(version_compare($version, LATEST_VERSION, '<')) {
        $outdated++;
        print '[WARN] outdated wordpress version ' . $version;
    } else {
        $current++;
        print '[OK] current wordpress version ' . $version;
    }
    print ' in ' . $path . "\n";
}
// print summary
print "We found " . count($wp_inst) . " wordpress installations, of which " . $outdated . " are outdated and " . $current . " are up to date.\n";
?>

Типичный вывод:

[WARN] outdated wordpress version 3.3 in /var/www/clients/pathX/ [WARN] outdated wordpress version 3.4 in /var/www/clients/pathY/ [OK] current wordpress version 3.8.1 in /var/www/clients/pathA/ [OK] current wordpress version 3.8.1 in /var/www/clients/pathB/

We found 114 wordpress installations, of which 85 are outdated and 29 are up to date.

Финальный скрипт и CSV-отчёт

В исходной статье приведён полный скрипт, который записывает результаты в CSV (path;found_version;latest_version). Запуск:

php find_wordpress.php /var/www /my/path/versions.csv

CSV-формат (пример):

/var/www/clients/path1/;3.6;3.8.1 /var/www/clients/path2/;3.8.1;3.8.1 /var/www/clients/path3/;3.8.1;3.8.1 /var/www/clients/path4/;3.0.1;3.8.1

Полный код скрипта (сохраните как find_wordpress.php):


 */
define('LATEST_VERSION', '3.8.1');
if(!isset($argv[1])) die("Please start this program with " . $argv[0] . "  []\n");
// set the base path
define('BASE_PATH', $argv[1]);
define('OUTFILE', (isset($argv[2]) ? $argv[2] : false));
// check that provided path exists
if(!is_dir(BASE_PATH)) {
    die(BASE_PATH . " is no valid path.\n");
}
// define array to store the wordpress installation paths
$wp_inst = array();
/* main function to loop through paths recursively */
function path_loop($path) {
    global $wp_inst;
    
    // make sure path ends with a slash
    if(substr($path, -1) !== '/') $path .= '/';
    
    // open dir
    $dir = opendir($path);
    if(!$dir) {
        print "[WARN] Could not access " . BASE_PATH . "\n";
        return false;
    }
    // loop through everything this dir contains
    while($cur = readdir($dir)) {
        // we only want to read paths, not files
        if($cur === '.' || $cur === '..' || is_link($path . $cur) || !is_dir($path . $cur)) continue;
        
        if(($cur === 'wp-content' || $cur == 'wp-admin' || $cur == 'wp-includes') && array_key_exists($path, $wp_inst) == false) {
            // this seems to be a wordpress installation path
            // check for the version file now
            $versionfile = $path . 'wp-includes/version.php';
            if(!file_exists($versionfile) || !is_readable($versionfile)) continue; // cannot read the file
            
            // we don't simply include the file for security reasons.
            // so store it in a variable
            $cont = file_get_contents($versionfile);
            
            // search for the version string
            $found = preg_match('/\$wp_version\s*=\s*((["\'])([0-9\.]+)\\1;/', $cont, $match);
            if(!$found) continue; // we found no version string in the file... strange.
            
            $wp_inst[$path] = $match[2];
            print '[INFO] found wp version ' . $match[2] . ' in ' . $path . "\n";
        }
        
        path_loop($path . $cur); // we dive into the dir even if we found wp here.
    }
    
    // free resource
    closedir($dir);
}
// start the loop process
path_loop(BASE_PATH);
// some statistic variables
$current = 0;
$outdated = 0;
if(OUTFILE) $fp = fopen(OUTFILE, 'w');
// loop through all found versions
foreach($wp_inst as $path => $version) {
    // is the found version lower than latest one?
    if(version_compare($version, LATEST_VERSION, '<')) {
        $outdated++;
        print '[WARN] outdated wordpress version ' . $version;
    } else {
        $current++;
        print '[OK] current wordpress version ' . $version;
    }
    print ' in ' . $path . "\n";
    
    if(OUTFILE) fputcsv($fp, array($path, $version, LATEST_VERSION), ';', '"');
}
if(OUTFILE) fclose($fp);
// print summary
print "We found " . count($wp_inst) . " wordpress installations, of which " . $outdated . " are outdated and " . $current . " are up to date.\n";

?>

Практические рекомендации и чек-лист перед запуском

  • Выполните скан сначала в тестовой среде или на подмножестве сайтов.
  • Запускайте от пользователя с минимально необходимыми правами чтения.
  • Делайте резервную копию важных конфигураций перед массовыми правками.
  • Если скрипт находит много устаревших установок — планируйте обновления по приоритету (по бизнес-важности и доступности резервных копий).

Короткий чек-лист:

  • Скопировать скрипт на сервер
  • Проверить php-cli (php -v)
  • Выполнить: php find_wordpress.php /var/www /tmp/wp_versions.csv
  • Проанализировать CSV
  • Обновить/удалить устаревшие инстансы

Когда этот метод не сработает (ограничения)

  • Если в установке WordPress переименовали стандартные папки (wp-content и т. п.).
  • Если версия хранится в другом формате (например, с буквенными суффиксами) — нужно расширить регулярное выражение.
  • Если у вас нет прав чтения папок — скрипт не увидит установок.

Альтернативы

  • Использовать готовые средства управления хостингом (cPanel/ISPConfig) с функцией инвентаризации.
  • Использовать инструмент на стороне HTTP (скан по URL) — полезно при отсутствии SSH/FS-доступа, но он медленнее и неточен при кастомных темах и плагинах.
  • Использовать конфигурационные менеджеры (Ansible/Chef) для отслеживания версий как части инвентаря.

Быстрая методика принятия решения (мини-Playbook)

  1. Собрать CSV и отфильтровать по устаревшим версиям.
  2. Для каждой записи: проверить наличие резервной копии и плагинов/тем, критичных для бизнеса.
  3. Тестировать обновление в стейджинг-среде.
  4. Планировать окно обновления и откат.

Матрица рисков (качественная)

  • Высокий риск: публичные сайты с устаревшими версиями и активными плагинами.
  • Средний риск: внутренние сайты без публичного доступа, где есть слабые пароли.
  • Низкий риск: полностью изолированные стендовые инстансы.

Митигаторы: ограничение доступа по IP, регулярные бэкапы, применение WAF, быстрые обновления.

1‑строчная глоссарий

  • wp-includes/version.php — файл, где WordPress хранит переменную $wp_version.

Критерии приёмки

  • Скрипт находит все установки, где присутствует wp-includes/version.php и возвращает версию.
  • CSV содержит путь, найденную версию и эталонную (LATEST_VERSION).
  • Скрипт не выполняет (не include-ит) найденные файлы.

Завершение

Используйте этот инструмент как часть регулярного аудита безопасности: он быстро укажет, где нужно срочно обновляться или расследовать подозрительную активность. Планируйте обновления, делайте бэкапы и минимизируйте риск через автоматизацию и контроль доступа.

Мы желаем вам «удачной охоты на устаревшие версии» и безопасного обслуживания серверов.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро