WordPress — одна из самых популярных CMS, давно выросшая из обычного блогового движка в конструктор, позволяющий создать веб-ресурс практически любого назначения. На нем работают интернет-магазины, форумы, каталоги, веб-хостинги, сайты поддержки пользователей и многое другое. В то же время популярность имеет и обратную сторону: сайт на WP атакуют постоянно, и если тебя еще не взломали, то только потому, что просто еще не нашли среди миллионов других подобных ресурсов.

 

Тревожный сигнал

Несмотря на то что WordPress развивается уже достаточно давно и код все время анализируется, уязвимости в движке находят постоянно, и можно предположить, что продолжат находить и в будущем. Нужно отдать должное разработчикам: они оперативно реагируют на все сообщения и устраняют проблемы, а простота обновления позволяет администраторам легко обезопасить свой ресурс. Хотя анализ показывает, что далеко не все спешат обновляться. Но вот основные проблемы безопасности WP не в самом движке. Сегодня доступно большое количество тем и плагинов, которые пишутся программистами разного уровня и нередко содержат уязвимости. Некоторые темы и плагины распространяются через сомнительные сайты и уже изначально могут содержать бэкдоры. Добавим сюда некорректные настройки сайта, неверные права и использование учетных записей по умолчанию, позволяющие атакующему спокойно подбирать пароли, — и без дополнительных мер защиты сайт на WP обречен.

Итак, имеем несколько сайтов на WP разного назначения, размещенных в VDS. Стандартная связка PHP5 + Apache 2 + MySQL. ОС Ubuntu 14.04.3 LTS. Также были установлены панель управления хостингом Vesta Control Panel и phpMyAdmin. Последним, впрочем, никто не пользовался, и, по-моему, о его существовании даже не знали, хотя журналы показали, что и то и другое тоже пытались взломать. На момент атаки движок блога, активные плагины и Vesta были обновлены до актуального состояния. Используемые темы в большинстве взяты из бесплатного каталога и подогнаны под свои условия. Бэкап SQL делался еженедельно, бэкап файлов — очень давно. Все это работало до поры до времени.

Первый сигнал поступил от MySQL. VDS, до этого не сильно нагруженный, перестал тянуть. В результате сервер баз данных просто отвалился, а вместе с ним и прекратили отвечать сайты. При этом количество посетителей на счетчике вписывалось в стандартную посещаемость. Перезапуск восстановил работу, но нагрузка, показанная htop, была очень высокой.

Следующий сигнал поступил от поисковых систем. Причем сообщения и, очевидно, алгоритмы работы у Яндекса и Google отличаются и по-разному полезны. Яндекс сообщил, что на сайте обнаружен вредоносный контент, в панели веб-мастера сайт был помечен соответствующим значком, указан предполагаемый тип (троян JS), и в поиске выводилась информация о том, что ресурс может навредить. Сразу скажу, что код, который раздражал Яндекс, был найден в файле заголовков почти всех тем в файле header.php, и после того, как он был убран, все сайты в течение одного-трех дней были признаны чистыми. Хотя в это время битва еще продолжалась.

Google прислал сообщение спустя шесть часов после Яндекса, но отметил, что на сайте обнаружен «взломанный контент», в панели можно было просмотреть список подозрительных файлов (на момент получения письма большинство было найдено и удалено). Информация сама по себе интересна, так как в ней указаны новые файлы, оставленные хакером, на которые нет прямых ссылок на сайте. Такие файлы, скорее всего, однозначно нужно будет удалять. Гугл в сообщении предлагает ссылку на «Инструмент для восстановления взломанных сайтов», позволяющий просмотреть, как выглядит сайт, и рекомендации. После удаления файлов необходимо вручную отправить на перепроверку те сайты, у которых при использовании site: в строке поиска показывает «Возможно, этот сайт был взломан». Позже Гугл убрал отметку об опасности части сайтов и начал выдавать сообщение о том, что на сайтах появилось большое количество ошибок. Проблема 404 возникла либо из-за некорректно внедренного кода, когда часть URL не работала, либо из-за того, что код ссылался на вредоносный файл, который уже был найден и удален.

Забегая вперед, скажу о результате. Атака шла с нескольких IP и массированно началась за три дня до взлома. Обнаружилось большое количество лишних файлов с расширением php, которые были разбросаны по всем каталогам, плюс каталог gopni3d с кучей HTML-файлов внутри. Здесь и шелл, и бэкдор-загрузчик, и дорвей, и рассыльщик спама. Внедрен PHP- и JS-код в тему header.php и некоторые файлы WP, включая wp-config.php. Изменен файл .htaccess. В WP появились две дополнительные учетные записи с правами администратора. Каталог SMTP-сервера /var/spool/exim4/input был завален большим количеством спам-писем.

Теперь разберем, как это все найти, потратив минимальные усилия и имея минимум знаний. Дальнейшие шаги понятны: найти чужой код, понять действия хакера, устранить уязвимости или снизить их количество, затруднить дальнейшие атаки. Все это нужно будет делать быстро и параллельно.

Код, оставленный хакером
Код, оставленный хакером
 

Первые шаги

Можно отключить сайт, остановив веб-сервер или переведя WP в режим обслуживания, но мы пока не знаем, что искать. Если отключить невозможно, то на этом этапе можно запретить регистрацию новых пользователей и комментарии, изменить пароли администратора WP и пароли к СУБД. При наличии свежего бэкапа можем восстановить сайт, затем перейти к анализу и заняться локализацией проблем и усилением защиты. Иначе придется чистить файлы вручную. Как минимум можно сразу заменить файлы WP новыми из архива, удалив предварительно старые файлы и каталоги (кроме, естественно, каталогов тем, плагинов и upload). Далее обновляем (если не сделали это раньше) движок, тему и плагины. Неактивные темы и плагины безоговорочно удаляем. Проверяем сами плагины. Хакер некоторые просто отключает, изменив название каталога (добавив знак подчеркивания в начало). Проверяем корректность файлов .htaccess, их содержимое хакер может просто обнулить. Если файл .htaccess был неправильно настроен, то к файлам сайта можно получить доступ из поисковика: site:example.org inurl:/wp-admin/. Переименуй тему, некоторые атаки идут пакетом, когда просто подбираются уязвимости к популярным темам. Переименовав тему, мы изменим URL, а значит, такая атака ее минует. Если до сих пор не использовалась капча, то ставь любой понравившийся плагин. Это снизит вероятность брутфорса. Некоторые к тому же предоставляют дополнительные возможности: блокировку IP в случае неправильного ввода несколько раз, ограничение по времени ввода, белый список. Проверять на зараженность можно как изнутри при помощи инструментов, доступных в ОС, так и через внешние сервисы. Запускаем антивирусную проверку.

$ sudo clamscan -i -r /var/www
/var/www/wp-content/plugins/akismet/_inc/img/sidebar-widescreen.php.suspected: Php.Malware.Agent-1426825 FOUND

Кроме антивируса, можно прогнать еще сканер Linux Malware Detect и скрипт AI-Bolit. Но найдут они не все.

Первые данные от внешних сервисов уже есть. Гугл выдал подсказку, просто ищем файлы, проверяем, действительно ли они вредоносны, и удаляем. Для последующего поиска сохраняем небольшой специфический текст, который будем использовать в качестве сигнатуры. Анализ самого кода позволит получить IP, URL и другие специфические параметры, их будем искать в логах и блокировать с помощью файрвола.

В Сети доступно множество ресурсов, проверяющих, безопасны ли сайты. Не все они полезны. Некоторые, например, просто получают данные о вредоносности от API Яндекса и Гугла. Услугу проверки URL предлагают и производители антивирусов. Например, сканер от Dr.Web проверяет страницы и анализирует, есть ли редирект на другие сайты. К сожалению, кроме того, что сайт заражен, и типа вируса, больше никакой полезной информации он не дал. Ресурс 2ip.ru показал, что на сайте обнаружены iframe-вставки. К сожалению, для повторной проверки он бесполезен, так как, очевидно, запоминает результат и сообщает, что сайт заражен, когда все остальные уже считают его безопасным.

Наибольшую пользу в поиске принес онлайн-сканер SiteGuarding.com, специально разработанный для поиска специфических вредоносных программ. В отчете были не только показаны проблемные ссылки, но и дана конкретика, позволяющая в дальнейшем найти этот код в файлах при помощи grep. Проект предлагает и свой плагин WP Antivirus Site Protection, доступный из каталога плагинов WP. В бесплатной версии он сканирует файлы, проверяя их на наличие опасного кода, и выдает отчет по обнаруженным malware и файлам, показавшимся подозрительным эвристическому анализатору. Правда, выданное не стопроцентно проблема, но это уже что-то. Число сканирований ограничено, но этого достаточно, чтобы решить проблемы и некоторое время контролировать ситуацию.

Отчет плагина об обнаруженном malware
Отчет плагина об обнаруженном malware

Полученную на SiteGuarding.com информацию о коде малвари скармливаем grep. Принцип простой: берем некий уникальный кусок (например, там указан URL сайта, на который идет редирект, или имя файла) и пробуем найти этот текст в остальных файлах веб-сайта.

$ grep -iR example.org /var/www/

Если при ручной разборке будут попадаться зараженные файлы, то анализируем и небольшой кусок уникального текста также предлагаем grep для поиска других аналогичных файлов. Код в файлы сайта вставляется либо в начало, либо в конец, и он, в отличие от остального, плохо структурирован, то есть идет сплошной массой. Это сразу бросается в глаза в любом текстовом редакторе, особенно с подсветкой кода. Но бывает, код специально отбивают за пределы видимой части экрана вправо или вниз. Можно составить небольшой скрипт, чтобы сразу вырезать кусок кода. Правда, остатки потом найти будет сложнее. Например, в decode использована последовательность HtI9Opn...Z. Создаем такой скрипт:

$ nano virusdel.sh
#!/bin/bash
virus='eval(base64_decode("HtI9Opn.*Z=="));'
find . -type f -name '*.php' -exec sed --in-place -e "s/$virus//g" '{}' \;

Запускаем:

$ chmod +x virusdel.sh
$ ./virusdel.sh

Найденное имя файла сразу проверяем на остальных подкаталогах и сайтах при помощи find.

$ find /var/www/ -name confg.php

Время доступа к файлам не всегда выдает его модификацию, но вот различие в размерах файла и количестве файлов в каталоге по сравнению с оригинальным бросается в глаза сразу. И мы можем легко сравнить два каталога при помощи diff или вручную, открыв два окна в mc. Самый простой diff -aqr dir1 dir2 покажет только отличающиеся файлы без самих изменений, полный diff -ruN > out.diff выдаст информацию в стиле patch. Внутри каталогов обнаружилось большое число лишних PHP-файлов, некоторые называются похоже на файлы WP или так же, но лежат в другом каталоге. Например, class-wp-*.php, wp-config .php (с пробелом). А также всякие users.php, confg.php, about.php и случайные имена (вроде a249yh.php, их легко заметить).

Каталог /var/spool/exim4/input был буквально забит спам-сообщениями. Количество сообщений в очереди, выведенное exim -bpc, достигало нескольких тысяч. Вывод ps aux показывал процесс sendmail, пытавшийся отправить письмо от неизвестного пользователя с доменом сайта. Чтобы не рассылать спам, SMTP-сервер лучше пока остановить. При попытке очистить командой rm -rf /var/spool/exim/input/* bash вываливался с ошибкой из-за большого количества файлов. Можно использовать маску и удалять файлы по частям, но в случае с exim проще ввести

$ sudo exipick -i | xargs exim -Mrm
 

Права доступа

Далее следует пересмотреть права доступа — ужесточить их по максимуму. Это позволит остановить атаку, не дав хакеру продолжать модифицировать файлы. Потом можно будет вернуть нормальные права.

$ sudo chmod 400 wp-config.php

Для быстрой смены можно использовать find. Например, установим для всех файлов 644:

$ sudo find . -type f -exec chmod 644 {} +

Если меняем каталоги, то используем -type d. Также проверяем командой ls -al, кто владелец файлов. В Ubuntu/Debian обычно это www-data:www-data, но если используется панель администрирования, то будет, скорее, admin:www-data. Это тоже нужно учитывать при выставлении прав и при использовании специальных плагинов, которые могут помочь, а могут сделать сайт нерабочим.

Для проверки корректности прав можно использовать плагин Acunetix WP Security, который, кроме этого, умеет переименовывать учетную запись Admin, бэкапит базу, изменяет префикс таблиц wp_, усложняя XSS-атаку, показывает в онлайн-режиме текущую активность на сайте (включая Lookup IP), убирает некоторые заголовки и вывод отладочной информации и дает информацию для усиления защищенности.

Плагин Look-See Security Scanner верифицирует основные файлы WP, показывая отличия, проверяет конфигурацию, ищет спрятанные скрипты в основных каталогах, показывает информацию об известных уязвимостях в плагинах и темах. На самом деле подобных плагинов много, можно найти и другие, более удобные. Но увлекаться тоже не стоит: каждый лишний плагин — это еще одна потенциальная лазейка.

 

Смотрим логи

Журналы веб-сервера, МySQL и системные — просто кладезь информации по свалившейся проблеме. Изучая их, мы должны попытаться получить ответы на вопросы: что именно произошло, кто атакует и где искать проблему. В зависимости от настроек в логах возможна разная детализация данных, но обычно установок по умолчанию вполне достаточно, чтобы ухватиться за ниточку. Вероятно, найти ответ, как именно проникли, в большом объеме сразу не получится, так как, скорее всего, атака будет идти большим потоком, но некоторые выводы все равно можно сделать. Если была настроена система мониторинга, за точку отсчета можно взять увеличение нагрузки на узел и рост сетевого трафика. Как правило, с некоторого момента графики идут вверх. Ответ на вопрос, что произошло, ищем до этого времени, проблемные места — после. Начинать, конечно, нужно с логов веб-сервера. Журналы смотрим как вручную, так и при помощи различных инструментов. Первый способ медленнее, но мы не пропустим нужное, второй способ позволяет увидеть ситуацию в общем. В начале атаки в логах можно увидеть множество запросов вроде

GET /wp-admin/admin-ajax.php?action=getfile&/../../wp-config.php

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

POST /wp-content/themes/default/user.php

Именно так отдаются команды. Такие файлы нужно проверять, удалять или чистить. IP, с которых идет атака, анализируем вживую:

$ tail -f /var/log/apache2/access.log | grep <IP-адрес>
$ cat /var/log/apache2/access.log | grep <IP-адрес>

И отправляем на блокировку iptables. Ищем в логах обращения к «запрещенным» файлам и каталогам сайта (wp-config.php, wp-admin, wp-login.php, .htaccess). Также проверяем все запросы, содержащие слова: mysql, function, connect, base64_decode, document.write, DOCUMENT_ROOT и так далее. Ничто не мешает составить команды для быстрого отбора нужных данных.

Например, выведем только IP и URL, к которым они получали доступ, подсчитаем и рассортируем:

$ cat /var/log/apache2/access.log | awk '{print $1" "$7}' | sort | uniq -c | sort -rg

Вставив перед вызовом awk grep -i POST, можем отобрать только POST-запросы. Если добавить в конец команды | grep wp-login.php, мы увидим, сколько раз с IP пытались подключиться к определенному URL.

Отбираем явных брутфорсеров
Отбираем явных брутфорсеров

Аналогично можем отследить ошибку 404, при нормальной работе их процент минимален. Рост в начале атаки свидетельствует не только о том, что кто-то пытается найти то, чего нет, а в конце атаки говорит о нарушении работы сайта из-за поломанных скриптов. Соответственно, когда ошибок 404 станет меньше, это значит, что от сайта отстали. Просмотреть общее количество ответов сервера с разным статусом можно так:

$ cat /var/log/apache2/access.log | awk ' { print $9 } ' | sort | uniq -c

Для заархивированных логов вместо cat используем zcat. В зависимости от настроек журналирования придется чуть поэкспериментировать с запросами, но такая небольшая автоматизация значительно сокращает время на общий анализ.

Также можно использовать в работе многочисленные программы для анализа логов веб-серверов. Например, утилита GoAccess позволяет строить самые разные отчеты как в интерактивном виде, так и генерируя HTML/JSON/CSV-файл. С его помощью можно быстро обнаружить аномалию, не прибегая к самостоятельному построению запроса.

$ sudo apt install goaccess

В самом простом случае указываем файл. При запуске понадобится подобрать формат журнала сервера.

$ goaccess -f /var/log/apache2/access.log

В результате получаем интерактивную таблицу с процентом уникальных посетителей, топ URL, запросы 404, IP хостов и так далее. Чтобы раскрыть секцию полностью, следует нажать соответствующую ей цифру (shift + 0–1 для 11–20 секций) и букву O. Чтобы закрыть, нажимаем q. При необходимости можно комбинировать запуск GoAccess с grep, awk, sed и прочим. Например, получим список IP, которые стучатся в админку, и сохраним его в файл.

$ grep -i wp-login.php /var/log/apache2/access.log | goaccess -a > report.html

Меняем на wp-config.php и смотрим, кто пытается получить этот файл.

Собираем IP атакующего при помощи GoAccess
Собираем IP атакующего при помощи GoAccess

В Win можно использовать Apache Logs Viewer — очень наглядный инструмент, который подсвечивает разным цветом запросы с разным статусом, показывает страну источника и позволяет быстро фильтровать, отбирать и сортировать данные, строить отчеты.

В контексте журналов хотелось бы упомянуть еще один плагин iThemes Security, который имеет много полезных функций: отслеживание 404, защиту от брутфорса (блокировка через .htaccess), контроль изменений файлов, блокировку записи основных файлов, бэкап базы данных, бан-лист, подстройку защитных функций и много другого. Но самое полезное — это вкладка «Логи», в которой выводятся отчеты по 404, блокировки, IP, пытавшиеся залогиниться. Причем выводится сразу и логин, с которым пытаются подключиться, что само по себе полезно, в логах Apache нет этой информации. То есть не нужно искать все это в журналах веб-сервера, а все на виду.

Атака в логах веб-сервера
Атака в логах веб-сервера
 

Пользователь «Администратор»

Журнал iThemes Security показал большое количество попыток подключения с логином admin с разных IP, поэтому стоит переименовать эту учетную запись (если это не сделано при установке блога) вручную в базе данных при помощи SQL-запроса или при помощи плагинов. Также стоит для повседневной работы завести отдельную учетную запись с меньшими правами (роль редактора или автора), использовав роль администратора только при обслуживании движка. Это уменьшит вероятность слить данные при появлении очередной уязвимости. Используя уязвимости, атакующий попробует создать учетную запись с ролью администратора. Поэтому следует сразу посмотреть во вкладке «Пользователи», применив фильтр wp-admin/users.php?role=administrator. Проблема в том, что все пользователи в этой вкладке не будут отображены. Так, счетчик показывал три записи, но выводилась только одна.

Информация о логинах и ролях хранится в двух таблицах: wp_users и wp_usermeta. Смотрим имя базы данных в wp-config.php. Заходим в консоль MySQL и выбираем базу:

$ MYSQL -uadmin -p
mysql> USE database;

Выводим список ролей:

mysql> SELECT * FROM wp_usermeta WHERE meta_key LIKE "wp_capabilities";

Нас интересуют те user_id, у которых значение wp_capabilities установлено в a:1:{s:13:"administrator";b:1;}.

Пользователи с ролью administrator, созданные хакером
Пользователи с ролью administrator, созданные хакером

Проверяем имя:

mysql> SELECT * FROM wp_users WHERE ID = 1024;

Удаляем:

mysql> DELETE FROM wp_users WHERE ID = 1024;

Обычно нет необходимости, чтобы MySQL веб-сайта был доступен из Сети. Проверяем порт:

$ netstat -ant | grep 3306
tcp    0    0 0.0.0.0:3306    0.0.0.0:*    LISTEN

Если получаем такой результат, то правим /etc/mysql/my.cnf, добавив туда строку skip-networking или bind-address = 127.0.0.1, и перезапускаем MySQL.

Дополнительно можно прикрыть порт MySQL файрволом:

$ sudo iptables -I INPUT -d 127.0.0.1/8 -j ACCEPT
$ sudo iptables -A INPUT -p tcp --dport 3306 -j DROP
 

Настраиваем файрвол

Лучше всего остановить атаку на приложение, совсем не дав атакующему к нему подключиться. Все найденные в логах IP, с которых ведутся подозрительные действия, скармливаем iptables:

$ sudo iptables -I INPUT -s 148.251.105.254 -j DROP

Не забываем выполнить iptables-save, чтобы сохранить их после перезагрузки. Перед блокировкой следует обязательно проверять IP, чтобы не забанить ботов поисковых систем. Посмотреть правила и статистику можно при помощи команды iptables -L -n -v. Конечно, вручную все время отслеживать и добавлять новые правила сложно, эту операцию лучше немного автоматизировать. Поручим разбираться с атакующими fail2ban.

$ sudo apt install fail2ban

Правила для WP нет, но, проанализировав логи, простейшее легко составить самому. Например, попытки подбора пароля в файле логов выглядят так:

31.210.35.218 - - [02/Apr/2016:11:04:27 +0300] "POST /wp-login.php HTTP/1.0" 200 4395 "-" "-"

Для блокировки создаем новый фильтр:

$ sudo nano /etc/fail2ban/filter.d/wp-auth.conf

[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreregex =

Создаем /etc/fail2ban/jail.local (в jail.conf лучше не писать, так как он перезапишется при обновлении):

[wp-auth]
enabled  = true
port     = http,https
filter   = wp-auth
logpath  = /var/log/apache2/*.log

Проверяем, есть ли совпадения (matched):

$ sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wp-auth.conf

Если все нормально, отдаем в работу. Перезапускаем сервис:

$ sudo service fail2ban restart

Аналогичным образом создаем правила и для других ситуаций.

 

Вывод

Битва за сайты продолжалась фактически три дня. Шаг за шагом усиливая защиту и блокируя подозрительные IP, удалось локализовать проблему. На самом деле защитить WP вполне возможно — достаточно просто придерживаться хотя бы минимальных рекомендаций, постоянно уделять внимание журналам. И не забывай про бэкапы!

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    5 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии