Рекламные объявления

Анализ исходного кода шифровальщика HelloKitty

Сборка и почерк.

С целью анализа был взят исходный код, утёкший в паблик 10.10.2023.
Программа написана на языке C++ (используется стандарт C++17 и поддержка Windows XP) и собиралась на MSVS 2015.
Теги файлов проекта свидетельствуют о создании исходного кода на русскоязычной ОС.

В путях включений сборки присутствуют:

c:\Projects\LockerInnocentFork\lk\NTRUEncrypt\include\
c:\Projects\LockerInnocentFork\lk\mbedtls\include

наводящие на мысль о форке некоего проекта LockerInnocent. Информации по нему я не нашел (но и не особо искал).

Алгоритм.

Математически шифрование реализовано с использованием библиотеки криптографических примитивов mbedtls и алгоритма NTRUEncrypt, который на данный момент считается устойчивым ко взлому квантовыми компьютерами. NTRU создан в 1996 году в качестве альтернативы RSA и алгоритмам на основе эллиптических кривых (ECC), и считается всё ещё плохо изученным.

Ключ генерируется с флагом NTRU_EES743EP1

что согласно приложенной документации является аналогом RSA с длиной ключа 1920 байт.

Публичный ключ длиной 1028 байт вшивается один для каждого отдельного билда HelloKitty.

Начальная стадия.

Исполнение шифровальщика начинается с запрета системе ронять программу при критических ошибках и запрета закрытия консоли по Ctrl + C.
Далее идёт формирование записки с выкупом с SHA256 публичного ключа.
Производится запись времени начала работы и по окончании шифрования отображается затраченное время.
Идёт проверка единственно поддерживаемого ключа командной строки: -path «путь». Если он указан, шифруется только эта папка.
Через WMI удаляются теневые копии и чистится содержимое корзины и создаются потоки.

Скорость, параллелизация и поиск​.

Для обработки файлов заранее создаются потоки в кол-ве, равному числу ядер процессора * 2, что считается довольно эффективным. Файлы обрабатываются асинхронно с получением уведомления об окончании через I/O completion port, после чего происходит шифрование очередного блока или файла в том же потоке без создания нового.

Для замера и отображения скорости создаётся отдельный поток, который сбрасывает счётчик каждую 1 секунду и выводит замеры скорости чтения и записи в заголовок консольного окна.

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

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

Сам поиск реализован через FindFirstFileW и рекурсию, что при сравнительном анализе с другими шифровальщиками по данным исследователя Chuong Dong является сильно не оптимальным и может приводить к переполнению стека. Существуют линейные алгоритмы рекурсивного поиска без рекурсии на базе кучи, лишенные этого недостатка.

Следующие файлы и папки пропускаются:

Часть из них отвечает за этап загрузки системы и при их изменении ОС не сможет запуститься.

Файлы размером <= 1 МБ не обрабатываются. За документы небольшого размера можно не переживать 

Если файл имеет атрибут «Только чтение», этот атрибут убирается.

Запись файла и его структура.

Файлы жертвы открываются через CreateFileW с шарингом прав на чтение и асинхронным режимом работы. Делается это сразу тем же потоком, что ищет файлы. А как мы помним выше, число этих потоков = числу дисков. Файлы могли бы открываться в бесконечном кол-ве. Для решения этой проблемы при перечислении файлов проверяется максимальное число уже открытых файлов. Поток уходит в бесконечный цикл повторной проверки этого значения, если оно выше 200.

Дескриптор файла ассоциируется с портом ввода-вывода.

Этот же поток читает первый блок данных, заполняя OVERLAPPED структуру первичными данными, нужными для шифрования (см. далее).

А за запись и чтение последующих блоков данных отвечают уже другие потоки (те, что = кол-ву ядер *2). Они вытаскивают из очереди I/O порта завершенные операции чтения/записи и обрабатывают очередной блок данных произвольного файла.

Если чтение первого блока неудачно, I/O операция отменяется.

В процессе шифрования блоков файла, I/O порт в указателе OVERLAPPED удерживает служебную структуру over_struct, имеющую всю информацию о ходе шифрования конкретного файла:

такую как путь к файлу, его размер, текущий блок данных, сид, контекст класса криптографии.

Файл обрабатывается блоками максимум по 160 КБ (DEFAULT_BLOCK_SIZE).

Поле operation держит текущее состояние объекта, по которому определяется, что делать дальше с текущим блоком или указателем файла.

*retry поля не задействованы, но по задумке, похоже, были ответственны за повторную попытку чтения/записи в случае неудачи.

Эта структура включает в себя другую структуру – enc_header, необходимую для обработки файла:

В качестве сигнатуры (магического числа) используется значение 0xBAADC0DE

encType содержит опциональные флаги, один из:

ENCTYPE_FULL_FILE = 2 (обработка файла целиком)
ENCTYPE_RANDOM_BLOCKS = 4 (обработка рандомных участков)
ENCTYPE_LIMIT_FILE_SIZE = 8 (ограничение длины файла для обработки)
ENCTYPE_USE_CRC32 = 16 (создание контрольной суммы самого заголовка для верификаци, что он не повреждён)
qwMaxEnctyptionSize – ограничение максимальной длины обработки файла (для флага ENCTYPE_USE_CRC32).
endBlockCrc32 – CRC32 заголовка (для флага ENCTYPE_USE_CRC32).
aes_key и aes_iv – ключ и вектор инициализации.

Затем байты структуры enc_header шифруются и записываются в конец файла (поле ntru_encrypted) в виде структуры enc_end_of_file_ntru:

туда же пишется cipherLen (размер ntru_encrypted в байтах) и сигнатура флага о завершении шифрования со значением ENCRYPTED_FILE_FLAG (0xABCCDCDA + 1).

В конце файл переименовывают, добавляя расширение .kitty

Конфигурация билда.

Конфигурация вшита в сам исходный код.

и содержит поля:

  • configSignature (не используется, содержит число 0xAAEECCD0)
  • реальный размер блока
  • максимальная длина файла для обработки, в случае включения режима bFullFileEncrypt
  • флаг включения записи и проверки контрольной суммы CRC32 заголовка хвоста
  • флаг «Шифрования файла целиком»
  • флаг «Шифровать рандомные блоки» (должен быть обязательно выбран либо этот флаг, либо шифрование целиком).

Стандартные настройки: шифрование рандомных блоков размером 160 КБ, и проверка CRC32.

Сетевые функции.

Перед запуском поиска на сетевых дисках, основной поток понижает свои права элегантным способом (обычно используют токен, украденный у другого процесса) – в данном случае в коде текущий процесс получает развернутую информацию о своем собственном токене, а именно связянный с ним limited token, т.к. по сути повышение прав осуществляется присоединением к текущему (limited) токену elevated токена.

Делается это, потому что обычно сетевые диски подключаются из-под ограниченных прав, и через evelated token не видны.

Поиск сетевых шар реализован через функцию WNetOpenEnumW. Для поиска файлов для каждой из шар создаётся отдельный поток, исполняющий тот же, код что и поиск локальных файлов. В дальнейшем их шифрованием занимается общий с локальными файлами набор потоков. Это может привести к блокировке всей процедуры шифрования, если к примеру, попадётся один сильно заторможенный сетевой ресурс.

Максимальное число потоков поиска (сетевых и локальных) жестко ограничено пределом в 64. В противном случае, все последующие сетевые ресурсы пропускаются.

Записка о выкупе.

В каждой директории создаётся вымогательская записка с именем read_me_lkdtt.txt
Для связи со злоумышленниками предлагается перейти на сайт, расположенный на сервисе в сети Tor.

Защита и снятие блокировок с файла

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

Самоудаление реализовано с задержкой через пинг на loopback и командой cmd, однако в исходнике вызов закомментирован.

Код никак не защищен от отладки или запуска внутри песочниц. Вероятно, используется дополнительный криптор, обрабатывающий уже готовую сборку либо иное решение, маскирующее процесс и его активность.

Работа шифровальщика завершается ожиданием всех потоков поиска и достижением кол-ва открытых дескрипторов файлов числа 0.

Мертвый код.

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

В исходнике закомментирован функционал, отвечающий за убийство процессов по списку. Что примечательно в комплекте идёт список из аж 1686 имён процессов.

Дешифровщик.

Создаёт мютекс «EnigmaThread«, чтобы предотвратить повторный запуск

Дешифровка выполняется в обратном порядке через извлечение структуры enc_end_of_file_ntru из хвоста файла и ее расшифровку приватным ключом, вшитым в конкретный билд.
Обработка файлов выполняется в многопоточном режиме через пул потоков и синхронное I/O с открытием файла через \\?\ префикс, а значит поддержкой длинных путей.
Если в конфиге билда была выбрана опция расчёта CRC32, то расшифрованный заголовок сверяется с контрольной суммой, правда уже после попытки расшифровать файл. В случае несовпадения, файл не будет переименован.

Дешифровщик также поддерживает ключ командной строки -path «» для выбора конкретного пути расшифровки.

Выводы делайте сами ​

Статья написана для развития умения читать чужой код, лучшего понимания техник работы современных зловредов и возможностей по поиску артефактов, коих в HelloKitty скажем, не так уж много; а также в виду желания выпустить хоть какую-то статью за долгое время перерыва, сделав ее в стиле статей блога эксперта реверсинга Chuong, который умеет писать также подробно и красиво, при этом не имея на руках исходного кода 

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

Статья составлена Dragokas и является интеллектуальной собственностью SafeZone.cc
Перепубликация на другие ресурсы без письменного разрешения администратора запрещена.