Содержание статьи
www
Подробности про группировку, инструменты и TTP ищи по ссылкам:
PowerShell loader
В начале 2024 года наша команда по расследованию инцидентов (PT ESC Positive Technoligies) выявила применение малвари CobInt в инфраструктуре заказчика. Проанализировав логи EVTX на скомпрометированной машине, мы извлекли сильно обфусцированный вредоносный скрипт PowerShell.
![Обфусцированный код PowerShell Обфусцированный код PowerShell](https://static.xakep.ru/images/e6707eb7452ec94dc3ebc67aea669107/36940/image1-1.png)
В конце кода скрипта мы видим вызов единственной функции, которая нас больше всего и интересует.
![Вызов функции Вызов функции](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36859/image2.png)
Код функции выглядит следующим образом:
If ([IntPtr]::size -eq 8){ $L7Q=aQGIf $d90qSK=1331}else{ $L7Q=tNKdTPG $d90qSK=1166}$YodSQB=[System.Convert]::FromBase64String((vXQvbyjhW $L7Q))RgEGGBTGL $YodSQB $d90qSK}
В этой функции на основе размера указателя определяется разрядность ОС, в зависимости от которой переменной $d90qSK
присваивается соответствующее значение. Оно определяет смещение к функции расшифровки шелл‑кода. Шелл‑код для определенной архитектуры декодируется из Base64, после чего передается в функцию RgEGGBTGL
вместе со смещением. Чтобы сохранить раскодированный шелл‑код на диск, сразу после вызова функции FromBase64String
добавим в код следующую строку:
[IO.File]::WriteAllBytes('shellcode.bin',$YodSQB)
Теперь убедимся, что шелл‑код сохранился корректно. Закидываем его в IDA, переходим по смещению 1331 (
в случае с x64 и преобразуем байты в код.
![Код расшифровки по смещению 0x533 Код расшифровки по смещению 0x533](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36860/image3.png)
Расшифровка тела шелл-кода
Код, который отвечает за расшифровку самого себя в памяти, выглядит следующим образом.
![Код для дешифровки тела шелл-кода Код для дешифровки тела шелл-кода](https://static.xakep.ru/images/f39a7a42e38474abb421da95c74cba86/36947/image4.png)
Нам нужно преобразовать шелл‑код в исполняемый файл. Я это делаю с помощью shellcode2exe:
shellcode2exe.bat 64 shellcode.bin cob_shellx64.exe
Теперь мы можем загрузить получившийся исполняемый файл в x64dbg. После загрузки жмем RUN, чтобы перейти к EntryPoint.
![Интерпретация зашифрованных байтов шелл-кода дебаггером Интерпретация зашифрованных байтов шелл-кода дебаггером](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36862/image5.png)
Код на текущий момент еще не расшифрован и представляет собой вольную интерпретацию мешанины из байтов, выданной дебаггером. Нужно перейти по известному смещению 0x533
+ ImageBase, то есть в нашем случае по адресу 0x401533
.
![Точка входа для расшифровки кода Точка входа для расшифровки кода](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36863/image6.png)
Мы видим уже знакомую функцию для расшифровки тела шелл‑кода. Выполнять код мы начнем с текущей строки. Для этого жмем Set RIP Here, после чего адрес Instruction
примет необходимое значение.
С помощью F8 нужно пройтись по инструкциям расшифровки и найти ту, которая отвечает за выход из цикла. Эта инструкция находится по адресу 0x401538
.
![Инструкция для выхода из цикла расшифровки Инструкция для выхода из цикла расшифровки](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36864/image7.png)
Ставим брейк‑пойнт на следующей за jne
инструкции и нажимаем F9, чтобы вручную не ходить по каждой итерации цикла расшифровки. После остановки на нашем брейк‑пойнте проходим по коду немного дальше и прыгаем на начало уже расшифрованного кода в оригинальной EntryPoint.
![Расшифрованный код в EntryPoint Расшифрованный код в EntryPoint](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36865/image8.png)
На этом этапе мы можем сдампить PE в расшифрованном виде для удобства дальнейшего дебага. Я использую в этих целях плагин OllyDumpEx.
![Дамп процесса Дамп процесса](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36866/image9.png)
Код для расшифровки себя в памяти содержит следующий алгоритм:
- XOR первых четырех байтов (Little Endian) с зашитым ключом
0x4498D9DE
. - Побитовый сдвиг влево на один бит для ключа (
rol
).xor_key, 1 - XOR следующих четырех байтов с модифицированным ключом и так далее.
Исследование загрузчика
Unhashing functions
Настало время поковыряться в загрузчике. Открываем сдампленный файл в x64dbg. В коде встречается множество вызовов функции 401380
, в которую передаются различные Hex-значения. Обычно такой паттерн свойственен функциям, отвечающим за восстановление имен библиотек и функций из хеш‑значений. Как видно на скриншоте, первый вызов вернул имя функции LoadLibraryA
библиотеки Kernel32
, а также ее адрес в RCX.
![Вызов unhashing-функции Вызов unhashing-функции](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36867/image10.png)
Рассмотрим эту функцию подробнее. Обрати внимание на следующий код.
![Инструкции для получения информации из PEB Инструкции для получения информации из PEB](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36868/image11.png)
Этот модуль сначала получает указатель на PEB (Process Environment Block) через смещение 0x60
в TEB (Thread Environment Block), доступ к которому осуществляется через регистр gs
. Затем код переходит по смещениям 0x18
и 0x20
. Чтобы понять, что это за смещения, можно обратиться к описанию структуры PEB или проверить их в WinDbg. Для этого:
- загружаем исполняемый файл в WinDbg;
- вводим команду
bp
для установки брейк‑пойнта на EntryPoint;$exentry - запускаем исполнение командой
g
; - перемещаемся нажатием F8 к рассматриваемому участку кода.
Команда dt
покажет структуру PEB со смещениями.
![Структура PEB в WinDbg Структура PEB в WinDbg](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36869/image12.png)
Первое смещение указывает на структуру PEB_LDR_DATA
, которая содержит в себе сведения о загруженных модулях для процесса. Изучим ее повнимательнее, для этого в WinDbg введем команду dt
.
![Структура PEB_LDR_DATA в WinDbg Структура PEB_LDR_DATA в WinDbg](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36870/image13.png)
Второе смещение указывает на двусвязный список InMemoryOrderModuleList
, который содержит загруженные модули для процесса. Каждый элемент в этом списке является указателем на структуру LDR_DATA_TABLE_ENTRY
. Смещение на него лежит в rbx
, поэтому берем адрес из rbx
и накладываем на него структуру _LDR_DATA_TABLE_ENTRY
.
![Содержание структуры LDR_DATA_TABLE_ENTRY, на которую получен указатель Содержание структуры LDR_DATA_TABLE_ENTRY, на которую получен указатель](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36871/image14.png)
Таким образом, по смещению 0x50
код получает доступ к полю buffer
с именем модуля. Далее вызывается функция, в которую аргументами передается указатель на строку с именем модуля и длина строки.
![Передача имени модуля и длины строки в функцию Передача имени модуля и длины строки в функцию](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36872/image15.png)
Эта функция выполняет хеширование строки. Алгоритм выглядит следующим образом.
![Алгоритм хеширования строки Алгоритм хеширования строки](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36873/image16.png)
Получив хеш, алгоритм проверяет полученное значение с переданным ранее аргументом. Если значения не совпадают, выполняется переход к следующему имени модуля. Если совпадают, то сохраняется указатель на адрес библиотеки, к которому прибавляются смещения.
![Доступ к данным библиотеки по смещениям Доступ к данным библиотеки по смещениям](https://static.xakep.ru/images/ae243445c0781d9ad8b7071a3fe96438/36874/image17.png)
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее