Сканер устаревших установок Joomla на сервере
Зачем это важно
Устаревшие установки CMS часто становятся входной точкой для взломов, рассылки спама и других инцидентов безопасности. Этот гайд фокусируется на Joomla — популярной CMS, особенно часто встречающейся на shared hosting — и описывает простой способ массовой проверки версий по файловой структуре сайтов.
Важно: метод применим и к другим системам, если в них есть аналогичные файлы с указанием версии.
Предпосылки
- На сервере должны быть установлены утилиты bc и sed. Они не всегда присутствуют по умолчанию. Установите через менеджер пакетов, если нужно (apt, yum, pacman и т.п.).
- У вас есть доступ к shell и правами на чтение сайтов (обычно root или администратор).
Короткая методология
- Найти каталоги с именем components (характерно для Joomla).
- Извлечь путь до корня установки (dirname).
- Внутри установки прочитать файл с версией (несколько возможных мест).
- Сравнить главную версию и минор с текущими ветками (используем bc для сравнения нецелочисленных значений).
- Вывести предупреждения и опционально записать CSV-отчёт.
Какие файлы содержат версию Joomla
В разных версиях Joomla информация о версии хранится в одном из следующих файлов:
- /libraries/joomla/version.php
- /libraries/cms/version/version.php
- /includes/version.php
В этих файлах важны две переменные: RELEASE (главная версия) и DEV_LEVEL (минор, или build). Пример содержимого:
var $RELEASE = ‘1.0’; var $DEV_LEVEL = ‘12’;
Поиск установок Joomla на сервере
Общая идея — найти все папки с именем components, но игнорировать административные каталоги:
find /var/www/ -type d -name ‘components’ ! -wholename ‘/administrator/components’
Замените /var/www/ на базовый путь сайтов на вашей машине. Если у вас ISPConfig 3, базовый путь обычно выглядит как /var/www/clients/client/web (см. совет ниже).
Чтобы перебрать все найденные каталоги в цикле и получить путь до корня установки:
for L in find /var/www/ -type d -name 'components' ! -wholename '/administrator/components' ; do D=dirname $L ; done
Получение главной и минорной версии из файла
Сначала проверяем, какой из трёх возможных файлов с версией присутствует, затем извлекаем значения переменных RELEASE и DEV_LEVEL с помощью grep и sed:
F=$D/libraries/joomla/version.php ; F2=$D/libraries/cms/version/version.php ; F3=$D/includes/version.php ; if [[ -e “$F” || -e “$F2” || -e “$F3” ]] ; then if [[ -e “$F” ]] ; then F=$F ; elif [[ -e “$F2” ]] ; then F=$F2 ; elif [[ -e “$F3” ]] ; then F=$F3 ; fi else echo “No joomla version file found.” ; fi
VERSION=grep '$RELEASE' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g" ; SUBVERSION=grep '$DEV_LEVEL' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g" ;
Примечание: конструкция sed извлекает содержимое кавычек; она устойчива к пробелам вокруг знака =.
Сравнение версий
Поскольку версии в виде 1.5, 2.5 и т.п. не всегда корректно сравниваются как целые числа в bash, используем утилиту bc для арифметических сравнений. Пример логики:
ISOK=1 ; if [[ $(echo “if (${VERSION} < 1.5) 1 else 0” | bc) -eq 1 ]] ; then
ISOK=0 ; elif [[ $(echo “if (${VERSION} == 1.5) 1 else 0” | bc) -eq 1 && $(echo “if (${SUBVERSION} < 26) 1 else 0” | bc) -eq 1 ]] ; then
ISOK=0 ;
further checks
else ISOK=1 ; fi
Эту логику удобно вынести в отдельный блок, где вы задаёте «текущие» версии для каждой ветки (например, CUR15, CUR25, CUR3) и сравниваете найденную установку с этими константами.
Готовый скрипт для проверки (joomlascan.sh)
Ниже приводится полный пример скрипта. Сохраните его как joomlascan.sh и запустите через bash joomlascan.sh. Если передать имя файла как аргумент, скрипт создаст CSV-отчёт.
#!/bin/bash
# текущая минорная версия для ветки 1.5
CUR15=26
# текущая минорная версия для ветки 2.5
CUR25=17
# текущая минорная версия для ветки 3.2
CUR3=1
# базовый путь для сайтов
BASEPATH="/var/www/"
# файл CSV для вывода (опционально)
OUTFILE=$1
if [[ "$OUTFILE" != "" ]] ; then
# очистить/создать CSV
echo -n "" > $OUTFILE ;
fi
for L in `find ${BASEPATH} -type d -name 'components' ! -wholename '**/administrator/components' | grep -v '/tmp/'` ; do
D=`dirname $L` ;
F=$D/libraries/joomla/version.php ;
F2=$D/libraries/cms/version/version.php ;
F3=$D/includes/version.php ;
ISOK=0 ;
SHOWNEWEST="" ;
IMPORTANCE=0 ;
if [[ -e "$F" || -e "$F2" || -e "$F3" ]] ; then
if [[ -e "$F" ]] ; then
F=$F ;
elif [[ -e "$F2" ]] ; then
F=$F2 ;
elif [[ -e "$F3" ]] ; then
F=$F3 ;
fi
VERSION=`grep '$RELEASE' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
SUBVERSION=`grep '$DEV_LEVEL' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
if [[ $(echo "if (${VERSION} < 1.5) 1 else 0" | bc) -eq 1 ]] ; then
# версия ниже 1.5
SHOWNEWEST="1.5.${CUR15}" ;
IMPORTANCE=3 ;
elif [[ $(echo "if (${VERSION} == 1.5) 1 else 0" | bc) -eq 1 && $(echo "if (${SUBVERSION} < ${CUR15}) 1 else 0" | bc) -eq 1 ]] ; then
# версия 1.5.x, но не самая свежая из ветки
SHOWNEWEST="1.5.${CUR15}" ;
IMPORTANCE=2 ;
elif [[ $(echo "if (${VERSION} == 1.6) 1 else 0" | bc) -eq 1 ]] ; then
# версия 1.6 — рекомендовать 2.5
SHOWNEWEST="2.5.${CUR25}" ;
IMPORTANCE=2 ;
elif [[ $(echo "if (${VERSION} == 1.7) 1 else 0" | bc) -eq 1 ]] ; then
# версия 1.7 — рекомендовать 2.5
SHOWNEWEST="2.5.${CUR25}" ;
IMPORTANCE=2 ;
elif [[ $(echo "if (${VERSION} > 1.7) 1 else 0" | bc) -eq 1 && $(echo "if (${VERSION} < 2.5) 1 else 0" | bc) -eq 1 ]] ; then
# версия между 1.7 и 2.5
SHOWNEWEST="2.5.${CUR25}" ;
IMPORTANCE=2 ;
elif [[ $(echo "if (${VERSION} == 2.5) 1 else 0" | bc) -eq 1 && $(echo "if (${SUBVERSION} < ${CUR25}) 1 else 0" | bc) -eq 1 ]] ; then
# ветка 2.5, но не самая свежая
SHOWNEWEST="2.5.${CUR25}" ;
IMPORTANCE=1 ;
elif [[ $(echo "if (${VERSION} >= 3) 1 else 0" | bc) -eq 1 && $(echo "if (${VERSION} < 3.2) 1 else 0" | bc) -eq 1 ]] ; then
# версия 3.0 или 3.1 — рекомендовать 3.2
SHOWNEWEST="3.2.${CUR3}" ;
IMPORTANCE=2 ;
elif [[ $(echo "if (${VERSION} == 3.2) 1 else 0" | bc) -eq 1 && $(echo "if (${SUBVERSION} < ${CUR3}) 1 else 0" | bc) -eq 1 ]] ; then
# версия 3.2, но минорная сборка ниже текущей
SHOWNEWEST="3.2.${CUR3}" ;
IMPORTANCE=1 ;
else
ISOK=1 ;
echo "[INFO] version $VERSION.$SUBVERSION in $D is ok." ;
fi
else
# похоже, это не Joomla
ISOK=1 ;
fi ;
if [[ $ISOK -eq 0 ]] ; then
echo "[WARN] outdated Joomla version $VERSION.$SUBVERSION in $D" ;
if [[ "$OUTFILE" != "" ]] ; then
# записать в CSV
echo "\"$D\";$VERSION.$SUBVERSION;$SHOWNEWEST;$IMPORTANCE" >> $OUTFILE ;
fi
fi
done
exit 0 ;Пример вывода
[INFO] version 1.5.26 in /var/www/xxx is ok. [WARN] outdated Joomla version 1.0.12 in /var/www/yyy [WARN] outdated Joomla version 1.5.14 in /var/www/zzz [WARN] outdated Joomla version 2.5.8 in /var/www/aaa [WARN] outdated Joomla version 1.5.10 in /var/www/bbb
Если вы указали имя CSV-файла при вызове, он будет содержать строки вида:
“/var/www/yyy”;1.0.12;1.5.26;3
Где последний столбец — условный индекс важности (чем больше — тем критичнее обновление).
Что делать после обнаружения устаревших установок
- Оцените критичность: публичный сайт, административная панель доступна извне, использует ли сайт плагины с уязвимостями.
- Если возможно — выполните резервное копирование файлов и базы данных перед обновлением.
- Для больших различий между ветками (например, 1.5 → 2.5 или 3.x) изучите документацию по миграции: просто обновить может быть недостаточно — часто требуется перенос данных и тестирование.
- Для быстро устраняемых уязвимостей ищите security-патчи или временные обходы (удаление уязвимого компонента, отключение модулей).
Важно: не обновляйте «вживую» без тестовой среды, если сайт критичен для бизнеса.
Альтернативные подходы и инструменты
- Netcraft, Wappalyzer, WhatWeb — позволяют определить CMS по HTTP-ответам, но могут ошибаться.
- Использовать автоматизированные сканеры уязвимостей (Nessus, OpenVAS) для оценки рисков, но они требуют настройки и дают много «шумных» результатов.
- Управляемые решения: панели хостинга (cPanel/ISPConfig) иногда предоставляют централизованный список версий.
Преимущество данного файлового подхода — он локален, не зависит от внешних HTTP-заголовков и работает без запуска сайта.
Когда метод не сработает (примеры)
- Если файловая структура модифицирована владельцем сайта и файлы версий переименованы или удалены.
- Если сайт — кастомная сборка на базе Joomla с изменёнными путями.
- Для Mambo (старый форк) скрипт не различает Mambo и помечает их как OK. Это известное ограничение.
Чеклист для администратора (role-based)
- Системный администратор:
- Убедиться в наличии bc и sed.
- Запустить скрипт с правами, достаточными для чтения сайтов.
- Просмотреть CSV-отчёт, сортировать по важности.
- DevOps/разработчик:
- Подготовить тестовую среду и план миграции для критичных сайтов.
- Проверить плагины и расширения на совместимость.
- Менеджер проекта/владелец сайта:
- Утвердить окно технического обслуживания.
- Принять решение об обновлении или о переносе в новую ветку CMS.
Мини-руководство по миграции (high-level)
- Создайте резервную копию файлов и БД.
- Разверните копию на тестовом сервере.
- Обновите расширения, отключите неподдерживаемые плагины.
- Последовательно обновите Joomla по официальной инструкции (межшаговые обновления, если требуется).
- Протестируйте функциональность и производительность.
- Запланируйте перенос на продакшн при подтверждённой работоспособности.
Ограничения и известные проблемы
- Скрипт читает только файлы в заранее известных местах. Если версия хранится иначе — результат может быть некорректным.
- Mambo не распознаётся корректно — потребуется отдельная логика.
- Сложные кастомные миграции требуют ручной работы и проверки.
Рекомендации по безопасности
- Регулярно сканируйте серверы и обновляйте CMS и плагины.
- Закрывайте доступ к административной панели (IP-ограничения, двухфакторная аутентификация).
- Минимизируйте набор установленных расширений — чем меньше кода, тем меньше возможных уязвимостей.
Краткое резюме
- Поиск по каталогу components и чтение файлов версии — надёжный и простой способ массово обнаружить установки Joomla.
- Скрипт помогает быстро получить список устаревших версий и подготовить план обновлений.
- Для миграции между крупными ветками требуются тестирование и подготовка.
Коротко: запуск joomlascan.sh даст вам показательный список потенциально уязвимых сайтов и облегчит приоритизацию работ по обновлению.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента