Статьи Война на передовой в условиях шаред хостинга на базе WHM/Cpanel/RHE

Discussion in 'Статьи' started by w00d, 12 Jul 2005.

  1. w00d

    w00d [ The Godfather ]

    Joined:
    30 Jun 2005
    Messages:
    172
    Likes Received:
    22
    Reputations:
    4
    http://www.securitylab.ru/

    whice (RST/GHC)

    Особые благодарности:

    foster,edisan,Mik,blf,1dt.w0lf

    "Война на передовой в условиях шаред хостинга на базе WHM/Cpanel/RHE"

    Вступление

    Сегодня в условиях развития информационных технологий на рынке е-комерции особое внимание уделяеться таким видам е-бизнеса как "shared hosting". Этот сегмент рынка продолжает стремительно рости и из-за своей распространенности и прибыльности попадает в поле зрения злоумышленников различного уровня.

    Обеспечение безопасности "shared hosting" имеет свои особенности. Я постараюсь обрисовать особенности защиты при проникновении через apache/mod_php.

    Известно, что для построения эффективной системы защиты в первую очередь следует определить каким образом может действовать атакующий; какого вида угрозы могут иметь место и исходя из этого сделать выводы о целесообразности самой защиты.

    И так, рассмотрим стандартные методы проникновения в систему.

    Приблизительный план атакующего:
    поиск на сервере доменов, содержащих php скрипт с уязвимостью;
    использование скрипта для выполнения локальных команд (с уровнем nobody);
    заливка, запуск backdoor;
    вход через backdoor;
    повышение привилегий.

    Противодействие пунктам 1 и 5 не рассматриваются, так как предполагается, что дырявый скрипт уже найден, а также, что предполагаемые статьей мероприятия нацелены на действия, предотвращающие 5-ый пункт.

    Учитывая, что среднестатистический сервер на базе WHM (исходя из default установки которую мало кто меняет) использует php как модуль apache (safe_mode = Off ), запускаемые через уязвимый скрипт команды имеют уровень привилегий apache (пользователь nobody).

    Пример списка процессов:

    [root@redhat root]# ps -eo %p%u%a --forest
    ......
    23091root/usr/local/apache/bin/httpd -DSSL
    23092nobody\_ /usr/local/apache/bin/httpd -DSSL
    23093nobody\_ uname -a
    ......

    После определения возможности запускать програмы, атакующий попытаеться залить backdoor's, exploit's, bot's .... etc с целью получить полноценный shell, повысить уровень привелегий.

    Исходя из вышеопределенного - выводим следующий план противодействия:
    Установка noexec nosuid на директории свалок

    - ограничение директорий свалок (/tmp,/var/tmp) от запуска backdoor, bot и другой закачанной нечисти;
    Контроль выполняемых процессов

    - ограничение количества команд, выполняемых от пользователя nobody;
    Настройка firewall.
    Настройка cPanel(WHM)+apache+php.ini.

    Данные меры вполне способны нарушить план атакующего, и отпугнуть многих scriptkidies.

    Перейдем к непосредственному расмотрению пунктов нашего плана.

    1. Установка noexec nosuid на директории свалок (/tmp, /var/tmp).

    К сожалению, в предустановленном варианте /tmp раздел не всегда идет отдельным разделом, что открывает атакующему дополнительные возможности. Мы прикроем это следующим образом:

    - директории-свалки сделаем отдельными файлами и будем присоединять их через mount -o loop,noexec,nosuid;

    - будем проверять все директории-свалки и что-то делать с файлами с опастными правами (x, s). Этот пункт противодействия важен, так-как noexec ограничение на раздел возможно обойти;

    Разобьем первый пункт на подпункты:

    1.1 Определение директорий для контроля

    1.2 Создание файл-разделов.

    1.3 Проверка работы noexec,nosuid.

    1.4 Обход ограничения noexec

    1.5 Скрипт для дополнительной защиты.

    1.1 Определение директорий для контроля

    Определяем, для каких директорий будут создаваться файл-разделы. Обычно это /tmp, /var/tmp .

    Для поиска директорий имеющих права запись/выполнение/чтение для всех + sticky bit (1**7) . можно использовать следующую команду:

    [root@redhat root]# find / -perm -1007 -type d -print

    Тоже но без sticky bit:

    [root@redhat root]# find / -perm -007 -type d -print

    Пример вывода:

    /tmp
    /tmp/.font-unix
    /var/tmp
    /var/spool/samba

    Так как обычно на Shared hosting не поддерживается работа samba (которая входит в установку по умолчанию), рекомендуется удалить пакет samba*. Вывести все пакеты, имеющие отношение к samba, может следующая команда:

    [root@redhat root]# rpm -qa|grep samba

    Пример вывода:

    samba-3.0.9-1.3E.2
    samba-common-3.0.9-1.3E.2
    samba-client-3.0.9-1.3E.2
    redhat-config-samba-1.0.16-2
    samba-swat-3.0.9-1.3E.2

    Удаляем пакеты:

    [root@redhat root]# rpm -e samba samba-common samba-client redhat-config-samba samba-swat

    Если не желаете удалять пакеты, тогда уберите права с директории /var/spool/samba:

    [root@redhat root]# chmod 0000 /var/spool/samba

    Если Вы таки используете samba, тогда с этой директорией поступайте так же, как дальше по статье работаем с /tmp.

    1.2 Создание файл-разделов.

    Мы определили директории, для которых необходимо создать раздел-файлы. Это /tmp, /var/tmp.

    Создаем директорию, где будут лежать файлы-разделы:

    mkdir /filesystems

    Создаем файл-разделы:

    [root@redhat root]# dd if=/dev/zero of=/filesystems/tmp_fs seek=100 count=1 bs=1M
    [root@redhat root]# dd if=/dev/zero of=/filesystems/var_tmp_fs seek=100 count=1 bs=1M

    Я решил выделить под /tmp и /var/tmp по 100 M. Вы можете выделить больше - по Вашим потребностям.

    Следующим шагом создаем в файлах ФС:

    [root@redhat root]# mkfs.ext3 /filesystems/tmp_fs
    [root@redhat root]# mkfs.ext3 /filesystems/var_tmp_fs

    Добавляем в /etc/fstab строки автоматического присоединения файл-разделов при старте сервера:

    /filesystems/tmp_fs /tmp ext3 defaults, noexec, nosuid, loop 1 1
    /filesystems/var_tmp_fs /var/tmp ext3 defaults, noexec, nosuid, loop 1 1

    Присоединяем и проверяем присоединились ли новые файл-разделы (не забыв удалить данные из папок /tmp /var/tmp или, если там есть нужные данные, - временно перенести в другое место, а потом положить в новые файл-разделы):

    [root@redhat root]# mount /tmp
    [root@redhat root]# mount /var/tmp
    [root@redhat root]# df

    Пример вывода:

    Filesystem Size Used Avail Use% Mounted on
    /dev/hda1 2.0G 988M 926M 52% /
    /filesystems/tmp_fs 98M 4.1M 89M 5% /tmp
    /filesystems/var_tmp_fs
    98M 4.1M 89M 5% /var/tmp

    1.3 Проверка работы noexec,nosuid.

    Пробуем запустить suid файл из под nobody. Вот код С программы:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    int main (int argc, const char * argv[],char * envp[])
    {
    uid_t uid;
    uid = getuid();
    printf("My id is %d\n",uid);
    if(0 != setuid(0)) printf("\nError suid to root\n");
    uid = getuid();
    printf("After suid My id is %d\n",uid);
    }

    Собираем:

    [root@redhat root]# gcc suid.c -o suid

    Ставим SUID на suid:

    [root@redhat root]# chmod 4775 suid

    Копируем для проверки в /:

    [root@redhat root]# cp suid /

    проверяем:

    [root@redhat root]# sudo -u nobody /suid
    My id is 99
    After suid My id is 0

    Копируем в защищенные директории /tmp /var/tmp:

    [root@redhat root]# cp suid /tmp/
    [root@redhat root]# cp suid /var/tmp/

    Проверяем:

    [root@redhat root]# sudo -u nobody /tmp/suid
    sudo: unable to exec /tmp/suid: Permission denied
    [root@redhat root]# sudo -u nobody /var/tmp/suid
    sudo: unable to exec /var/tmp/suid: Permission denied

    Сделаем аналогичную проверку для SheLL, Perl, PHP скриптов.

    Пример скриптов:

    test.php:
    #!/usr/bin/php -q
    <? echo "running\n"; ?>


    test.pl:
    #!/usr/bin/perl
    print "running\n"


    test.sh:
    #!/bin/sh
    echo "running"

    Результатты проверок:

    PHP:

    [root@redhat root]# chmod 755 test.php
    [root@redhat root]# ./test.php
    running
    [root@redhat root]# cp test.php /tmp
    [root@redhat root]# /tmp/test.php
    -bash: /tmp/test.php: /usr/bin/php: bad interpreter: Permission denied


    Perl:

    [root@redhat root]# chmod 755 test.pl
    [root@redhat root]# ./test.pl
    running
    [root@redhat root]# cp test.pl /tmp/
    [root@redhat root]# /tmp/test.pl
    -bash: /tmp/test.pl: /usr/bin/perl: bad interpreter: Permission denied


    Shell:

    root@redhat root]# chmod 755 test.sh
    [root@redhat root]# ./test.sh
    running
    [root@redhat root]# cp test.sh /tmp/
    [root@redhat root]# /tmp/test.sh
    -bash: /tmp/test.sh: /bin/sh: bad interpreter: Permission denied

    На первый взгляд все хорошо. Ничего из директорий-свалок запустить нельзя.

    1.4 Обход ограничения noexec .

    Обход noexec при запуске исполняемого файла:

    root@redhat root]# sudo -u nobody /lib/ld-linux.so.2 /tmp/suid
    My id is 99
    error suid to root
    After suid My id is 99

    Как видите, ограничение noexec было обойдено, ограничение на nosuid обойти не удалось (мне не известны способы обхода nosuid на директорию...).

    Данный способ обхода был действителен для всех доступных мне ОС Linux RHE (<=2.4.21-27.0.4.EL - последний kernel, доступный для обновление через up2date, в момент написания статьи). В случае использование 2.6.x kernel, собранного с исходников, данный способ уже недействителен.

    root@redhat root]# sudo -u nobody /lib/ld-linux.so.2 /tmp/suid
    /tmp/suid: error while loading shared libraries:
    /tmp/suid: failed to map segment from shared object: Operation not permitted

    Вот пример обхода ограничения на запуск скриптов PHP/Perl/Shell:

    PHP:

    [root@redhat root]# /usr/bin/php -q /tmp/test.php
    running

    Perl:

    [root@redhat root]# /usr/bin/perl /tmp/test.pl
    running

    Shell:

    [root@redhat root]# /bin/sh /tmp/test.sh
    running

    1.5 Скрипт для дополнительной защиты.

    Как видим, одно ограничение noexec, nosuid не способно остановить вторжение, но является дополнительным сдерживающим средством. Расширим его скриптом, который будет проходить по директориям-свалкам и изменять/удалять неугодные нам файлы. Я лишь приведу пример написанный на shell. Вы можете реализовать данную методику любым удобным Вам способом.

    Вот код:

    #!/bin/sh
    DIR4PROTECT="/root/dir4protect"
    for dir in `cat $DIR4PROTECT`;do
    FILE2DELETE=`find $dir -perm +1111 -print`
    for file in `echo $FILE2DELETE`;do
    if [ -f $file ];then
    chmod 0000 $file
    chown root.root $file
    fi
    done
    done

    Проверяем его работу:

    [root@redhat root]# ./tmpprotect.sh
    [root@redhat root]# ls -la /tmp
    total 45
    drwxr-xr-x 3 root root 1024 Apr 29 18:32 .
    drwxr-xr-x 20 root root 4096 Apr 28 23:45 ..
    ---------- 1 root root 0 Apr 29 18:32 1
    drwx------ 2 root root 12288 Apr 27 21:31 lost+found
    ---------- 1 root root 11841 Apr 29 00:36 s2
    ---------- 1 root root 34 Apr 29 00:10 shell.sh
    ---------- 1 root root 11841 Apr 29 00:00 suid
    ---------- 1 root root 40 Apr 29 16:30 test.php
    ---------- 1 root root 38 Apr 29 16:35 test.pl
    ---------- 1 root root 26 Apr 29 16:40 test.sh
    [root@redhat root]# ls -la /var/tmp
    total 29
    drwxr-xr-x 3 root root 1024 Apr 29 00:00 .
    drwxr-xr-x 19 root root 4096 Mar 4 23:29 ..
    drwx------ 2 root root 12288 Apr 27 21:32 lost+found
    ---------- 1 root root 11841 Apr 29 00:00 suid

    Проверяем возможно ли запустить скрипты:

    [root@redhat root]# sudo -u nobody /usr/bin/php -q /tmp/test.php
    [root@redhat root]# sudo -u nobody /usr/bin/perl /tmp/test.pl
    Can't open perl script "/tmp/test.pl": Permission denied
    [root@redhat root]# sudo -u nobody /bin/sh /tmp/test.sh
    /tmp/test.sh: /tmp/test.sh: Permission denied

    Написанный скрипт помогает блокировать файлы, которые могут быть backdoor, exploits, trojanhorse в директориях свалках. Его можно расширить автоматическим отправлением письма администратору, любыми другими пришедшими вам на ум идеями. Самый простой способ - это установить данный скрипт для автозапуска в crontab на запуск раз в минуту.

    Пример содержимого файла крон службы:

    * * * * * /root/tmpprotect.sh

    2. Контроль выполняемых процессов.

    Следующий эшелон защиты – это контроль выполняемых процессов. Этот способ заключается в проверке списка процессов и снятии с выполнения неугодных.

    Вот пример скрипта, который, основываясь на файле-списке разрешенных процессов, убивает остальные.

    /root/nobody.sh

    #!/bin/sh
    USER="nobody"
    RULEFILE="/root/nobody"
    if [ -f "$RULEFILE" ]; then
    KPID=`ps -eo "%p%u%c"|grep $USER|grep -vi $$|grep -vif $RULEFILE |awk '{print$1}'`
    for j in `echo "$KPID"`; do
    kill -9 $j >> /dev/null 2>&1
    done
    fi

    файл список разрешенных програм:

    /root/nobody

    httpd
    suexec

    *Для корректной работы WHM/Cpanel в /root/nobody необходимо внести список выполняемых файлов из директорий /scripts/ /usr/local/cpanel/bin/.

    Проверим работу скрипта. Открыв второй шелл, запустим там команду "sudo -u nobody sleep 500", а в первом – на выполнение наш скрипт.

    [root@redhat root]# sudo -u nobody sleep 500
    Killed
    ---
    [root@redhat root]# chmod 750 nobody.sh
    [root@redhat root]# ./nobody.sh

    Процесс, не входящий в список разрешенных, был убит нашим скриптом.

    Теперь попробуем другой скрипт:

    httpd:

    #!/bin/sh
    while [ "1" ];do
    sleep 1
    done

    Сохраним его в директории /tmp, сделаем запускаемым и запустим:

    [root@redhat tmp]# sudo -u nobody ./httpd
    sudo: unable to exec ./httpd: Permission denied
    [root@redhat tmp]# sudo -u nobody /bin/sh ./httpd
    Killed

    Наш скрипт его убивает, и все потому, что он видится как процесс sh. Для примера того, что скрипт может быть не убиваем, скопируем его в / и запустим оттуда. ( в реальной жизни это будет директория какого-то пользователя, который открыл директорию на заливку (777) )

    [root@redhat /]# sudo -u nobody ./httpd
    ./httpd: line 4: 4101 Killed sleep 1
    ./httpd: line 4: 4111 Killed sleep 1

    Позапускав наш скрипт nobody.sh видим, что главный скрипт не умирает, а вот потомки снимаються с выполнения. Это из-за того, что главный скрипт подпадает под разрешенные процессы.

    Приведенный вариант не панацея и является всего лишь толчком для Вашей фантазии. Вы его можете модернизировать, переделать или сделать как Вам удобнее. Главное – я показал принцип и точку, в которой можно противодействовать вторжению.

    3. Настройка Firewall.

    Учитывая нюансы WHM/Cpanel, перечислим порты, которые должны быть открыты на вход:

    TCP 21,22,25,53,80,110,443,2082,2083,2086,2087,2089,2095,2096
    UDP 53
    ICMP 0,30,8

    на выход:

    TCP 25,53,2089
    ( 2089 необходим для работы WHM для авторизации)
    UDP 53
    ICMP 0,30,8

    Напишем скрипт, который будет загружать в iptables правила для файрволинга при старте системы. Ограничивая исходящие соединения, мы тем самым уменьшаем количество возможных backconnect.

    /etc/firewall.sh:

    #/bin/sh
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 21 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 22 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 25 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 53 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 80 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 110 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 443 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2082 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2083 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2086 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2087 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2089 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2095 -j ACCEPT
    /sbin/iptables -A INPUT -p tcp -s 0/0 -d 10.10.10.10 --dport 2096 -j ACCEPT
    /sbin/iptables -A INPUT -p udp -s 0/0 -d 10.10.10.10 --dport 53 -j ACCEPT
    /sbin/iptables -A INPUT -p icmp -s 0/0 -d 10.10.10.10 --icmp-type 0 -j ACCEPT
    /sbin/iptables -A INPUT -p icmp -s 0/0 -d 10.10.10.10 --icmp-type 8 -j ACCEPT
    /sbin/iptables -A INPUT -p icmp -s 0/0 -d 10.10.10.10 --icmp-type 30 -j ACCEPT
    /sbin/iptables -A INPUT -p all -s 0/0 -d 10.10.10.10 -j DROP

    /sbin/iptables -A OUTPUT -p tcp -d 0/0 -s 10.10.10.10 --dport 25 -j ACCEPT
    /sbin/iptables -A OUTPUT -p tcp -d 0/0 -s 10.10.10.10 --dport 53 -j ACCEPT
    /sbin/iptables -A OUTPUT -p tcp -d 0/0 -s 10.10.10.10 --dport 2089 -j ACCEPT
    /sbin/iptables -A OUTPUT -p udp -d 0/0 -s 10.10.10.10 --dport 53 -j ACCEPT
    /sbin/iptables -A OUTPUT -p icmp -d 0/0 -s 10.10.10.10 --icmp-type 0 -j ACCEPT
    /sbin/iptables -A OUTPUT -p icmp -d 0/0 -s 10.10.10.10 --icmp-type 8 -j ACCEPT
    /sbin/iptables -A OUTPUT -p icmp -d 0/0 -s 10.10.10.10 --icmp-type 30 -j ACCEPT
    /sbin/iptables -A OUTPUT -p all -d 0/0 -s 10.10.10.10 -j DROP

    В данном скрипте 10.10.10.10 - это IP адрес Вашего сервера. Если сервер имеет более одного IP то необходимо добавить эти-же строки но с другим IP .

    Сделаем скрипт запускаемым:

    chmod 755 /etc/firewall.sh

    Добавим в /etc/rc.local строку:

    /etc/firewall.sh

    Осталось вручную загрузить правила:

    /etc/firewall.sh

    Будте осторожны - Вы можете закрыть доступ на сервер для самого себя.

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

    4. Настройка cPanel(WHM)+apache+php.ini

    Есть две задачи, которые в данном случае приходится решать, идя на компромис между ними:

    - максимум возможностей для пользователя,

    - максимум безопасности на уровне пользователя.

    Увеличивая возможности для пользователя, а, соответственно, и привлекательность хостинга, нам прийдется забыть о safe mode для PHP. Однако, чтоб немного оградить тех же пользователей от взлома их страниц, а свой хостинг от проникновения скрипт-кидди, нам необходимо ограничить опасные функции, которые обычно используются для начального взлома системы.

    Действовать будем, отталкиваясь от популярных уязвимостей.

    Во-первых, это внедрение PHP кода в сценарии и выполнение произвольных команд. В php.ini прописываем следующее:

    - запретим открытие/включение удаленных файлов:

    allow_url_fopen = Off
    enable_dl = Off

    - запретим выполнение команд:

    disable_functions = ini_alter, curl_exec, exec, system, passthru, shell_exec, proc_open, proc_close, proc_get_status, proc_nice, proc_terminate, leak, listen, chgrp, chmod, set_time_limit, apache_note, apache_setenv, closelog, debugger_off, debugger_on, define_syslog_variables, openlog, syslog,ftp_exec,phpinfo,dl ;

    запретим вывод php скриптами ошибок:

    display_errors = Off

    - выключим передачу информации о php в заголовках HTTP ответов:

    expose_php = Off

    Если пользователи не настаивают, то рекомендуем отключить и функции posix, с помощью которых возможен обход некоторых ограничений на выполнение команд.

    Уязвимости типа SQL injection ограничим включением параметра

    magic_quotes_gpc = on

    В некоторых случаях можно было бы установить mod_security. Полезный модуль, который ограничивает внедрение SQL, java script и др. кода.

    Полезно было бы сбить с толку горе-хакеров, изменив заголовок веб-сервера, отправляемый по умолчанию. Для apache это делается следующим образом. В файле src/include/httpd.h редактируем строки типа:

    #define SERVER_BASEPRODUCT “Apache”
    #define SERVER_BASEVERSION “1.3.27”

    После этого компилируем веб-сервер и устанавливаем его. Впрочем, если вы установили mod_security, это все можно сделать с его помощью, не переустанавливая веб сервер.

    И, наконец, зайдем в закладку "Tweak Security" в cPanel/WHM и активируем:

    Php open_basedir Tweak
    Compilers Tweak

    Первый установит в httpd.conf на все VirtualHost open_basedir на домашнюю папку пользователя.

    Второй разрешит доступ к GCC только для указанных в списке пользователей.
     
  2. w00d

    w00d [ The Godfather ]

    Joined:
    30 Jun 2005
    Messages:
    172
    Likes Received:
    22
    Reputations:
    4
    Эпилог

    Эпилог

    В данной статье рассмотрены методы борьбы на "передовой"; противодействие атакующему через веб-скрипты (apache/mod_php) на базе распространенной панели для shared hosting WHM/Cpanel (cpanel.net) с ОС Linux RHE. (Учитывая особенности работы данной панели, применяемые меры не идут в разрез с работой WHM/Cpanel), которые дают Вам зацепку, через которую можно выстроить достаточно плотную защиту обход которой будет не всегда соразмерен полученному результату.

    P.S. Для всех используемых команд для более детального понимания прошу обращаться к man страницам.