Программа-вымогатель MountLocker
Обзор
Это мой отчет по образцу MountLocker Ransomware v5.0, который используется группой вымогателей XingLocker.
Эта программа-вымогатель использует схему гибридной криптографии RSA-2048 и ChaCha20 для шифрования файлов и защиты своих ключей. В отличие от других программ-вымогателей, MountLocker шифрует все ключи ChaCha20 с помощью глобального ключа ChaCha20, прежде чем шифровать этот глобальный ключ с помощью открытого ключа RSA-2048. Зашифрованный глобальный ключ и соответствующий зашифрованный ключ ChaCha20 добавляются в конце каждого зашифрованного файла.
Эта версия включает в себя новую функцию червя, позволяющую ему самостоятельно распространяться на другие компьютеры в сети с помощью COM-интерфейсов IDirectorySearch и IWbemServices.
MountLocker имеет сложную схему многопоточности, но ее производительность страдает от нехватки потоков из-за рекурсивного обхода файлов.
Я больше не буду тратить свое время на объяснение того, почему рекурсивный обход файлов ужасен, потому что я высказал свое мнение в последних нескольких отчетах. Пожалуйста, не стесняйтесь прочитайте мой анализ Darkside, если вы хотите лучше понять теорию, стоящую за ним!
MD5: 3808f21e56dede99bc914d90aeabe47a
SHA256: 4a5ac3c6f8383cc33c795804ba5f7f5553c029bbb4a6d28f1e4d8fb5107902c1
Сэмпл: https://bazaar.abuse.ch/sample/4a5ac3c6f8383cc33c795804ba5f7f5553c029bbb4a6d28f1e4d8fb5107902c1/
Записка с требованием выкупа
Записка о выкупе записывается в формате HTML и помещается в файлы RecoveryManual.html в системе.
Идентификатор клиента, встроенный в записку о выкупе, генерируется из имени компьютера жертвы и жестко запрограммированной строки в памяти.
Производительность
MountLocker имеет довольно среднюю производительность и не полностью использует вычислительную мощность машины.
Статический анализ кода
Параметры командной строки
MountLocker можно запустить как с параметрами командной строки, так и без них. Программа-вымогатель сначала проверяет и анализирует заданные параметры, чтобы соответствующим образом изменить свои функции.
Ниже приведен список аргументов, которые могут быть предоставлены операторами:
Логирование
Программа-вымогатель имеет два разных способа ведения журнала своих операций, и каждый из них можно включить, установив для аргументов командной строки /CONSOLE значение 1 и /NOLOG на 0.
В этом конкретном примере значение флага /NOLOG жестко запрограммировано равным 0, поэтому он всегда записывает и удаляет файл журнала в системе жертвы.
Когда флаг /NOLOG равен 0, MountLocker извлекает путь к текущему исполняемому файлу, добавляет .log в конец и использует его в качестве пути к файлу журнала.
Если флаг /CONSOLE равен 1, MountLocker также будет вести журнал через стандартный поток вывода консоли. Он вызывает AllocConsole и GetStdHandle(STD_OUTPUT_HANDLE), чтобы выделить консоль и получить дескриптор стандартного потока вывода. Для записи в эту консоль он вызывает WriteConsoleW с этим дескриптором.
В начале журнала сообщается версия конкретного образца MountLocker, и в данном случае это версия 5.0.
Он также извлекает и записывает информацию о системе жертвы, такую как количество процессоров, общий объем системной памяти, версию Windows, архитектуру системы и т.д.
Таким образом записываются все файловые и сетевые операции (перебор, пропуск, шифрование, ошибка).
Терминация сервисов
Если аргумент /NETWORK не указан, вредоносное ПО будет работать в локальном режиме.
В этом режиме, если аргумент /NOKILL равен 0, он перечисляет и уничтожает все службы с этими строками в их имени.
"SQL", "database", "msexchange"
Во-первых, он вызывает OpenSCManagerA для получения дескриптора диспетчера управления службами и вызывает EnumServicesStatusA для перечисления всех служб Win32 со статусом SERVICE_ACTIVE.
Если служба содержит любую из трех приведенных выше строк, MountLocker завершит ее, вызвав OpenServiceA для получения дескриптора управления службой и вызвав ControlService для отправки кода остановки управления. Затем он непрерывно зацикливается до тех пор, пока состояние службы не станет SERVICE_CONTROL_STOP, чтобы убедиться, что служба полностью завершена.
Завершение процессов
Если он работает в локальном режиме и аргумент /NOKILL равен 0, MountLocker перечислит и уничтожит все процессы с этими строками в их имени.
"msftesql.exe", "sqlagent.exe", "sqlbrowser.exe", "sqlwriter.exe", "oracle.exe", "ocssd.exe",
"dbsnmp.exe", "synctime.exe", "agntsvc.exe", "isqlplussvc.exe", "xfssvccon.exe", "sqlservr.exe",
"mydesktopservice.exe", "ocautoupds.exe", "encsvc.exe", "firefoxconfig.exe", "tbirdconfig.exe",
"mydesktopqos.exe", "ocomm.exe", "mysqld.exe", "mysqld-nt.exe", "mysqld-opt.exe", "dbeng50.exe",
"sqbcoreservice.exe", "excel.exe", "infopath.exe", "msaccess.exe", "mspub.exe", "onenote.exe",
"outlook.exe", "powerpnt.exe", "sqlservr.exe", "thebat.exe", "steam.exe", "thebat64.exe", "thunderbird.exe",
"visio.exe", "winword.exe", "wordpad.exe", "QBW32.exe", "QBW64.exe", "ipython.exe", "wpython.exe",
"python.exe", "dumpcap.exe", "procmon.exe", "procmon64.exe", "procexp.exe", "procexp64.exe"
Программа-вымогатель сначала вызывает ZwQuerySystemInformation с информационным классом SystemProcessInformation, чтобы получить массив структур SYSTEM_PROCESS_INFORMATION. Он перебирает каждый запущенный процесс, избегает своего собственного процесса и начинает завершать процессы в списке уничтожения.
Чтобы проверить и убить процесс, он проходит по списку PROCESS_TO_KILL и сравнивает имя процесса. Если имя процесса есть в списке, он вызывает OpenProcess, чтобы получить дескриптор этого процесса, и завершает его с помощью TerminateProcess.
Генерация глобального ключа ChaCha20
Затем случайным образом генерируется глобальный ключ ChaCha20. Рандомизация выполняется путем вызова инструкции rdtsc, чтобы получить отметку времени процессора, и операции xor его младшего значащего байта для генерации каждого байта в ключе.
После создания глобального ключа программа-вымогатель копирует ключ в другой глобальный буфер в памяти и шифрует этот новый буфер с помощью жестко запрограммированного ключа RSA-2048.
Позже MountLocker использует этот глобальный ключ ChaCha20 для шифрования и защиты своих ключей ChaCha20 вместо использования RSA-2048. Поскольку шифрование RSA-2048 выполняется только один раз, эта схема гибридной криптографии дает некоторое преимущество в производительности, поскольку RSA довольно медленный по сравнению с ChaCha20.
Шифрование
Создание потоков шифрования
Несмотря на наличие разных схем для разных типов дисков и целей, функциональность шифрования практически одинакова.
MountLocker имеет специальную функцию, которая принимает имя диска/файла для шифрования и функцию для его перечисления в качестве параметров.
Эта функция сначала передает перечисляющую функцию и целевое имя пользовательской структуре, прежде чем создать поток для начала шифрования.
Этот поток действует как основной поток в шифровании, который рекурсивно перечисляет и предоставляет файлы для шифрования дочерним потокам.
Функция основного потока вызывает CreateEventA, чтобы создать обработчик событий для каждого дочернего потока, чтобы позже отправить им информацию о файле посредством вызова SetEvent.
Создаются только 2 дочерних рабочих потока, и эти потоки зацикливаются и ждут получения файлов из основного потока для шифрования. Основной поток начнет подавать им файлы, вызвав функцию перечисления в пользовательской структуре выше и перечислив целевую папку.
Дочерние рабочие потоки
После создания каждый рабочий поток получает общую структуру с основным потоком и постоянно проверяет наличие сигнала шифрования 1 в этой общей структуре.
Из-за синхронизации посредством совместного использования общей структуры среди потоков дочерний поток вызывает _InterlockedExchange для атомарного извлечения сигнала шифрования, чтобы проверить, разрешено ли ему шифрование.
Когда он находит файлы для шифрования, основной поток добавляет имя файла в общую структуру и устанавливает сигнал шифрования для дочернего потока для обработки этого файла.
После получения информации о файле рабочий поток создает структуру для хранения такой информации о файле, как имя файла, зашифрованное имя файла, дескриптор файла, размер файла и т. д.
Затем он проверит, есть ли у него права на открытие файла и получение размера файла.
Затем он случайным образом генерирует ключ файла ChaCha20 и добавляет его к файловой структуре выше. Рандомизация выполняется вызовом инструкции rdtsc аналогично генерации глобального ключа ChaCha20.
После генерации ключа файла ChaCha20 рабочий поток создает 313-байтовый буфер, в котором хранится строка маркера файла "lock2" с прямым порядком байтов, размер быстрого шифрования, зашифрованный глобальный ключ ChaCha20 и зашифрованный ключ файла ChaCha20. Этот буфер добавляется в конец зашифрованного файла.
Вот макет буфера ключей в конце зашифрованного файла.
Шифрование файлов довольно стандартное. Рабочий поток шифрует фрагмент размером 0x100000 байт за раз, пока он не зашифрует байты FAST_CRYPT_SIZE или не закончатся байты для шифрования.
Он использует ReadFile для чтения содержимого файла в буфер, шифрует его с помощью файлового ключа ChaCha20 и записывает обратно с помощью WriteFile. Поскольку шифрование выполняется для одного и того же файла, вызывается SetFilePointerEx для настройки указателя файла после чтения и записи.
Я не буду анализировать функцию ChaCha20, потому что MountLocker просто использует эту библиотеку CRYPTOGAMS от OpenSSL( https://github.com/dot-asm/cryptogams/blob/master/x86_64/chacha-x86_64.pl) .
Перечисление основного потока
MountLocker использует ту же функцию для обхода файлов для сетевых дисков, общих сетевых ресурсов и локальных дисков.
Перед обходом диска программа-вымогатель проверяет, предоставлено ли имя файла маркера из аргумента командной строки /MARKER=. Если это так, MountLocker создает пустой файл с этим именем файла маркера на зашифрованном диске перед его перечислением. Это в основном для обозначения того, какой диск был зашифрован.
Для перечисления папок MountLocker вызывает FindFirstFileW и FindNextFileW. При перечислении через сетевые серверы вместо этого будут использоваться WNetOpenEnumW и WNetEnumResourceW.
Программа-вымогатель также вызывает функцию для проверки, следует ли шифровать каждый найденный файл/папку.
При обработке папки функция проверки проверяет следующие вещи. Если что-то из этого верно, папка пропускается.
Ниже приведен список FOLDER_TO_AVOID.
":\\Windows\\", ":\\System Volume Information\\", ":\\$RECYCLE.BIN\\", ":\\SYSTEM.SAV", ":\\WINNT",
":\\$WINDOWS.~BT\\", ":\\Windows.old\\", ":\\PerfLog\\", ":\\Boot", ":\\ProgramData\\Microsoft\\",
":\\ProgramData\\Packages\\", "$\\Windows\\", "$\\System Volume Information\\", "$\\$RECYCLE.BIN\\",
"$\\SYSTEM.SAV", "$\\WINNT", "$\\$WINDOWS.~BT\\", "$\\Windows.old\\", "$\\PerfLog\\", "$\\Boot",
"$\\ProgramData\\Microsoft\\", "$\\ProgramData\\Packages\\", "\\WindowsApps\\", "\\Microsoft\\Windows\\",
"\\Local\\Packages\\", "\\Windows Defender", "\\microsoft shared\\", "\\Google\\Chrome\\", "\\Mozilla Firefox\\",
"\\Mozilla\\Firefox\\", "\\Internet Explorer\\", "\\MicrosoftEdge\\", "\\Tor Browser\\", "\\AppData\\Local\\Temp\\"
Если папка действительна и в ней еще нет файла с примечанием о выкупе, MountLocker поместит в папку примечание о выкупе.
При обработке файла функция проверки проверяет следующее. Если хотя бы одно из них верно, файл пропускается.
- Если размер файла меньше MIN_CRYPT_SIZE (если указано MIN_CRYPT_SIZE) или если размер файла больше MAX_CRYPT_SIZE (если указано MAX_CRYPT_SIZE)
- Если имя файла «RecoveryManual.html», «bootmgr» или имеет зашифрованное расширение файла.
- Если расширение файла находится в списке EXTENSION_TO_AVOID
Ниже приведен список EXTENSION_TO_AVOID.
"exe", "dll", "sys", "msi", "mui", "inf", "cat", "bat", "cmd", "ps1", "vbs", "ttf", "fon", "lnk"
Если файл действителен, основной поток программы-вымогателя заполнит общую файловую структуру именем файла для шифрования своего рабочего потока.
Из-за проблем с синхронизацией основной поток также должен вызывать функции WaitForSingleObject и _InterlockedExchange, чтобы дождаться получения доступа к общей структуре.
После заполнения файловой структуры он вызывает SetEvent, чтобы сигнализировать о событии для шифрования рабочих потоков.
Свойство червя
Подобно WannaCry и Ryuk, этот образец MountLocker представляет собой комбинацию программы-вымогателя и червя с возможностью самораспространения на другие узлы в сети.
В отличие от WannaCry, эта программа-вымогатель не использует какие-либо причудливые 0-day, а вместо этого использует COM-интерфейсы, такие как IDirectorySearch и IWbemServices, для своего распространения и выполнения.
MountLocker имеет эту структуру, которая является общей для всех потоков червя.
Сначала для этой структуры выделяется память и создаются дескриптор события и дескриптор семафора. Функция запуска программы-вымогателя и ее параметр изначально оставлены нулевыми.
MountLocker создает 8 потоков для выполнения этого свойства червя.
Каждый из этих потоков ожидает, когда событие будет сигнализировано основным потоком, прежде чем вызывать функцию червя для удаленного запуска программы-вымогателя. Основной поток соответствующим образом установит эту функцию червя, прежде чем сигнализировать о событии.
После создания этих рабочих потоков основной поток начинает перечисление домена Windows, в котором находится текущий узел.
Это достигается путем вызова NetGetDCName для получения имени основного контроллера домена и добавления этого имени после строки "LDAP:// ".
Облегченный протокол доступа к каталогам (LDAP) (https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) — это протокол для связи и запросов к нескольким различным типам каталогов, и в этом случае MountLocker использует его для выполнения запросов Active Directory к основному контроллеру домена.
Он вызывает ADsOpenObject с новой строкой ADsPath и предоставляет учетные данные (имя пользователя и пароль) из аргументов /LOGIN= и /PASSWORD=. Предоставленный RIID — {109BA8EC-92F0-11D0-A790-00C04FD8D5A8}, и через этот вызов программа-вымогатель получает интерфейс IDirectorySearch.
Этот трюк с запросом IDirectorySearch ранее использовался Trickbot, как объяснил Витали здесь ( https://www.vkremez.com/2017/12/lets-learn-introducing-new-trickbot.html).
Этот интерфейс можно использовать для выполнения поиска всех контроллеров домена с помощью функции IDirectorySearch::ExecuteSearch, которая возвращает дескриптор поиска AD.
MountLocker вызывает IDirectorySearch::GetFirstRow и IDirectorySearch::GetNextRow для перечисления всех поисков, передавая каждый поиск в функцию для извлечения информации о контроллере домена.
Для каждого из этих дескрипторов поиска MountLocker затем вызывает IDirectorySearch::GetColumn с именем столбца "name", чтобы получить соответствующую структуру ADS_SEARCH_COLUMN в этой строке.
Эта структура содержит массив структур ADSVALUE, и каждая из этих структур содержит строку DN объекта службы каталогов в Active Directory. Эта строка отличительного имени (DN) в основном представляет собой имя для идентификации другого ПК в сети.
Когда строка DN ПК извлекается, она передается в функцию, где программа-вымогатель будет использовать ее в качестве параметра функции в структуре WORM_STRUCT. Функция структуры настроена на определенную функцию, которая удаляет и запускает образец удаленно. SetEvent вызывается для выполнения этой функции после того, как структура WORM_STRUCT полностью заполнена.
Функция дропа червя
Сначала поток червя попытается установить соединение с удаленным целевым ПК, вызвав WNetAddConnection2W и предоставив имя пользователя и пароль из аргументов /LOGIN= и /PASSWORD=.
Далее выделяется память для пользовательской структуры. Я просто называю это WORM_REMOTE_STRUCT.
Затем он заполняет эту структуру. Имя исполняемого файла — это число, полученное из GetTickCount, а путь на хосте для удаления программы-вымогателя — "C:\ProgramData".
Функция drop_ransomware проверяет, содержит ли строка DN какое-либо из имен общих ресурсов с более высокими привилегиями "\ADMIN$" и "\IPC$". Если да, то MountLocker использует его как основной путь в команде для запуска исполняемого файла. Если это не так, то он просто использует обычный путь.
Образец программы-вымогателя запускается с параметром /NOLOG и любыми аргументами, указанными в исходном аргументе /PARAMS=.
Наконец, он дропает программу-вымогатель на целевой компьютер, вызывая CopyFileW.
MountLocker не только сбрасывает исполняемый файл программы-вымогателя на целевой ПК, но также перебирает общие ресурсы ПК в сети ПК, вызывая NetShareEnum. Найдя путь к каждому общему ресурсу, программа-вымогатель вызывает drop_ransomware, чтобы удалить исполняемый файл в системе общего ресурса.
Функция запуска червя
MountLocker имеет два разных способа запуска исполняемого файла на удаленном хосте.
Если предоставленный аргумент /NETWORK имеет значение s, он запускает исполняемый файл через службу.
Сначала создается полная команда cmd.exe.
cmd.exe /c start "ransomware_path PARAMS_VALUE /NOLOG"
Затем программа-вымогатель вызывает OpenSCManagerW, чтобы установить соединение с диспетчером управления службами на целевом ПК. Используя этот дескриптор, он вызывает CreateServiceW с приведенной выше командой в качестве параметра lpBinaryPathName для создания дескриптора службы и вызывает StartServiceW для его запуска.
Если предоставленный аргумент /NETWORK имеет значение w, он запускает исполняемый файл с помощью инструментария управления Windows (WMI).
Сначала MountLocker извлекает интерфейс IWbemServices. Это делается путем вызова CoCreateInstance с CLSID {4590F811-1D3A-11D0-891F-00AA004B2E24} для получения объекта IWbemLocator.
Используя этот объект IWbemLocator, он вызывает IWbemLocator::ConnectServer для подключения к пространству имен ROOT\CIMV2 ПК и получения объекта IWbemServices.
Отсюда MountLocker устанавливает соответствующую структуру SEC_WINNT_AUTH_IDENTITY_A с заданными именем пользователя и паролем. Затем он вызывает CoSetProxyBlanket, чтобы установить информацию аутентификации для этого объекта IWbemServices.
Используя этот объект IWbemServices, программа-вымогатель вызывает функцию IWbemServices::GetObjectA с путем "Win32_Process", чтобы получить объект IWbemClassObject, соответствующий процессам Windows32.
Затем, используя этот объект "Win32_Process", он затем вызывает функцию IWbemClassObject::GetMethod с именем метода "Create", чтобы получить объект IWbemClassObject, соответствующий методу создания процесса.
С этим объектом метода он вызывает IWbemClassObject::SpawnInstance для создания нового экземпляра класса.
Поскольку Win32_Process::Create требует допустимого значения для параметра командной строки для правильного выполнения, MountLocker вызывает функцию IWbemClassObject::Put, чтобы установить значение командной строки для команды запуска, которую он построил выше.
Наконец, он вызывает IWbemServices::ExecMethod для создания процесса Win32, выполняющего приведенную выше команду "cmd.exe". Он также проверяет, успешно ли создан новый процесс, проверяя, изменился ли идентификатор процесса с помощью вызова IWbemClassObject::Get.
Если какой-либо из этих шагов по удалению и запуску исполняемого файла не удается, MountLocker просто прибегает к использованию WNetOpenEnumW и WNetEnumResourceW для перечисления через сеть жертвы и аналогичным образом удаляет программу-вымогатель.
Самоудаление
Если для аргумента /NODEL установлено значение 0, MountLocker удалит свой собственный исполняемый файл.
Во-первых, он создает в папке TEMP файл .bat со случайным именем из GetTickCount.
Он записывает эту команду в этот .bat-файл, который очищает атрибуты "Только для чтения", "Системный" и "Скрытый" от исполняемого файла программы-вымогателя, принудительно удаляет исполняемый файл, если он существует, и удаляет файл bat.
attrib -s -r -h %1
:l
del /F /Q %1
if exist %1 goto l
del %0
Затем MountLocker создает строку командной строки для выполнения файла .bat с путем к исполняемому файлу в качестве параметра и, наконец, вызывает CreateProcessW для удаления себя.
Правила для ЯРА
rule MountLocker5_0 {
meta:
description = "YARA rule for MountLocker v5.0"
reference = "http://chuongdong.com/reverse engineering/2021/05/23/MountLockerRansomware/"
author = "@cPeterr"
tlp = "white"
strings:
$worm_str = "========== WORM ==========" wide
$ransom_note_str = ".ReadManual.%0.8X" wide
$version_str = "5.0" wide
$chacha_str = "ChaCha20 for x86_64, CRYPTOGAMS by <appro@openssl.org>"
$chacha_const = "expand 32-byte k"
$lock_str = "[OK] locker.file > time=%0.3f size=%0.3f KB speed=%" wide
$bat_str = "attrib -s -r -h %1"
$IDirectorySearch_RIID = { EC A8 9B 10 F0 92 D0 11 A7 90 00 C0 4F D8 D5 A8 }
condition:
uint16(0) == 0x5a4d and all of them
}
Обзор
Это мой отчет по образцу MountLocker Ransomware v5.0, который используется группой вымогателей XingLocker.
Эта программа-вымогатель использует схему гибридной криптографии RSA-2048 и ChaCha20 для шифрования файлов и защиты своих ключей. В отличие от других программ-вымогателей, MountLocker шифрует все ключи ChaCha20 с помощью глобального ключа ChaCha20, прежде чем шифровать этот глобальный ключ с помощью открытого ключа RSA-2048. Зашифрованный глобальный ключ и соответствующий зашифрованный ключ ChaCha20 добавляются в конце каждого зашифрованного файла.
Эта версия включает в себя новую функцию червя, позволяющую ему самостоятельно распространяться на другие компьютеры в сети с помощью COM-интерфейсов IDirectorySearch и IWbemServices.
MountLocker имеет сложную схему многопоточности, но ее производительность страдает от нехватки потоков из-за рекурсивного обхода файлов.
Я больше не буду тратить свое время на объяснение того, почему рекурсивный обход файлов ужасен, потому что я высказал свое мнение в последних нескольких отчетах. Пожалуйста, не стесняйтесь прочитайте мой анализ Darkside, если вы хотите лучше понять теорию, стоящую за ним!
IOCS
Этот образец версии 5.0 представляет собой 64-разрядный файл .exe.MD5: 3808f21e56dede99bc914d90aeabe47a
SHA256: 4a5ac3c6f8383cc33c795804ba5f7f5553c029bbb4a6d28f1e4d8fb5107902c1
Сэмпл: https://bazaar.abuse.ch/sample/4a5ac3c6f8383cc33c795804ba5f7f5553c029bbb4a6d28f1e4d8fb5107902c1/
Записка с требованием выкупа
Записка о выкупе записывается в формате HTML и помещается в файлы RecoveryManual.html в системе.
Идентификатор клиента, встроенный в записку о выкупе, генерируется из имени компьютера жертвы и жестко запрограммированной строки в памяти.
Производительность
MountLocker имеет довольно среднюю производительность и не полностью использует вычислительную мощность машины.
Статический анализ кода
Параметры командной строки
MountLocker можно запустить как с параметрами командной строки, так и без них. Программа-вымогатель сначала проверяет и анализирует заданные параметры, чтобы соответствующим образом изменить свои функции.
Ниже приведен список аргументов, которые могут быть предоставлены операторами:
Логирование
Программа-вымогатель имеет два разных способа ведения журнала своих операций, и каждый из них можно включить, установив для аргументов командной строки /CONSOLE значение 1 и /NOLOG на 0.
В этом конкретном примере значение флага /NOLOG жестко запрограммировано равным 0, поэтому он всегда записывает и удаляет файл журнала в системе жертвы.
Когда флаг /NOLOG равен 0, MountLocker извлекает путь к текущему исполняемому файлу, добавляет .log в конец и использует его в качестве пути к файлу журнала.
Если флаг /CONSOLE равен 1, MountLocker также будет вести журнал через стандартный поток вывода консоли. Он вызывает AllocConsole и GetStdHandle(STD_OUTPUT_HANDLE), чтобы выделить консоль и получить дескриптор стандартного потока вывода. Для записи в эту консоль он вызывает WriteConsoleW с этим дескриптором.
В начале журнала сообщается версия конкретного образца MountLocker, и в данном случае это версия 5.0.
Он также извлекает и записывает информацию о системе жертвы, такую как количество процессоров, общий объем системной памяти, версию Windows, архитектуру системы и т.д.
Таким образом записываются все файловые и сетевые операции (перебор, пропуск, шифрование, ошибка).
Терминация сервисов
Если аргумент /NETWORK не указан, вредоносное ПО будет работать в локальном режиме.
В этом режиме, если аргумент /NOKILL равен 0, он перечисляет и уничтожает все службы с этими строками в их имени.
"SQL", "database", "msexchange"
Во-первых, он вызывает OpenSCManagerA для получения дескриптора диспетчера управления службами и вызывает EnumServicesStatusA для перечисления всех служб Win32 со статусом SERVICE_ACTIVE.
Если служба содержит любую из трех приведенных выше строк, MountLocker завершит ее, вызвав OpenServiceA для получения дескриптора управления службой и вызвав ControlService для отправки кода остановки управления. Затем он непрерывно зацикливается до тех пор, пока состояние службы не станет SERVICE_CONTROL_STOP, чтобы убедиться, что служба полностью завершена.
Завершение процессов
Если он работает в локальном режиме и аргумент /NOKILL равен 0, MountLocker перечислит и уничтожит все процессы с этими строками в их имени.
"msftesql.exe", "sqlagent.exe", "sqlbrowser.exe", "sqlwriter.exe", "oracle.exe", "ocssd.exe",
"dbsnmp.exe", "synctime.exe", "agntsvc.exe", "isqlplussvc.exe", "xfssvccon.exe", "sqlservr.exe",
"mydesktopservice.exe", "ocautoupds.exe", "encsvc.exe", "firefoxconfig.exe", "tbirdconfig.exe",
"mydesktopqos.exe", "ocomm.exe", "mysqld.exe", "mysqld-nt.exe", "mysqld-opt.exe", "dbeng50.exe",
"sqbcoreservice.exe", "excel.exe", "infopath.exe", "msaccess.exe", "mspub.exe", "onenote.exe",
"outlook.exe", "powerpnt.exe", "sqlservr.exe", "thebat.exe", "steam.exe", "thebat64.exe", "thunderbird.exe",
"visio.exe", "winword.exe", "wordpad.exe", "QBW32.exe", "QBW64.exe", "ipython.exe", "wpython.exe",
"python.exe", "dumpcap.exe", "procmon.exe", "procmon64.exe", "procexp.exe", "procexp64.exe"
Программа-вымогатель сначала вызывает ZwQuerySystemInformation с информационным классом SystemProcessInformation, чтобы получить массив структур SYSTEM_PROCESS_INFORMATION. Он перебирает каждый запущенный процесс, избегает своего собственного процесса и начинает завершать процессы в списке уничтожения.
Чтобы проверить и убить процесс, он проходит по списку PROCESS_TO_KILL и сравнивает имя процесса. Если имя процесса есть в списке, он вызывает OpenProcess, чтобы получить дескриптор этого процесса, и завершает его с помощью TerminateProcess.
Генерация глобального ключа ChaCha20
Затем случайным образом генерируется глобальный ключ ChaCha20. Рандомизация выполняется путем вызова инструкции rdtsc, чтобы получить отметку времени процессора, и операции xor его младшего значащего байта для генерации каждого байта в ключе.
После создания глобального ключа программа-вымогатель копирует ключ в другой глобальный буфер в памяти и шифрует этот новый буфер с помощью жестко запрограммированного ключа RSA-2048.
Позже MountLocker использует этот глобальный ключ ChaCha20 для шифрования и защиты своих ключей ChaCha20 вместо использования RSA-2048. Поскольку шифрование RSA-2048 выполняется только один раз, эта схема гибридной криптографии дает некоторое преимущество в производительности, поскольку RSA довольно медленный по сравнению с ChaCha20.
Шифрование
Создание потоков шифрования
Несмотря на наличие разных схем для разных типов дисков и целей, функциональность шифрования практически одинакова.
MountLocker имеет специальную функцию, которая принимает имя диска/файла для шифрования и функцию для его перечисления в качестве параметров.
Эта функция сначала передает перечисляющую функцию и целевое имя пользовательской структуре, прежде чем создать поток для начала шифрования.
Этот поток действует как основной поток в шифровании, который рекурсивно перечисляет и предоставляет файлы для шифрования дочерним потокам.
Функция основного потока вызывает CreateEventA, чтобы создать обработчик событий для каждого дочернего потока, чтобы позже отправить им информацию о файле посредством вызова SetEvent.
Создаются только 2 дочерних рабочих потока, и эти потоки зацикливаются и ждут получения файлов из основного потока для шифрования. Основной поток начнет подавать им файлы, вызвав функцию перечисления в пользовательской структуре выше и перечислив целевую папку.
Дочерние рабочие потоки
После создания каждый рабочий поток получает общую структуру с основным потоком и постоянно проверяет наличие сигнала шифрования 1 в этой общей структуре.
Из-за синхронизации посредством совместного использования общей структуры среди потоков дочерний поток вызывает _InterlockedExchange для атомарного извлечения сигнала шифрования, чтобы проверить, разрешено ли ему шифрование.
Когда он находит файлы для шифрования, основной поток добавляет имя файла в общую структуру и устанавливает сигнал шифрования для дочернего потока для обработки этого файла.
После получения информации о файле рабочий поток создает структуру для хранения такой информации о файле, как имя файла, зашифрованное имя файла, дескриптор файла, размер файла и т. д.
Затем он проверит, есть ли у него права на открытие файла и получение размера файла.
Затем он случайным образом генерирует ключ файла ChaCha20 и добавляет его к файловой структуре выше. Рандомизация выполняется вызовом инструкции rdtsc аналогично генерации глобального ключа ChaCha20.
После генерации ключа файла ChaCha20 рабочий поток создает 313-байтовый буфер, в котором хранится строка маркера файла "lock2" с прямым порядком байтов, размер быстрого шифрования, зашифрованный глобальный ключ ChaCha20 и зашифрованный ключ файла ChaCha20. Этот буфер добавляется в конец зашифрованного файла.
Вот макет буфера ключей в конце зашифрованного файла.
Шифрование файлов довольно стандартное. Рабочий поток шифрует фрагмент размером 0x100000 байт за раз, пока он не зашифрует байты FAST_CRYPT_SIZE или не закончатся байты для шифрования.
Он использует ReadFile для чтения содержимого файла в буфер, шифрует его с помощью файлового ключа ChaCha20 и записывает обратно с помощью WriteFile. Поскольку шифрование выполняется для одного и того же файла, вызывается SetFilePointerEx для настройки указателя файла после чтения и записи.
Я не буду анализировать функцию ChaCha20, потому что MountLocker просто использует эту библиотеку CRYPTOGAMS от OpenSSL( https://github.com/dot-asm/cryptogams/blob/master/x86_64/chacha-x86_64.pl) .
Перечисление основного потока
MountLocker использует ту же функцию для обхода файлов для сетевых дисков, общих сетевых ресурсов и локальных дисков.
Перед обходом диска программа-вымогатель проверяет, предоставлено ли имя файла маркера из аргумента командной строки /MARKER=. Если это так, MountLocker создает пустой файл с этим именем файла маркера на зашифрованном диске перед его перечислением. Это в основном для обозначения того, какой диск был зашифрован.
Для перечисления папок MountLocker вызывает FindFirstFileW и FindNextFileW. При перечислении через сетевые серверы вместо этого будут использоваться WNetOpenEnumW и WNetEnumResourceW.
Программа-вымогатель также вызывает функцию для проверки, следует ли шифровать каждый найденный файл/папку.
При обработке папки функция проверки проверяет следующие вещи. Если что-то из этого верно, папка пропускается.
Ниже приведен список FOLDER_TO_AVOID.
":\\Windows\\", ":\\System Volume Information\\", ":\\$RECYCLE.BIN\\", ":\\SYSTEM.SAV", ":\\WINNT",
":\\$WINDOWS.~BT\\", ":\\Windows.old\\", ":\\PerfLog\\", ":\\Boot", ":\\ProgramData\\Microsoft\\",
":\\ProgramData\\Packages\\", "$\\Windows\\", "$\\System Volume Information\\", "$\\$RECYCLE.BIN\\",
"$\\SYSTEM.SAV", "$\\WINNT", "$\\$WINDOWS.~BT\\", "$\\Windows.old\\", "$\\PerfLog\\", "$\\Boot",
"$\\ProgramData\\Microsoft\\", "$\\ProgramData\\Packages\\", "\\WindowsApps\\", "\\Microsoft\\Windows\\",
"\\Local\\Packages\\", "\\Windows Defender", "\\microsoft shared\\", "\\Google\\Chrome\\", "\\Mozilla Firefox\\",
"\\Mozilla\\Firefox\\", "\\Internet Explorer\\", "\\MicrosoftEdge\\", "\\Tor Browser\\", "\\AppData\\Local\\Temp\\"
Если папка действительна и в ней еще нет файла с примечанием о выкупе, MountLocker поместит в папку примечание о выкупе.
При обработке файла функция проверки проверяет следующее. Если хотя бы одно из них верно, файл пропускается.
- Если размер файла меньше MIN_CRYPT_SIZE (если указано MIN_CRYPT_SIZE) или если размер файла больше MAX_CRYPT_SIZE (если указано MAX_CRYPT_SIZE)
- Если имя файла «RecoveryManual.html», «bootmgr» или имеет зашифрованное расширение файла.
- Если расширение файла находится в списке EXTENSION_TO_AVOID
Ниже приведен список EXTENSION_TO_AVOID.
"exe", "dll", "sys", "msi", "mui", "inf", "cat", "bat", "cmd", "ps1", "vbs", "ttf", "fon", "lnk"
Если файл действителен, основной поток программы-вымогателя заполнит общую файловую структуру именем файла для шифрования своего рабочего потока.
Из-за проблем с синхронизацией основной поток также должен вызывать функции WaitForSingleObject и _InterlockedExchange, чтобы дождаться получения доступа к общей структуре.
После заполнения файловой структуры он вызывает SetEvent, чтобы сигнализировать о событии для шифрования рабочих потоков.
Свойство червя
Подобно WannaCry и Ryuk, этот образец MountLocker представляет собой комбинацию программы-вымогателя и червя с возможностью самораспространения на другие узлы в сети.
В отличие от WannaCry, эта программа-вымогатель не использует какие-либо причудливые 0-day, а вместо этого использует COM-интерфейсы, такие как IDirectorySearch и IWbemServices, для своего распространения и выполнения.
MountLocker имеет эту структуру, которая является общей для всех потоков червя.
Сначала для этой структуры выделяется память и создаются дескриптор события и дескриптор семафора. Функция запуска программы-вымогателя и ее параметр изначально оставлены нулевыми.
MountLocker создает 8 потоков для выполнения этого свойства червя.
Каждый из этих потоков ожидает, когда событие будет сигнализировано основным потоком, прежде чем вызывать функцию червя для удаленного запуска программы-вымогателя. Основной поток соответствующим образом установит эту функцию червя, прежде чем сигнализировать о событии.
После создания этих рабочих потоков основной поток начинает перечисление домена Windows, в котором находится текущий узел.
Это достигается путем вызова NetGetDCName для получения имени основного контроллера домена и добавления этого имени после строки "LDAP:// ".
Облегченный протокол доступа к каталогам (LDAP) (https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) — это протокол для связи и запросов к нескольким различным типам каталогов, и в этом случае MountLocker использует его для выполнения запросов Active Directory к основному контроллеру домена.
Он вызывает ADsOpenObject с новой строкой ADsPath и предоставляет учетные данные (имя пользователя и пароль) из аргументов /LOGIN= и /PASSWORD=. Предоставленный RIID — {109BA8EC-92F0-11D0-A790-00C04FD8D5A8}, и через этот вызов программа-вымогатель получает интерфейс IDirectorySearch.
Этот трюк с запросом IDirectorySearch ранее использовался Trickbot, как объяснил Витали здесь ( https://www.vkremez.com/2017/12/lets-learn-introducing-new-trickbot.html).
Этот интерфейс можно использовать для выполнения поиска всех контроллеров домена с помощью функции IDirectorySearch::ExecuteSearch, которая возвращает дескриптор поиска AD.
MountLocker вызывает IDirectorySearch::GetFirstRow и IDirectorySearch::GetNextRow для перечисления всех поисков, передавая каждый поиск в функцию для извлечения информации о контроллере домена.
Для каждого из этих дескрипторов поиска MountLocker затем вызывает IDirectorySearch::GetColumn с именем столбца "name", чтобы получить соответствующую структуру ADS_SEARCH_COLUMN в этой строке.
Эта структура содержит массив структур ADSVALUE, и каждая из этих структур содержит строку DN объекта службы каталогов в Active Directory. Эта строка отличительного имени (DN) в основном представляет собой имя для идентификации другого ПК в сети.
Когда строка DN ПК извлекается, она передается в функцию, где программа-вымогатель будет использовать ее в качестве параметра функции в структуре WORM_STRUCT. Функция структуры настроена на определенную функцию, которая удаляет и запускает образец удаленно. SetEvent вызывается для выполнения этой функции после того, как структура WORM_STRUCT полностью заполнена.
Функция дропа червя
Сначала поток червя попытается установить соединение с удаленным целевым ПК, вызвав WNetAddConnection2W и предоставив имя пользователя и пароль из аргументов /LOGIN= и /PASSWORD=.
Далее выделяется память для пользовательской структуры. Я просто называю это WORM_REMOTE_STRUCT.
Затем он заполняет эту структуру. Имя исполняемого файла — это число, полученное из GetTickCount, а путь на хосте для удаления программы-вымогателя — "C:\ProgramData".
Функция drop_ransomware проверяет, содержит ли строка DN какое-либо из имен общих ресурсов с более высокими привилегиями "\ADMIN$" и "\IPC$". Если да, то MountLocker использует его как основной путь в команде для запуска исполняемого файла. Если это не так, то он просто использует обычный путь.
Образец программы-вымогателя запускается с параметром /NOLOG и любыми аргументами, указанными в исходном аргументе /PARAMS=.
Наконец, он дропает программу-вымогатель на целевой компьютер, вызывая CopyFileW.
MountLocker не только сбрасывает исполняемый файл программы-вымогателя на целевой ПК, но также перебирает общие ресурсы ПК в сети ПК, вызывая NetShareEnum. Найдя путь к каждому общему ресурсу, программа-вымогатель вызывает drop_ransomware, чтобы удалить исполняемый файл в системе общего ресурса.
Функция запуска червя
MountLocker имеет два разных способа запуска исполняемого файла на удаленном хосте.
Если предоставленный аргумент /NETWORK имеет значение s, он запускает исполняемый файл через службу.
Сначала создается полная команда cmd.exe.
cmd.exe /c start "ransomware_path PARAMS_VALUE /NOLOG"
Затем программа-вымогатель вызывает OpenSCManagerW, чтобы установить соединение с диспетчером управления службами на целевом ПК. Используя этот дескриптор, он вызывает CreateServiceW с приведенной выше командой в качестве параметра lpBinaryPathName для создания дескриптора службы и вызывает StartServiceW для его запуска.
Если предоставленный аргумент /NETWORK имеет значение w, он запускает исполняемый файл с помощью инструментария управления Windows (WMI).
Сначала MountLocker извлекает интерфейс IWbemServices. Это делается путем вызова CoCreateInstance с CLSID {4590F811-1D3A-11D0-891F-00AA004B2E24} для получения объекта IWbemLocator.
Используя этот объект IWbemLocator, он вызывает IWbemLocator::ConnectServer для подключения к пространству имен ROOT\CIMV2 ПК и получения объекта IWbemServices.
Отсюда MountLocker устанавливает соответствующую структуру SEC_WINNT_AUTH_IDENTITY_A с заданными именем пользователя и паролем. Затем он вызывает CoSetProxyBlanket, чтобы установить информацию аутентификации для этого объекта IWbemServices.
Используя этот объект IWbemServices, программа-вымогатель вызывает функцию IWbemServices::GetObjectA с путем "Win32_Process", чтобы получить объект IWbemClassObject, соответствующий процессам Windows32.
Затем, используя этот объект "Win32_Process", он затем вызывает функцию IWbemClassObject::GetMethod с именем метода "Create", чтобы получить объект IWbemClassObject, соответствующий методу создания процесса.
С этим объектом метода он вызывает IWbemClassObject::SpawnInstance для создания нового экземпляра класса.
Поскольку Win32_Process::Create требует допустимого значения для параметра командной строки для правильного выполнения, MountLocker вызывает функцию IWbemClassObject::Put, чтобы установить значение командной строки для команды запуска, которую он построил выше.
Наконец, он вызывает IWbemServices::ExecMethod для создания процесса Win32, выполняющего приведенную выше команду "cmd.exe". Он также проверяет, успешно ли создан новый процесс, проверяя, изменился ли идентификатор процесса с помощью вызова IWbemClassObject::Get.
Если какой-либо из этих шагов по удалению и запуску исполняемого файла не удается, MountLocker просто прибегает к использованию WNetOpenEnumW и WNetEnumResourceW для перечисления через сеть жертвы и аналогичным образом удаляет программу-вымогатель.
Самоудаление
Если для аргумента /NODEL установлено значение 0, MountLocker удалит свой собственный исполняемый файл.
Во-первых, он создает в папке TEMP файл .bat со случайным именем из GetTickCount.
Он записывает эту команду в этот .bat-файл, который очищает атрибуты "Только для чтения", "Системный" и "Скрытый" от исполняемого файла программы-вымогателя, принудительно удаляет исполняемый файл, если он существует, и удаляет файл bat.
attrib -s -r -h %1
:l
del /F /Q %1
if exist %1 goto l
del %0
Затем MountLocker создает строку командной строки для выполнения файла .bat с путем к исполняемому файлу в качестве параметра и, наконец, вызывает CreateProcessW для удаления себя.
Правила для ЯРА
rule MountLocker5_0 {
meta:
description = "YARA rule for MountLocker v5.0"
reference = "http://chuongdong.com/reverse engineering/2021/05/23/MountLockerRansomware/"
author = "@cPeterr"
tlp = "white"
strings:
$worm_str = "========== WORM ==========" wide
$ransom_note_str = ".ReadManual.%0.8X" wide
$version_str = "5.0" wide
$chacha_str = "ChaCha20 for x86_64, CRYPTOGAMS by <appro@openssl.org>"
$chacha_const = "expand 32-byte k"
$lock_str = "[OK] locker.file > time=%0.3f size=%0.3f KB speed=%" wide
$bat_str = "attrib -s -r -h %1"
$IDirectorySearch_RIID = { EC A8 9B 10 F0 92 D0 11 A7 90 00 C0 4F D8 D5 A8 }
condition:
uint16(0) == 0x5a4d and all of them
}