Современные хакеры редко “дефейсят” взломанные сайты, как правило, внедряют сторонний код в скрипты для осуществления дальнейших зловредных действий.
Как часто вы тратили часы, выискивая код, внедрённый в ваши скрипты, после атаки?
Некоторое время назад меня привлекли к администрированию десяти сайтов, расположенных на одном виртуальном хостинге. Сайты крутились на “полуразложившихся” движках, написанных в 2000-2003 годах. Сайты постоянно падали под натиском “скрипт-кидди” и изобиловали внедрёнными “зловредами”. Мои задачи были тривиальны: поддержать работу сайтов, перенести на новые движки или залатать дыры в старых движках.
Всё предельно просто, но в полевых условиях было необходимо анализировать текущее состояние файлов, чтобы не дать возможности внедрить код ни в один из сайтов, так как получение доступа к одному сайту на виртуальном хостинге ставило под прицел и сайты, уже перенесённые на новые версии движков. Реагировать на внедрение кода нужно было молниеносно, а проверять файлы вручную при наличии тысяч файлов не представлялось возможным.
В процессе работы родилось очень простое решение, которым я и хочу поделиться. Хочу оговориться, что данное решение простое и не претендует на гениальность и полноту реализации, но надеюсь, что будет кому-то полезно.
Алгоритм работы скрипта прост, он рекурсивно проходит все директории и файлы, начиная с директории, указанной при конфигурации и выводит список файлов, изменившихся за указанный промежуток времени. Вот и всё!
Пользоваться будем следующими функциями:
scandir()
stat()
Данные будем выводить в два столбца таблицы:
Дата модификации
Путь к файлу
Перед запуском необходимо провести небольшую конфигурацию нашего скрипта, переменной $start_folder задать значение, равное пути к каталогу, с которого мы начнём сканирование.
Скрипт поддерживает некий аналог фильтрации, если вам необходимо проигнорировать некую директорию при сканировании, вы можете передать необязательный параметр $filter — массив названий папок. Сканирование папок из массива производиться не будет.
При запуске мы можем указать GET параметр days=n, чтобы вывести изменённые файлы за n дней.
Простейшая реализация имеет огромное количество недостатков и неудобств, для меня одним из основных недостатков стало отсутствие общей сортировки по дате модификации файла. Данную проблему можно решить путём доработки скрипта, но проще мне показалось решение с подключением jQuery плагина TableSorter. Сканер работает достаточно долго, если файлов много, дальнейшая сортировка на стороне сервера требовала бы дополнительного времени и ресурсов, а jQuery позволяет сортировать таблицу на стороне клиента.
Для этого необходимо подключить плагин TableSorter, добавить нашей таблице следующие id и class.
Привязать к нашей таблице обработчик.
Можно автоматизировать процесс полностью, дописав отправку отчёта на электронную почту и запуская сканер через Cron по расписанию.

Надеюсь, моя статья будет полезна начинающим веб разработчикам и даст пищу для размышлений.
Update: Как правильно замечено в комментариях полагаться на дату изменения файла нельзя, так как команда touch() позволяет модифицировать дату.
В работе я использую функционал, встроенный в IDE PHP Storm — синхронизацию локального проекта и удалённого FTP сервера, особых знаний и умений это не требует и отлично подойдет начинающим разработчикам, изменения в файлах выводятся очень наглядно и удобно.
Как часто вы тратили часы, выискивая код, внедрённый в ваши скрипты, после атаки?
Некоторое время назад меня привлекли к администрированию десяти сайтов, расположенных на одном виртуальном хостинге. Сайты крутились на “полуразложившихся” движках, написанных в 2000-2003 годах. Сайты постоянно падали под натиском “скрипт-кидди” и изобиловали внедрёнными “зловредами”. Мои задачи были тривиальны: поддержать работу сайтов, перенести на новые движки или залатать дыры в старых движках.
Всё предельно просто, но в полевых условиях было необходимо анализировать текущее состояние файлов, чтобы не дать возможности внедрить код ни в один из сайтов, так как получение доступа к одному сайту на виртуальном хостинге ставило под прицел и сайты, уже перенесённые на новые версии движков. Реагировать на внедрение кода нужно было молниеносно, а проверять файлы вручную при наличии тысяч файлов не представлялось возможным.
В процессе работы родилось очень простое решение, которым я и хочу поделиться. Хочу оговориться, что данное решение простое и не претендует на гениальность и полноту реализации, но надеюсь, что будет кому-то полезно.
Общий алгоритм работы сканера
Алгоритм работы скрипта прост, он рекурсивно проходит все директории и файлы, начиная с директории, указанной при конфигурации и выводит список файлов, изменившихся за указанный промежуток времени. Вот и всё!
Пользоваться будем следующими функциями:
scandir()
stat()
Данные будем выводить в два столбца таблицы:
Дата модификации
Путь к файлу
Код функции с комментариями:
function scan_tree ($folder, $period, $filter = NULL) { $files = scandir ($folder); // Получаем массив папок и файлов в текущей папке foreach ($files as $file) { // В цикле обходим все папки и файлы в дериктории if (($file == '.') || ($file == '..') || (is_array ($filter) && in_array ($file, $filter))) continue; // Пропускаем текущую папку, родительскую папку и папки из фильтруемых $item = $folder.DIRECTORY_SEPARATOR.$file; // Формируем полный путь к папке или файлу if (is_dir ($item)) { // Если текущий элемент - папка, то рекурсивно вызываем функцию сканирования scan_tree ($item, $period, $filter); } else { // Если текущий элемент - файл, то получаем информацию о файле $stat_info = stat ($item); if (time () - $stat_info['mtime'] < $period) { // Если дата изменения файла не старше заданного отрезка времени, то выводим новую строку в таблицу echo '<tr><td>'.date ("d-m H:i", $stat_info[9]).'</td><td>'.$folder.DIRECTORY_SEPARATOR.$file.'</td></tr>'; } } } }
Конфигурация
if (!empty($_GET['days'])) $days = intval ($_GET['days']); else $days = 1; // Получаем через GET отрезок времени $period = 86400 * $days; //Пересчитываем в секунды для сравнения с timestamp //$start_folder = 'D:\www\htdocs'; $start_folder = '/home/www/'; // Задаём начальную директорию сканирования $filter = array ('cache', 'logs.old', 'logs'); // Список фильтруемых папок, они будут игнорироваться при сканировании
Перед запуском необходимо провести небольшую конфигурацию нашего скрипта, переменной $start_folder задать значение, равное пути к каталогу, с которого мы начнём сканирование.
Скрипт поддерживает некий аналог фильтрации, если вам необходимо проигнорировать некую директорию при сканировании, вы можете передать необязательный параметр $filter — массив названий папок. Сканирование папок из массива производиться не будет.
При запуске мы можем указать GET параметр days=n, чтобы вывести изменённые файлы за n дней.
Запуск скрипта
<table> <thead> <tr> <th title="Дата изменения">Дата</th> <th title="Пути файла">Путь к файлу</th> </tr> </thead> <tbody> <?php scan_tree ($start_folder, $period, $filter); ?> </tbody> </table>
Возможные улучшения функционала
Простейшая реализация имеет огромное количество недостатков и неудобств, для меня одним из основных недостатков стало отсутствие общей сортировки по дате модификации файла. Данную проблему можно решить путём доработки скрипта, но проще мне показалось решение с подключением jQuery плагина TableSorter. Сканер работает достаточно долго, если файлов много, дальнейшая сортировка на стороне сервера требовала бы дополнительного времени и ресурсов, а jQuery позволяет сортировать таблицу на стороне клиента.
Для этого необходимо подключить плагин TableSorter, добавить нашей таблице следующие id и class.
<table id="data_table" class="tablesorter">
Привязать к нашей таблице обработчик.
$(document).ready(function () { $("#data_table").tablesorter(); } );
Можно автоматизировать процесс полностью, дописав отправку отчёта на электронную почту и запуская сканер через Cron по расписанию.
Результат работы сканера с плагином TableSorter

Надеюсь, моя статья будет полезна начинающим веб разработчикам и даст пищу для размышлений.
Спасибо и удачи!
Update: Как правильно замечено в комментариях полагаться на дату изменения файла нельзя, так как команда touch() позволяет модифицировать дату.
В работе я использую функционал, встроенный в IDE PHP Storm — синхронизацию локального проекта и удалённого FTP сервера, особых знаний и умений это не требует и отлично подойдет начинающим разработчикам, изменения в файлах выводятся очень наглядно и удобно.