Одним из главных инструментов любой хакерской группировки является вредоносное ПО. В зависимости от уровня квалификации хакеров и особенностей операции, они могут использовать как массовые, зачастую публично доступные инструменты (типичным примером может быть фреймворк Cobalt Strike), так и собственные разработки.
Создание уникального набора инструментов для каждой атаки требует большого количества ресурсов, поэтому вредоносное ПО так или иначе переиспользуется как в различных операциях одной группы, так и среди дружественных группировок. Массовое использование одного и того же инструмента неизбежно приводит к его попаданию на радары антивирусных компаний, и, как следствие, к снижению его эффективности.
Чтобы бороться с этой проблемой, хакеры используют техники упаковки, шифрования и мутации кода. Такие техники часто реализуют отдельные инструменты — «крипторы» (crypters), иногда называемые просто «пакерами». В этой статье на примере банковского трояна RTM мы рассмотрим, какие пакеры могут использовать злоумышленники, как эти пакеры осложняют обнаружение конкретного ВПО и какие еще вредоносы ими упаковываются.
Packer-as-a-service
Хакерская группа, стоящая за распространением RTM, до конца 2020 года регулярно проводила массовые фишинговые рассылки с вредоносными вложениями. Этот процесс, по всей видимости, происходил автоматически.
Каждое такое вложение содержало существенно отличающиеся друг от друга файлы, при этом итоговая полезная нагрузка практически не менялась.
Подобная особенность — естественное следствие применения крипторов. Первоначально группа, стоящая за RTM, использовала свой собственный уникальный криптор, однако в течение 2020 года дважды его сменила.
При исследовании по-новому упакованных образцов нам удалось обнаружить множество другого ВПО, которое было защищено аналогичным образом. Пересечения с другими вредоносами с учетом автоматизации процесса упаковки, на наш взгляд, позволяют говорить об использовании злоумышленниками модели packer-as-a-service. В этой модели упаковка вредоносных файлов делегируется специальному сервису, которым управляет третья сторона.
Доступ к таким сервисам часто продается на хакерских форумах.
Далее мы рассмотрим конкретные примеры крипторов, которые были применены группой RTM.
Rex3Packer
Первое использование этого пакера группой RTM, которое нам удалось обнаружить, относится к ноябрю 2019 года. Активное же его применение, по нашим данным, приходится на период апрель—май 2020 года. Единичные случаи использования этого пакера для распространения старых версий трояна RTM мы также наблюдали в конце января 2021 года.
Нам не удалось связать этот упаковщик с каким-либо из ранее описанных публично, поэтому мы дали ему свое название по трем особенностям его устройства: наличию рекурсии (recursion), реверса битов (reverse), и рефлективной загрузки PE-файлов (reflection) — Rex3Packer.
Алгоритм распаковки
Общий алгоритм извлечения полезной нагрузки выглядит так:
- С помощью VirtualAlloc выделяется заранее определенное количество памяти с правами на чтение, запись и исполнение.
- В выделенный буфер копируется содержимое образа текущего процесса в памяти (в частности, секция .text).
- Управление передается на функцию внутри буфера.
- Вычисляется разница между положением одних и тех же данных в буфере и в образе PE-файла (разность между адресами в буфере и виртуальными адресами в образе). Эта разность заносится в регистр ebx. Все обращения к виртуальным адресам в коде проиндексированы содержимым этого регистра. За счет этого, везде, где это необходимо, к адресам из PE-образа добавляется поправка, которая позволяет получить соответствующий адрес в буфере.
- Выделяется еще один буфер под упакованные данные.
- Через вызов VirtualProtect устанавливаются права RWX на весь регион памяти с образом PE-файла.
- Упакованные данные копируются в свой буфер.
- Происходит декодирование упакованных данных.
- Регион памяти с образом PE заполняется нулевыми байтами.
- Декодированные данные представляют собой исполняемый файл — PE-нагрузку. Эта полезная нагрузка рефлективно загружается на место исходного PE-образа, и управление передается на ее точку входа.
Отдельный интерес представляет специфический алгоритм декодирования упакованных данных. В данном случае некорректно говорить об упаковке, как о сжатии: алгоритм устроен так, что размер упакованных данных всегда больше размера исходных.
Непосредственно упакованным данным предшествует заголовок размером 16 байт, который содержит 4 поля по 4 байта:
- размер самого заголовка,
- размер исходных данных (PE-нагрузки),
- позиция в исходных данных (*), по которой происходит их разделение (об этом ниже),
- режим кодирования (1, 2, либо 4).
Декодирование выполняется следующим образом:
- Внутри каждого байта выполняется реверс порядка битов (к примеру, 10011000 становится 00011001).
- В зависимости от режима кодирования (1, 2, 4) данные разбиваются на блоки размером N = 9, 5, либо 3 байта соответственно. Результат декодирования блока — это (N – 1) байт (то есть 8, 4, или 2).
- В первых N-1 байтах блока отсутствует часть битов: их значения всегда равны нулю. Чтобы восстановить оригинальные байты, с помощью масок вида 00000001, 00010001 или 01010101 из последнего байта блока извлекаются недостающие биты. При этом для каждого следующего байта маска сдвигается. То есть последний байт блока фактически составлен из объединенных логической операцией OR битов, которые извлечены из предыдущих байтов.
Например, в режиме 4 последний байт состоит из четных битов первого байта блока и нечетных битов второго байта блока. В результате возврата этих битов в первый и второй байты, получается оригинальная последовательность из двух байт.
- После операции по восстановлению битов во всех блоках полученные данные представляют собой исходный PE-файл, который был разделен по позиции (*) на две части. Эти части, в свою очередь, были переставлены между собой. Обратная перестановка с учетом значения (*) позволяет получить оригинальный файл.
Обфускация
Чтобы усложнить анализ, в пакере применяются несколько техник добавления «мусорного» кода :
-
В промежутках между исполнением полезных команд делаются вызовы различных функций WinAPI. Их результаты сохраняются, но не используются, а сами функции выбираются так, чтобы не влиять на работу программы.
-
Характерная особенность данного пакера — наличие циклов (не выполняющих полезных операций), которые реализуются через рекурсивную функцию.
-
Для дополнительного запутывания в исполняемый файл добавляется несколько десятков случайно сгенерированных функций. Они могут ссылаться друг на друга, но в процессе работы ни одна из них не получает управления.
Использование
Кроме экземпляров RTM, мы обнаружили использование Rex3Packer для упаковки различного ВПО, в основном имеющего происхождение из стран СНГ. Ниже расположен список некоторых примеров таких вредоносов.
Семейство ВПО | SHA256 |
---|---|
Phobos Ransomware | 6e9c9b72d1bdb993184c7aa05d961e706a57b3becf151ca4f883a80a07fdd955 |
Zeppelin Ransomware | 8d44fdbedd0ec9ae59fad78bdb12d15d6903470eb1046b45c227193b233adda6 |
Raсcoon Stealer | 3be91458baa365febafb6b33283b9e1d7e53291de9fec9d3050cd32d98b7a039 |
KPOT Stealer | 9b6af2502547bbf9a64ccfb8889ee25566322da38e9e0ccb86b0e6131a67df1e |
Predator The Thief | d1060835793f01d1e137ad92e4e38ef2596f20b26da3d12abcc8372158764a8f |
QakBot | 18cc92453936d1267e790c489c419802403bb9544275b4a18f3472d2fe6f5dea |
Также мы отметили использование пакера для упаковки экземпляров ВПО из семейств Nemty, Pony, Amadey. Безусловно, приведенные нами примеры — это далеко не все случаи использования Rex3Packer.
HellowinPacker
В мае 2020 группа RTM переключилась на использование нового упаковщика, который продолжала активно использовать до начала 2021 года. Мы назвали его HellowinPacker из-за встречающихся в некоторых экземплярах строк с именем файла hellowin.wav.
Ключевой особенностью этого пакера является два уровня мутации кода. Первый из них существенно меняет структуру кода распаковки, делая различные образцы не похожими друг на друга.
На примере выше можно увидеть сравнение образцов 5b5f30f7cbd6343efd409f727e656a7039bff007be73a04827cce2277d873aa0 (слева) и 1f9a8b3c060c2940a81442c9d9c9e36c31ad37aaa7cd61e1d7aec2d86fe1c585 (справа).
Второй уровень меняет лишь отдельные детали при неизменной в целом структуре кода. При этом изменения главным образом затрагивают ассемблерные инструкции и не влияющие на работу программы константы. В результате в декомпилированном виде код выглядит практически идентичным.
Так же, как и в случае с Rex3Packer, мы имеем дело с массовым использованием HellowinPacker для упаковки различного ВПО. При этом вредоносное ПО из одного семейства, как правило, имеет в упакованном виде одну и ту же структуру. Это можно пронаблюдать, по крайней мере, на протяжении некоторого времени — затем структура может измениться.
Все эти особенности хорошо согласуются с описанием одного из сервисов упаковки, доступ к которому продается на хакерских форумах:
По всей видимости, в каждый такой уникальный криптор закладывается собственная структура генерируемого кода. При этом сам криптор также умеет изменять код, но уже на более низком уровне, не меняя структуру программы в целом. В любом случае содержание «полезного» исполняемого кода остается одинаковым.
Алгоритм распаковки
Одни из первых действий, которые встречаются во всех упакованных файлах — это попытки открыть ключ реестра HKEY_CLASSES_ROOT\Interface\{b196b287-bab4-101a-b69c-00aa00341d07} (регистр символов в конкретном случае может отличаться) и запросить в нем значение по умолчанию (Default). От успешности этих операций в некоторых модификациях генерируемого кода зависит корректное продолжение работы программы.
GUID интерфейса в разных случаях также может отличаться. Вот некоторые из возможных вариантов:
- {3050f1dd-98b5-11cf-bb82-00aa00bdce0b}
- {aa5b6a80-b834-11d0-932f-00a0c90dcaa9}
- {683130a6-2e50-11d2-98a5-00c04f8ee1c4}
- {c7c3f5a1-88a3-11d0-abcb-00a0c90fffc0}
- {b8da6310-e19b-11d0-933c-00a0c90dcaa9}
Дальнейший код некоторым образом получает адрес, по которому располагается блок зашифрованных данных.
Этот блок начинается с четырехбайтного числа, которое хранит размер исходных данных (тех, которые будут получены после декодирования). Вызовом VirtualAlloc под расшифрованные данные выделяется блок памяти нужного размера с правами RWX. В выделенную память блоками по X байт копируются зашифрованные данные. При этом в оригинальном файле между этими блоками располагаются пропуски длиной Y байт.
Затем происходит процесс дешифровки блоками по 4 байта:
- очередной блок интерпретируется как целое число (DWORD),
- к его значению прибавляется индекс первого байта в блоке,
- выполняется операция XOR между полученным значением и суммой индекса и фиксированного ключа, числа Z.
Пример реализации алгоритма на Python:
def decrypt(data, Z): index = 0 while index < len(data): dword = struct.unpack("<I", data[index:index + 4])[0] dword = (dword + index) & (2 ** 32 - 1) dword = dword ^ (index + Z) data[index:index + 4] = struct.pack("<I", dword) index += 4
Значения X, Y и Z варьируются в зависимости от конкретного упакованного экземпляра.
Внутри дешифрованных данных располагается следующая стадия извлечения полезной нагрузки — шеллкод. Он получает управление после окончания расшифровки.
Шеллкод самостоятельно загружает необходимые для своей работы функции, имена которых прописаны в таблице импорта, находящейся в начале дешифрованных данных.
Для большей вариативности строки в таблице импорта могут частично заполняться посторонними символами. Так, в примере выше, первое имя функции — GetProcAddress — полностью заменено на строку aaa45678901234; кроме того, повреждены имена VirtualAlloc и VirtualProtect. Непосредственно перед обработкой таблицы шеллкод восстанавливает корректные значения для всех символов.
Полезная нагрузка (на этот раз, это PE-файл) извлекается шеллкодом из оставшейся части дешифрованных данных. Она вновь зашифрована, причем тем же алгоритмом, который описан выше. В качестве ключа Z всегда используется число 1001.
После окончательной расшифровки шеллкод производит рефлективную загрузку PE-файла, используя для этого импортированные на первом этапе функции.
Обфускация
Как и в случае с Rex3Packer, в экземплярах с HellowinPacker встречаются вызовы функций WinAPI, не относящихся к основной логике программы. Однако в данном случае они используются скорее как способ затруднить поведенческий анализ и детектирование в песочницах. В пользу этого предположения говорит то, что в большинстве случаев разнообразные функции вызываются подряд в самом начале программы.
Дополнительным эффектом от такого использования WinAPI становится невозможность детектирования по списку импортируемых функций и imphash.
При работе с различными числовыми значениями часто встречается некоторая арифметическая обфускация: необходимые константы представляются в виде суммы или разности других констант (в определенных случаях равной нулю). При этом для получения констант могут быть использованы и вызовы функций WinAPI, дающие предсказуемый результат (например, 0 в случае неудачи).
Пример такой обфускации приведен на рис. 17: единственная задача данной функции — присвоить глобальной переменной, на которую указывает target, значение аргумента source. В данном случае результат вызова GetStockObject(789644) всегда будет равняться нулю, поскольку функции передан заведомо некорректный аргумент.
Разного рода мутации встречаются и на ассемблерном уровне: вставка «мусорных» команд, непрозрачные предикаты (opaque predicates), передача неиспользуемых аргументов в функции и повторные вызовы функций, изменение инструкций на эквивалентные.
Использование
HellowinPacker существует по крайней мере с 2014 года. За это время он был использован в различном массовом вредоносном ПО. Вот лишь несколько примеров:
Семейство ВПО | SHA256 |
---|---|
Cerber Ransomware | 1e8b814a4bd850fc21690a66159a742bfcec212ccab3c3153a2c54c88c83ed9d |
ZLoader | 44ede6e1b9be1c013f13d82645f7a9cff7d92b267778f19b46aa5c1f7fa3c10b |
Dridex | f5dfbb67b582a58e86db314cc99924502d52ccc306a646da25f5f2529b7bff16 |
Bunitu | 54ff90a4b9d4f6bb2808476983c1a902d7d20fc0348a61c79ee2a9e123054cce |
QakBot | c2482679c665dbec35164aba7554000817139035dc12efc9e936790ca49e7854 |
Пакер неоднократно упоминался в отчетах других исследователей. Самое раннее упоминание, которое нам удалось найти, относится к 2015 году. В своей статье о крипторах специалисты Malwarebytes в качестве примера исследуют образцы с HellowinPacker. Другие исследователи позже напишут о нем, как об упаковщике Emotet: (1, 2). Уже в 2020 году наши коллеги из NCC Group дадут ему название CryptOne и опишут его применение для упаковки вымогателя WastedLocker. По данным NCC Group, он также использовался в таких семействах ВПО, как Netwalker, Gozi ISFB v3, ZLoader, Smokeloader.
Заключение
Пример с использованием крипторов позволяет проиллюстрировать разделение обязанностей в хакерской среде, в особенности среди массового ВПО. Разработка вредоносной нагрузки, ее защита от антивирусов (крипт) и доставка конечному пользователю может выполняться совершенно не связанными между собой хакерами, при этом каждый элемент в этой цепочке может предоставляться как сервис. Такой подход снижает порог входа для технически не подготовленных киберпреступников: для проведения массовой атаки достаточно обладать лишь необходимой суммой денег на оплату всех сервисов.
Описанные нами упаковщики, конечно же, далеко не единственные из существующих на рынке. При этом они хорошо демонстрируют общие свойства подобного рода инструментов: в результате их работы получается исполняемый файл с обфусцированным полиморфным кодом распаковщика и шифрованной тем или иным образом полезной нагрузкой. Мутации в коде и переиспользование одних и тех же крипторов делают практически невозможным статическое детектирование полезной нагрузки. Однако поскольку эта нагрузка так или иначе расшифровывается в память и начинает свою вредоносную деятельность, поведенческий анализ с использованием песочниц (таких, как PT Sandbox) позволяет обнаруживать ВПО и давать точные вердикты даже для упакованных файлов. Помимо этого, нужно отметить, что упаковщики никак не влияют на взаимодействие вредоносов с управляющими серверами. Это даёт возможность определять присутствие ВПО в сети, используя инструменты анализа трафика – такие, как PT Network Attack Discovery.
Вердикты наших продуктов
PT Sandbox
-
Trojan.Win32.RTM.a
-
Trojan.Win32.RTM.b
-
Trojan-Banker.Win32.RTM.a
-
Trojan-Banker.Win32.RTM.b
-
Trojan-Banker.Win32.RTM.c
-
Trojan-Banker.Win32.RTM.d
-
Trojan-Banker.Win32.RTM.e
-
Trojan-Banker.Win32.RTM.f
PT Network Attack Discovery
-
REMOTE [PTsecurity] TeamBot/RTM
sid: 10004412; -
BACKDOOR [PTsecurity] TeamBot/RTM
sid: 10004415; -
MALWARE [PTsecurity] RTM Banker CnC POST
sid: 10000765; -
MALWARE [PTsecurity] RTM.N (Redaman)
sid: 10005556; 10005557; -
MALWARE [PTsecurity] Spy.RTM.AF
sid: 10005468; -
MALWARE [PTsecurity] Trojan[Banker]/RTM
sid: 10004855; 10004875; -
MALWARE [PTsecurity] Win32/Spy.RTM.N (Redaman)
sid: 10003414; 10004754; 10005555; -
PAYLOAD [PTsecurity] RTM.Payload.xor
sid: 10005585;
IOCs (RTM)
Дата обнаружения | Криптор | SHA256 | SHA1 | MD5 |
---|---|---|---|---|
19.04.2020 | RTM | a4229a54f76815ac30a2a878eadf275e199c82da657dbc5f3fc05fe95603c320 | ad22ceb309dd30dc769f63174292657fe07f0ced | 80b116708f75de212b49ff994ad8b43e |
22.04.2020 | Rex3Packer | 9b88e8143e4452229dac7fdcc3d9281d21390f286c086f09aec410f120dc4325 | f881729f6a5ca6fe80f385a2b0f8583b19214466 | 3965b819eb945a9c0defc746bbc8ed7a |
13.05.2020 | HellowinPacker | 43e8ebacfa319ff7d871eef3cc35266cfa7c6f44dd787f27a48311e39727e10f | 8a28b75285409c55d5bbeca62e3819c83c8e663f | afd18be08d135f7bf07007c1c9041126 |
28.01.2021 | Rex3Packer (2 слоя) | fbf5974daee93bf5a2ed1816a4edbb108ceccb264d3e3f72d0aed268dd45e315 | 2e3352c6341ce57a03aaf2c4fbf484f3a0a4bfe3 | 6e0c8510443586cdc8f84330e447aae5 |