Всем привет, как я обещал в первой части статьи «Привет Emotet!», в следующей статье мы приступим к расследованию инцидента в дампе оперативной памяти и заодно пройдём задание от cyberdefenders.org ответив на 10 несложных вопросов, а также узнаем как вредонос скрывает свою активность в скрытых процессах и как ему удаётся обходить средства защиты информации. Разберём распространённую атаку Direct Kernel Object Manipulation (DKOM), которая часто используется Rootkit’ами.
В статье я постараюсь объяснить как устроены некоторые стурктуры в памяти, в том числе: структура ядра и исполняемых процессов. Но на подробное объяснение не хватит ни одной статьи, поэтому если у вас есть желание узнать более подробную информацию о структурах: ядра, процессов и расследовании инцидентов в дампах оперативной памяти, рекомендую обзавестись книгой «The Art of Memory Forensics» by Michael Hale Ligh, Andrew Case, Jamie Levy, AAron Walters. В книге изложена вся необходимая базовая информация о структуре ОС, ядра, процессов и.т.д, не только Windows, но и Linux, а также Mac. В связи с изменениями версий ОС информация несколько устарела, на базовый материал в книге – определённо мастхэв для изучения.
Правильно подобранный набор утилит и хорошо подготовленный стенд — залог успеха в расследовании инцидентов, поэтому начнем именно с этого. Я буду использовать SIFT (by SANS), т.к. он уже содержит набор необходимых утилит и плагинов.
Основная утилита, которой мы сегодня будем пользоваться это, конечно многим знакомая, volatility на python2.
Часть 2 серии статей «Привет Emotet»!
В первую очередь, загрузим дамп оперативной памяти с трояном внутри и разархивируем его на SIFT (рисунок 1)
Чтобы не обращаться к нему постоянно с помощью “-f dump.vmem”, добавим в переменную окружения расположение файла дампа оперативной памяти:
export VOLATILITY_LOCATION=file:///home/sansforensics/Desktop/Emotet_dump/banking-malware.vmem (рисунок 2)
Теперь нам необходимо узнать наименование профиля ОС, чтобы корректно работать с содержимым (процессами, файлами и.т.д) и заодно ответить на первый вопрос What profile should you use for this memory sample?
Для этого, мы воспользуемся плагином kdbgscan, которые находит Kernel Debugger Data Block (KDBG), результат на рисунке 3.
Получим исчерпывающую информацию о структуре ОС, в том числе указание профиля и предложенные профили (их 8). Определить, что профиль выбран верно можно с помощью следующих плагинов:
pslist;
psscan;
filescan;
hivelist.
Если профиль выбран неверно, вы получите нечитаемый или искажённый результат после выполнения этих плагинов.
Здесь же мы обнаружим виртуальный и физический адреса и сразу ответим на второй вопрос (рис 4):
What is the KDBG virtual address of the memory sample?
Также, вы можете воспользоваться плагином imageinfo, но с ним вы получите чуть меньше информации.
Для удобства, чтобы не передавать в каждом вызове volatility указание профиля (--profile=’win7sp1x64_2400’) мы экспортируем наименование профиля в переменную окружения:
export VOLATILITY_PROFILE='Win7SP1x64_24000'
Готово, теперь мы, запустив vol.py, можем сразу использовать плагины, без указания месторасположения и профиля, например получить список активных процессов: vol.py pslist
В следующем вопросе There is a malicious process running, but it's hidden. What's its name? нас просят найти имя скрытого процесса. Что это за процесс, почему и от кого он скрыт?
Kernel Debugger Data Block (KDBG) имеет указатель на структуру _EPROCESS block list, где каждый блок указывает на объекты: handles, VAD Tree, Access Tokens, Threads, Process Environment Block (PEB для понимания, сюда входят исполняемые файлы, dll и.т.д). Также эта структура содержит всю остальную информацию о процессе, директории из которой был запущен исполняемый файл, пользователь, который его запустил, время и многое другое. По сути, с этой структурой работает большинство плагинов Volatility.
И мы с вами с этими объектами будем работать. Визуально схема описанная выше выглядит следующим образом:
Также в структуре _EPROCESS есть цепочка процессов и ссылок ActiveProcessLinks (на неё указывает PsActiveProcessHead из KDBG), данная цепочка называется doublelinked и выглядит как на рисунке 5:
Forward Link (Flink) или прямая ссылка, указывает на адрес структуры ActiveProcessLink следующего процесса, а Backward Link (Blink) указывает на адрес структуры ActiveProcessLink предыдущего процесса.
В случае со скрытым
процессом, Forward Link буквально перепрыгивает
через впереди стоящий процесс и указывает на адрес структуры ActiveProcessLink следующего процесса, то же
самое производится по отношению к Backward Link, таким образом процесс
становится скрытым. Это означает, что при просмотре запущенных
процессов в диспетчере задач и через консоль tasklist, а также process explorer, мы его не увидим.
Данный принцип лежит в основе атаки DKOM, в ходе которой вредоносное ПО меняет объекты
ядра непосредственно в памяти. Такие изменения не оставляют следов на диске и
позволяют обходить средства защиты: АВЗ и другие.
Как выглядит цепочка со скрытым процессом Process 2 отобразил на рисунке 6.
Как мы можем заметить, на его структуру ActiveProcessLinks не указывает ни один процесс. Flink Process 1 указывает на ActiveProcessLinks процесса N, в то время как Blink процесса N указывает на структуру ActiveProcessLinks процесса 1, вместо указания структуры Process 2. Пометил красным изменённые указатели в сравнении со схемой на рисунке 5.
С краткой теорией мы покончили, теперь продолжим нашу практику. И для ответа на вопрос, напомню: There is a malicious process running, but it's hidden. What's its name? мы воспользуемся плагином psxview, который отобразит нам, что один из процессов был скрыт (рисунок 7), в таком случае плагины pslist и psscan его не отобразят, т.к. они проходят по цепочке тех самых ссылок Flink & Blink, аналогично работают: Диспетчер задач, Process Explorer, tasklist.
Плагин psxview позволяет находить скрытые процессы и отображает имя, PID, физический адрес и другую информацию о процессах. Это достигается благодаря тому, что в отличие от плагина pslist, которые читает _EPROCESS double linked list, данный плагин не сканирует только цепочку ссылок которая завязана на ActiveProcessLinks адреса, а совмещает в себе сразу несколько плагинов:
pslist - читает _EPROCESS double linked список;
psscan – считывает структуры _EPROCESS, отображает завершённые процессы, иногда помогает находить руткиты;
thrdproc – процессы и потоки;
pspeid – Таблица PspCid отслеживает процессы и потоки;
csrss – хранит дескриптор процесса, который запустился после (True) или до(False);
session – список процессов, принадлежащих каждому сеансу входа в систему;
deskthrd – определение процессов по потокам, которые прикреплены к каждому рабочему столу.
Таким образом, мы определили, что процесс с именем vds_ps.exe, PID:2448 и физическим адресом 0x000000007d336950 скрыт, т.к. имеет значение False для pslist & psscan. Что позволяет нам ответить на следующий вопрос об адресе процесса: What is the physical offset of the malicious process? (нашли ранее).
Для ответа на вопрос о пути процесса: What is the full path (including executable name) of the hidden executable? мы можем пойти сразу несколькими путями. Сейчас я покажу простой способ поиска пути и далее в статье расскажу более сложный способ. Итак, после того, как мы определили адрес процесса, давайте посмотрим его путь, а также все dll которые он использует (рисунок 8), разумеется информацию о местоположении запущенного исполняемого файла можно также обнаружить в Prefetch и ShimCahe, но я пойду через dlllist:
vol.py --offset=0x000000007d336950 dlllist
Давайте сразу сдампим процесс в текущую директорию и посмотрим, какая информация есть по известным сигнатурам на virustotal (рисунки 9 и 10):
vol.py procdump --offset=0x000000007d336950 -D .
Перед нами Emotet, неожиданно, конечно, учитывая что задание называет Emotet. Cразу ответим на следующий вопрос Which malware is this?
Для ответа на вопрос The malicious process had two PEs injected into its memory. What's the size in bytes of the Vad that contains the largest injected PE? Answer in hex, like: 0xABC воспользуемся плагином malfind, который позволяет найти следы для большинства техник типа process injection (рисунок 11) здесь мы сразу и сдампим найденный плагином внедрённый код в текущую директорию:
vol.py malfind --offset=0x000000007d336950 -D .
Обратите внимание, что тип защиты памяти PAGE_EXECUTE_READWRITE для исполняемых файлов, которые загружены естественным путём – не нормальный (красные стрелки). Нормальное состояние защиты памяти для легитимно загруженных исполняемых файлов – PAGE_EXECUTE_WRITECOPY. Это говорит нам о том, что процесс был внедрён (injected), т.к. при этом изменяется тип памяти, ответственную за это функцию Windows API мы найдём ниже.
Давайте посмотрим на функции, которые используются вредоносным процессом при помощи утилиты strings (Рисунок 12):
strings process.0xfffffa8004536950.0x220000.dmp
Здесь мы видим «полный набор»:
Process32First/Next и CreateToolhelp32Snapshot позволяют находить необходимый процесс (часто функции используются для внедрения DLL).
VirtualProtect позволяет изменять тип защиты отдельных участков памяти.
GetProcAdddress и др. функции из библиотеки kernel32.dll.
Чтобы ответить на вопрос нам всего то нужно взять последний используемый адрес в памяти у самого большого по размеру дампа: process.0xfffffa8004536950.0x2a80000.dmp.
Для этого я воспользуюсь ndisasm в REMnux (в SIFT) утилита отсутствует и выведу последние несколько дизассемблированных строк (рис 13) :
Чтобы сильно не нагружать информацией, сразу следом выйдет 3-я заключительная часть из серии статей "Привет Emotet!".
В 3-й части серии статей «Привет Emotet!» начинается самое интересное, мы убираем в сторону плагины, автоматизирующие нашу работу и идём гулять по узким коридорам памяти, в поисках артефактов...