Как найти устаревшие версии WordPress на сервере
Зачем это важно
Устаревшие установки WordPress — частая точка входа для атак на общедоступные и шаред-хостинги. Как только уязвимость публикуется, злоумышленники массово сканируют сервера в поисках уязвимых версий. Этот метод помогает быстро найти такие установки и снизить риск компрометации.
Предпосылки
- Установлен php-cli и есть права чтения каталога(ов), которые вы собираетесь сканировать (обычно root или sudo).
- Базовое понимание PHP и доступа к командной строке.
Как WordPress хранит номер версии
WordPress хранит строку версии в файле wp-includes/version.php. В нём обычно есть строка вида:
$wp_version = ‘3.8.1’;
Мы не будем включать (include) этот файл в код, чтобы избежать исполнения потенциально вредоносного PHP-кода — вместо этого читаем содержимое как текст и распознаём строку с помощью регулярного выражения.
Идея скрипта
- Рекурсивно обойти базовую папку (например, /var/www).
- Найти каталоги, характерные для установки WordPress: wp-content, wp-admin или wp-includes.
- Если найдены — попытаться прочитать wp-includes/version.php как текст.
- Извлечь $wp_version с помощью preg_match.
- Сравнить найденную версию с константой LATEST_VERSION через version_compare.
- Собрать статистику и опционально записать в 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)
- Собрать CSV и отфильтровать по устаревшим версиям.
- Для каждой записи: проверить наличие резервной копии и плагинов/тем, критичных для бизнеса.
- Тестировать обновление в стейджинг-среде.
- Планировать окно обновления и откат.
Матрица рисков (качественная)
- Высокий риск: публичные сайты с устаревшими версиями и активными плагинами.
- Средний риск: внутренние сайты без публичного доступа, где есть слабые пароли.
- Низкий риск: полностью изолированные стендовые инстансы.
Митигаторы: ограничение доступа по IP, регулярные бэкапы, применение WAF, быстрые обновления.
1‑строчная глоссарий
- wp-includes/version.php — файл, где WordPress хранит переменную $wp_version.
Критерии приёмки
- Скрипт находит все установки, где присутствует wp-includes/version.php и возвращает версию.
- CSV содержит путь, найденную версию и эталонную (LATEST_VERSION).
- Скрипт не выполняет (не include-ит) найденные файлы.
Завершение
Используйте этот инструмент как часть регулярного аудита безопасности: он быстро укажет, где нужно срочно обновляться или расследовать подозрительную активность. Планируйте обновления, делайте бэкапы и минимизируйте риск через автоматизацию и контроль доступа.
Мы желаем вам «удачной охоты на устаревшие версии» и безопасного обслуживания серверов.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента