Началась данная история довольно прозаично. Один из клиентов начал жаловаться, что на его сайте, работающем на CMS Битрикс, постоянно слетают то настройки модулей, то вообще сайт перестает работать с «выплевыванием ошибок» там, где они быть не должны. Сменил клиенту пароли, восстановил сайт из ночного бекапа и спокойно занялся своими делами, списав ситуацию на обычную компроментацию паролей и вандализм.
Но не через несколько часов симптомы повторились вновь, причем были в случайных местах затерты куски PHP кода, что давало основание полагать, что сайт пытаются выключить намеренно. Выводы кому же понадобилось потушить типичный государственный сайт небольшого поселения с посещаемость 5-6 человек в день оставим сотрудникам компетентых органов, я же расскажу вкратце для новичков как действовать в этом случае.
1) Смотрим на 2ip.ru либо другом подобном сервисе свой внешний ip адрес, а также просим всех администраторов сайта прислать ip, с которых они сейчас подключены к интернету. Тут правило простое — обращение к административным папкам 1С-Битрикс должно идти только с этих адресов.
2) Открываем файл журнала доступа вебсервера, для вебсервера apache он как правило лежит на сервере по пути /var/log/apache2/access.log. Ищем запросы файлов админки с адресов, не принадлежащих администраторам сайта. В моем конкретном случае меня смутила данная строчка:
xxx.xxx.xxx.xxx - - [xx/xx/2015:xx:xx:xx +0300] "POST /bitrix/admin/htmleditor2/bitrix_log.php HTTP/1.0" 200 4 "http://xxxxxxxxxxxxx/bitrix/admin/htmleditor2/bitrix_log.php" "Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0"
Здесь мало того, что доступ к файлу админки идет с IP-адреса, не присутствующего в списке из первого пункта, но еще и к файлу, которого изначально в поставке CMS Битрикс нет! Когда работаете с логами и файлам, желательно разверните отдельно эталонную копию CMS, на которой работает сайт, чтобы можно были сравнивать файлы на предмет изменены ли они или нет.
3) Открываем файл /bitrix/admin/htmleditor2/bitrix_log.php. Глазам предстает следюущая мешанина символов:
<?php
$auth_pass = "b1248f5dde2d214b74ef121288b61801";
$color = "#df5";
$default_action = 'FilesMan';
$default_use_ajax = true;
$default_charset = 'Windows-1251';
$o='HZzFksNKuoQ';//В ЭТОЙ ПЕРЕМЕННОЙ 20 страниц "ГОВНОСИМВОЛОВ", СОКРАТИЛ ЕЕ ДЛЯ УДОБСТВА ПОНИМАНИЯ
//eval("x65x76x61x6Cx28x67x7Ax69x6Ex66x6Cx61x74x65x28x62x61x73x65x36x34x5Fx64x65x63x6Fx64x65x28x24x6Fx29x29x29x3B");
функцию eval(), которую злоумышленник пытался спрятать за кучей «говносимволов», я сразу закомментировал.
В принципе для рядовых админов можно было просто удалить данный файл, сделать поиск функции eval по остальным скриптам и где ее не должно быть — удалить и закончить свои исследования. Но я решил посмотреть, что же данное произведение народного творчества делает с сайтом и сервером.
Сначала обращаем внимание на строку:
eval("x65x76x61x6Cx28x67x7Ax69x6Ex66x6Cx61x74x65x28x62x61x73x65x36x34x5Fx64x65x63x6Fx64x65x28x24x6Fx29x29x29x3B");
HEX символозаменители видны невооруженным взглядом. Превратить их в удобочитаемый невооруженным взглядом текст поможет любой HEX декодер, я пользовался этим.
После скармливания декодеру брюки символы превращаются:
eval(gzinflate(base64_decode($o)))
в элегантные семейные трусы выполнение кода, который декодируется и разархивируется из переменной $o (которая и содержит «говносимволы», а точнее содержит просто заархивированную информацию). Разработчик данного творения очень постарался защитить его от деобфускации, а именно при адльнейшей попытке дешифровать перменную $o снова натыкаемся eval(gzinflate(base64_decode([КУЧА «ГОВНОСИМВОЛОВ»]))). Но и это можно обойти.
Код был немного переписан, после мешанки из «говносимволов» добавляю код расшифровки:
$string = gzinflate(base64_decode($o));
после этого мы знаем что код циклически разархивирует сам себя и запускает разархивированный кусок, т.е. можно просто пройти тот же цикл но не выполняя код, а сбрасывая в какую-нибудь из переменных до полной разархивации. т.к. в каждой «итерации» архива код содержит начальную строку eval(gzinflate(base64_decode( после того как в разархивированном варианте не будет данной строки можно останавливать цикл. Распакованный код сливаем в какой нибудь файл для последующего анализа.
Вот реализация данного кода на PHP:
while (substr_count($string,"eval(gzinflate(base64_decode(")>0) {
$string = str_replace("eval(gzinflate(base64_decode('","",$string);
$string = str_replace("')));",");",$string);
$string =gzinflate(base64_decode($string));
}
file_put_contents("unpacked.dat",$string);
После окончания работы скрипта открываем unpacked.dat и видим типичный php шелл (каких море) с файл менеджером и прочими «пряниками». На сервере сайт каждого клиента работает под правами пользователя данного клиента, которые довольно сильно урезаны, плюс запрещена команда exec(). Поэтому злоумышленник глумился только над этим сайтом и не смог подлезть к остальным.
Да и метод обфускации своего шелла он выбрал не очень удачный — функция eval в битриксе используется довольно редко, и данный шел по этой функции очень легко отыскать, плюс «говносимволы» сразу наводят на подозрение. Из за этого шелл выделяется в общей структуре сайта как клоун на похоронах.
Путь попадания шелла также оказался весьма нетривиальным — раньше у клиента на сервере весело 2 копии сайта, одна из них была старым вариантом сайта на на старой и «дырявой как решето» версии Joomla. Эту версию сайта оставили для удобного переноса контента на новый сайт. В этот момент через дыру в Joomla и был загружен шелл (сайты располагались под одним пользователем в соседних папках).
Поэтому я всегда старые версии сайтов размещаю на отдельной виртуалке, которую не жалко. Что и вам советую.
Автор: MatasDragonV