Как стать автором
Обновить
77.46
Солар
Безопасность за нами

Зловред PlugX: как мы встретили старого знакомого в новом обличии

Уровень сложностиСложный
Время на прочтение15 мин
Количество просмотров3K

Бэкдор PlugX многим хорошо известен. Зловред нацелен на хищение самого дорогого – конфиденциальной информации. В 2022 году в рамках одного из расследований наша команда Solar JSOC CERT наткнулась на очередной сэмпл этого вредоноса. Главной его особенностью было то, что он использовался для продвижения в локальной сети заказчика, а не для связи с управляющим сервером. И это далеко не все, чем интересна новая версия PlugX в сравнении с предыдущей. Подробности расскажем в этом посте.

Загрузка

Сэмпл состоит из двух файлов:

  • dbgeng.dll

  • desktop.ini

Файл dbgeng.dll выступает в роли загрузчика полезной нагрузки, которая содержится в desktop.ini. Мы обнаружили несколько вариантов dbgeng.dll, но все они имеют одинаковую функциональность: считать файл и передать ему управление. Однако некоторые из них серьезно обфусцированы.

Итак, dbgeng.dll открывает файл С:\ProgramData\Microsoft\DeviceSync\desktop.ini, считывает оттуда данные и передает управление на четвертый байт.

Файл desktop.ini содержит:

  • зашифрованную и запакованную полезную нагрузку;

  • шелл-код, который расшифровывает ее и передает ей управление.

По смещению 6 от начала файла desktop.ini находится переход к функции расшифровки:

Вызов функции распаковки и заголовок зашифрованной полезной нагрузки
Вызов функции распаковки и заголовок зашифрованной полезной нагрузки

Следом после инструкции перехода по смещению 11 находится структура, которая содержит ключ для расшифровки, размер запакованных и распакованных данных:

Структура зашифрованной и запакованной полезной нагрузки
Структура зашифрованной и запакованной полезной нагрузки

Алгоритм расшифровки самописный (код ниже). Алгоритм сжатия – LZNT1.

def __decrypt (buffer, key):
    res = []
    for i in buffer:
        key += 1
        res.append((key + (key ^ ((i + (0x100 - key) & 0xff))) & 0xff)
    return bytes(res)

В результате распаковки полезной нагрузки в памяти оказывается полноценный PE-файл, где нулевыми байтами затерты:

  • dos-заголовок (за исключением указателя на PE-заголовок по смещению 0x3c);

  • dos-stub;

  • сигнатура PE-заголовка.

Заголовок расшифрованной полезной нагрузки
Заголовок расшифрованной полезной нагрузки

Далее PE-файл загружается в память и управление передается на entrypoint выгруженного исполняемого файла.

Работа распакованного файла

Вначале идет попытка установки привилегий SeDebugPrivilege и SeTcbPrivilege. После –   проверка, в каком контексте запущен исполняемый файл. Если он работает не в контексте msiexec.exe или winlogon.exe, то вредонос запускает процесс msiexec.exe и внедряется в него. Основная нагрузка запускается, если вредоносный код загружен в контексте msiexec.exe. Winlogon.exe используется для работы плагинов от аутентифицированных пользователей. Далее рассмотрены варианты работы данного вредоносного файла в контексте winlogon.exe и msiexec.exe.

Выбор варианта работы вредоносного файла в зависимости от контекста, в котором он работает
Выбор варианта работы вредоносного файла в зависимости от контекста, в котором он работает

Работа в контексте процесса msiexec.exe

На этапе инициализации, вредоносный файл запускает следующие потоки:

  1. Поток для обработки UDP и установки входящих соединений.

  2. Поток для мониторинга аутентифицированных сессий. Если находит, то внедряет себя в процесс winlogon.exe.

Также на данном этапе производится проверка ключа реестра "SOFTWARE\Clients\Mail", где хранится случайное значение и инициализируются плагины. Описание плагинов приведем ниже в отдельном разделе.

Далее идет запуск потоков-обработчиков команд, приходящих извне. Количество потоков зависит от количества следующих вшитых структур:

struct port_struct
{
  MW_SOCK_TYPE type;
  char gap;
  __int16 port;
};
enum MW_SOCK_TYPE, width 1 byte
{
    TCP = 1,
    UDP = 2
};

В данном сэмпле присутствуют две структуры со значениями:

  1. Тип сокета: TCP, порт: 8081

  2. Тип сокета: UDP, порт: 5356

На каждую такую структуру запускается поток обработки приема соединения. Разницы в функционале между типами сокетов нет. При поступлении нового соединения запускается поток обработки команд. Данные, приходящие от интерфейса-коннектора, обрабатываются одинаково для каждого из двух типов сокетов. Чтобы это стало возможным, для каждого типа сокета (TCP, UDP) реализован свой класс-коннектор с одинаковым интерфейсом. Ниже подробно описан класс работы по протоколу UDP. Класс, реализующий взаимодействие по протоколу TCP, является примитивным и в основном ограничивается вызовом системных функций.

Создание слушающего сокета и ожидание принятия соединения
Создание слушающего сокета и ожидание принятия соединения

Код, представленный на рисунке выше, универсальный как для TCP, так и для UDP. Поэтому здесь следует немного уточнить.

При запуске TCP-сервера требуется последовательное выполнение следующих функций или их аналогов: socket(), bind(), listen(), accept().

Здесь же выполняются две функции: listen() и accept().

Функция socket_listen() TCP-класса содержит вызовы следующих команд socket(), bind() и listen(). В данной функции инициализируется сокет, устанавливаются необходимые параметры, сокет привязывается к порту и запускается прослушивание порта. Если рассмотреть вариант UDP-сокета, то для запуска сервера требуется лишь два вызова: socket() и bind(). Также в этот список еще стоит добавить функцию recvfrom(), которая напрямую отвечает за получение данных. Однако в рамках данной реализации функция recvfrom() играет роль функции accept(). Это происходит из-за того, что поверх UDP реализован свой протокол взаимодействия. Таким образом, вызовом socket_listen() инициализируется UDP-сокет и соответствующий ему класс, необходимый для обработки пакетов, поступающих по протоколу UDP, о чем подробнее будет ниже. Функция socket_accept() ожидает появления "входящего соединения". Непосредственно само активное ожидание реализовано в отдельном потоке, который запускается при инициализации вредоноса.

struct socket_class_vt
{
  __int64 (__fastcall *socket_listen)(socket_class *this, __int16 port);
  __int64 (__fastcall *socket_close)(socket_class *this);
  __int64 (__fastcall *socket_accept)(socket_class *this, conn_handler **conn_handler);
};

Интерфейс принятия соединения

Класс-коннектор, осуществляющий взаимодействие по TCP, довольно простой. Он не реализует никаких дополнительных уровней абстракции и протокол взаимодействия с RAT-командами реализован поверх TCP.

+-----------------+
| RAT protocol |
+-----------------+
|       TCP       |
+-----------------+

1. Обработка команд

После принятия соединения запускается поток с обработкой входящих команд.

Изучаемый сэмпл имеет 5 команд:

Команда

Описание

0

Запустить прокси

1

Отправить команду на другой сервер

2

Отправить основные сведенья о текущем компьютере: имя пользователя, имя компьютера, IP-адрес, MAC-адрес

3

Запустить функции выбранного плагина

4

Перечислить все запущенные RDP-сессии

5

Завершить работу текущего сэмпла

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

Каждая команда имеет заголовок и раздел с данными. Общий формат данных для всех приходящих команд выглядит так:

 	struct buffer_generic
{
  buffer_general_header header;
  _BYTE                 data[header.data_packed_size];
};
struct buffer_general_header
{
  _WORD   rnd_val;
  _WORD   gap_2;
  command command;
  _WORD   gap_6;
  _WORD   data_unpacked_size;
  _WORD   data_packed_size;
  _DWORD  session_id;
};
union command
{
  _WORD         cmd; // кроме плагинов, есть возможность вызвать иные функции вредоноса
  cmd_for_union plugin; // для болле корректного отображения в IDA Pro, пришлось создать отдельную структуру, так как в данном WORD, используется старший байт для определения id плагина.
};
struct cmd_for_union
{
  char gap;
  char plugin_id;
};

В заголовке (16 байт) обязательно передается команда, размер запакованных данных (сколько байт данных необходимо еще получить) и размер распакованных данных (размер данных после распаковки в байтах).

После заголовка идут данные, которые приходят в зашифрованном и запакованном виде.

Алгоритм шифрования: RC4, ключ: хеш-сумма MD5 от заголовка данных (первые 16 байт).

Алгоритм сжатия: lznt1.

Отдельно отмечу: если пришли данные помимо заголовка, то перед обработкой команды из header.command вычитается значение header.sm_rnd_val. Также, учитывая тот факт, что заголовок пакета служит для шифрования передаваемых данных, поле rnd_val нужно, скорее всего, для того, чтобы ключ шифрования отличался при одном и том же заголовке. Можем предположить, что сделано это для усложнения выявления заголовка на основе только лишь дампа сетевого трафика.

Операция вычитания над полем header.command
Операция вычитания над полем header.command

2. Класс, реализующий взаимодействие по UDP.

Здесь нужно особое внимание. Поверх UDP реализован протокол, который не связан с вредоносной функциональностью. Он служит для взаимодействия по UDP и отправки данных, что показано на схеме ниже. Далее будем называть его PlugXUDP. Так как он напрямую не отвечает за вредоносную активность, а лишь является дополнительным слоем для взаимодействия сервера и клиента по протоколу UDP, остановимся лишь на некоторых интересных моментах. Далее по тексту текущий экземпляр назовем «сервер». А источник внешнего подключения к серверу – «клиент»

+-------------------+
|  RAT protocol  |
+-------------------+
|    PlugXUDP    |
+-------------------+
|        UDP         |
+-------------------+

Благодаря протоколу PlugXUDP появляется возможность:

  • поддерживать несколько одновременных сессий, которые не пересекаются между собой;

  • регулировать размер пакета для принятия данных со стороны изучаемого сэмпла;

  • снизить вероятность потери пакета, что актуально при работе по UDP.

Для работы данного протокола, при инициализации ратника, запускается отдельный поток. Он предназначен для получения и отправки пакетов и не связан напрямую с обработкой команд ратника. При запуске потока создается соединение – структура, в которой хранятся тип соединения и другие необходимые данные для работы самописного сетевого протокола. Под типом соединения подразумеваются следующие варианты:

  • тип для приема новых подключений - он устанавливается при создании UDP-сокета.

  • тип для установленных соединений – он используется для дальнейшего взаимодействия: отправка и прием данных.

На каждый запрос установки соединения создается подобная структура с другим типом соединения.

У PlugXUDP-протокола есть свой набор команд, который помогает устанавливать связь, отправлять и получать данный с сервера. Основные из них приведены ниже:

Команда

Описание

0x30

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

0x34

Отправка данных

0x39, 0x35

Получение данных

Тип команды передается первыми двумя байтами. Дальше идут параметры команды:

  • Размер фрейма (то есть UDP-пакеты, которые используются для передачи данных). Далее при получении данных с сервера размер фрейма будет ограничен этим значением. Минимальный размер фрейма: 38 байт, где 22 байта отводится на заголовок PlugXUDP протокола, следовательно, минимальный объем передаваемых данных – 16 байт.

  • Идентификатор клиента. При установке соединения сервер создает структуру, описывающую соединение. Она содержит множество данных, среди которых есть идентификатор клиента (6 байт). При дальнейшем взаимодействии с сервером необходимо обращаться именно к этой структуре.

  • Верхний предел количества отправляемых пакетов. То есть сколько пакетов (отличных друг от друга) может быть передано. Но это значение может быть далее изменено командами запроса данных.

При подсоединении к серверу первой должна быть отправлена команда 0x30. Она отвечает за установку соединения и передачу двух параметров: максимальный размер пакета и идентификатор участника.

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

Структура пакета 0x30
Структура пакета 0x30

Идентификатора клиента состоит из двух значений, которые имеют следующие размеры: два и четыре байта. Если изучать код, то изначально это похоже на порт и IP-адрес. На рисунке ниже sock_addr_out содержит действительные адрес и порт клиента, которые приходят из функции WSARecvFrom. Поле s_addrinfo_recved_id_44 – идентификатор клиента. Однако не обнаружено, чтобы эти данные использовались где-то, кроме как при проверке выбранной структуры. Фактически на место двух этих полей можно поставить любое значение.  Также это дает возможность клиенту организовывать сессии, различая их идентификатором клиента, так как данные значения отправляются сервером при отправке любого пакета.

Проверка идентификатора клиента и входящего адреса, полученного из функции WSARecvFrom
Проверка идентификатора клиента и входящего адреса, полученного из функции WSARecvFrom

После установки соединения начинается взаимодействие с возможностью отправлять команды RAT. Для этого используются команды 0x34 и 0x39 (0x35).

Команда 0x34 нужна для отправки данных. В ней передается номер фрейма с данными, что необходимо при фрагментации команды на несколько фреймов. Далее идут передаваемые данные. Причем не обязательно будет заголовок RAT-команды, так как она может быть разделена на несколько пакетов. И в таком случае в начале раздела данных будет идти продолжение RAT команды. Также в начале структуры пакета передается идентификатор клиента и идентификатор соединения, который приходит в ответ на установку соединения (команду 0x30).

Структура пакета команды 0x34
Структура пакета команды 0x34

Для получения ответа с сервера, если данные не вместились в один фрейм, который приходит в ответ на команду 0x34, необходимо использовать команду 0x39. В ней передается номер фрейма. Также есть возможность увеличить лимит передаваемых фреймов. Здесь стоит отметить, что нельзя отправить команду на получение номера предыдущего фрейма и уменьшить лимит передаваемых фреймов. То есть значение номера фрейма должно быть меньше, чем отправленное ранее значение.

Структура пакета команды 0x39
Структура пакета команды 0x39

Команды 0x39 и 0x35 отличаются набором необходимых данных. Команда 0x35 позволяет менять некоторые значения, используемые во взаимодействии по протоколу PlugXUDP.

Ниже представлен алгоритм для отправки RAT-команд по UDP.

Алгоритм отправки команды по UDP-протоколу
Алгоритм отправки команды по UDP-протоколу

Работа в контексте процесса winlogon.exe

При работе в контексте процесса winlogon.exe создается именованный пайп с названием \\.\PIPE\X%d, где %d – пид текущего процесса. После инициализируются плагины (этот процесс и их работа описаны ниже). Команды поступают через именованный пайп. Далее команда парсится и вызывается плагин, соответствующий текущей команде. Благодаря такой технике у вредоноса появляется возможность выполнять функционал плагинов от лица аутентифицированного пользователя. Здесь используется тот же формат данных, что и при обработке команд при работе в контексте процесса msiexec.

Плагины

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

struct generic_plugin_interface
{
  void (__fastcall *destructor)(generic_plugin_handler *this, __int64 bool_destroy);
  void (__fastcall *init_plugin)(generic_plugin_handler *this, unsigned __int8 *plugin_id_out);
  void (__fastcall *run_plugin_handler)(generic_plugin_handler *this, conn_handler_tcp *conn_handler, buffer_generic *buf);
  void (__fastcall *graceful_shutdown)(generic_plugin_handler *this);
};

Функция init_plugin вызывается при инициализации плагина. В ней инициализируются поля класса, и, если необходимо, запускаются потоки для дальнейшей корректной работы плагина. После вызова функции ссылка на объект кладется в глобальный массив. Идентификатор плагина – индекс в массиве этой глобальной переменной.

Функция run_plugin_handler выполняет обработку команды для плагина. Команда плагина состоит из двух байт: где младший байт – команда плагина, старший – идентификатор. Именно поэтому при обработке RAT-команд берется старший байт.

Список плагинов и краткое их описание:

Инициализация двух плагинов
Инициализация двух плагинов

Plugin id

Название

CMD

Описание

2

File system management

0x200

Перечислить диски

 

 

0x201, 0x206

Перечислить файлы в директории

 

 

0x202

Открыть файл при помощи вызова функции ShellExecuteExW

 

 

0x203

Операции над файлами: переместить, копировать, удалить

 

 

0x205

Считать файл с заданного отступа

 

 

0x207

Создать файл и продолжить запись в существующий с заданного отступа

3

Interactive shell with PIPES

0x300

Запустить интерактивную командную оболочку

4

Proxy

0x400

Превратить данное соединение в туннель

 

 

0x401

Подключиться к заданной машине

 

 

0x402

Отправить данные на указанное установленное соединение

 

 

0x403

Завершить указанное соединение

5

Screenshot

0x500

Сделать скриншот с указанными размерами

 

 

0x502

Отправить серию скриншотов для мониторинга происходящих действий. Задать размеры изображения также возможно

7

Logs keys and clipboard.

0x700

Прочитать файл ntuser.dat.log1

 

 

0x701

Прочитать файл ntuser.dat.log2

 

 

0x702

Стереть содержимое файла ntuser.dat.log1

 

 

0x703

Стереть содержимое файла ntuser.dat.log2

6

Interactive shell with CONIN$, CONOUT$

0x600

Запустить эмуляцию telnet

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

Плагин "2"

Создан для взаимодействия с файлами: «хождение» по папкам, загрузка и выгрузка файлов. Его отличает возможность дозаписывать данные или писать по определенному отступу, что позволяет восстанавливать запись в результате возможного обрыва соединения.

struct fs_plugin_handler
{
  fs_plugin_vt *vt;
};

Плагин "3"

Создаются два именованных пайпа для взаимодействия с процессом =\.\pipe\sI%d= (%d – это адрес объекта класса для взаимодействия с сервером). Далее запускается процесс и два потока, которые обрабатывают взаимодействие клиента и запущенного процесса через созданные именованные пайпы. После это соединение служит для работы в режиме интерактивной командной оболочки, пока не завершится процесс или соединение не прервется. Данные, присылаемые от клиента, приходят ровно в том же формате, в котором происходит взаимодействие с RAT-командами. То есть сохраняются заголовок и шифрование.

struct interactive_shell_plugin_handler
{
  interactive_shell_plugin_vt *vt;
  _QWORD sI_pipe;
  _QWORD sO_pipe;
  _QWORD hadnle_to_sI_pipe_IO;
  _QWORD hadnle_to_sO_pipe_IO;
  PROCESS_INFORMATION process_info;
  _QWORD event_handler;
  conn_handler_tcp *conn_handler;
};

Плагин "4"

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

Вначале запускается два потока. Первый – обрабатывает данные, приходящие с подключенных сетевых узлов. Второй – обрабатывает команды, приходящие от клиента (подключиться к сетевому узлу, отправить данные и завершить соединение).

struct portmap_plugin_handler
{
  portmap_plugin_vt *vt;
  conn_handler_tcp *conn_h;
  _QWORD event_handler;
  CRITICAL_SECTION crit_sec;
  CRITICAL_SECTION crit_sec2;
  _DWORD sync_counter;
  portmap_plugin_session sessions[1024];
};
struct __declspec(align(8)) portmap_plugin_session
{
  _QWORD session_id;
  _DWORD socket;
};

Плагин "5"

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

struct screen_plugin_handler
{
  screen_plugin_vt *vt;
};

Плагин "6"

Предоставляет доступ к интерактивной командной оболочке через объекты "CONIN$" и "CONOUT$", что позволяет эмулировать соединение по Telnet. Это дает возможность управлять дочерними процессами, запущенными в рамках текущей сессии, даже если потоки stdin, stdout и stderr не наследуются дочерним процессом.

struct __declspec(align(8)) console_plugin_handler
{
  sixth_plugin_fns *vt_0;
  conn_handler_tcp *conn_h_8;
  _QWORD event_h_10;
  PROCESS_INFORMATION process_info_18;
  char input_buffer_30[32]; // to track new input packets
  _WORD console_width_50;
  _WORD console_height_52;
  __declspec(align(8)) _DWORD console_buffer_size_58;
  struct _CHAR_INFO *p_to_prev_buf_60;
  struct _CHAR_INFO *p_to_cur_buf_68;
};

Плагин "7"

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

  • файл %USERPROFILE%\AppData\Roaming\ntuser.dat.LOG1 – используется для сохранения нажатий клавиш;

  • файл %USERPROFILE%\AppData\Roaming\ntuser.dat.LOG2 – используется для сохранения буфера обмена.

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

struct keylogger_plugin_handler
{
  keylogger_plugin_vt *vt;
  _QWORD qw_8; // unused field
};

Сравнение с прошлой версией PlugX

Теперь давайте сравним найденный нами вариант PlugX с исследованиями компании "Dr.Web" за 2020 год.

Начнем с загрузки и шифрования. Файл, анализируемый экспертами Dr.Web, также сначала ищет файл по конкретному пути на зараженной системе и после считывания файла передает ему управление. Особенностью «нашего» загрузчика (код, который первым выполняется при передаче управления файлу desktop.ini) является то, что он не обфусцирован. Также не обфусцированы и строки в полезной нагрузке. При расшифровке полезной нагрузки можно наблюдать следующие изменения:

  • структура зашифрованной полезной нагрузки стала проще и теперь хранит лишь саму полезную нагрузку,

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

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

В итоге также расшифровывается PE-файл со сбитыми заголовками. Единственное отличие в нашем случае: сигнатуры "MZ" и "PE" затерты нулевыми байтами, а не "XV".

При переходе к полезной нагрузке она принимает в качестве аргумента ссылку на большую структуру конфигурации вредоносной программы, где содержатся IP-адреса C&C и иная информация. В нашем сэмпле не наблюдается подобной большой структуры. Это может быть обусловлено тем, что наш изучаемый сэмпл – это сервер, который самостоятельно не инициирует никакого подключения. Также не обнаружено проверки неиспользуемых глобальных переменных или аргументов функции dllMain, что можно интерпретировать как следы наличия единой кодовой базы для клиентского серверного приложения.

В начале инициализации полезной нагрузки процесс внедряется в другие найденные процессы:

  • в нашем случае это winlogon;

  • в случае Dr.Web это "IEFrame" для версии 28, или запуск "msiexec.exe" с присвоенным маркером доступа для версии 38.

Также отличается протокол сетевого взаимодействия с управляющим сервером:

  • ключ для шифрования данных – это дворд, а не весь заголовок целиком;

  • также в новой версии указывается размер распакованных данных.

Эти отличия не позволяют старому и новому экземплярам PlugX взаимодействовать между собой.

Плагины в исследуемой версии PlugX утратили названия и временную отметку. В исследуемом нами экземпляре вредоносного ПО структура плагина – это лишь таблица виртуальных методов. Также плагинов гораздо меньше и нет возможности загрузить новый из внешнего файла. Ниже представлена таблица сравнения идентификаторов плагинов нашей версии и версии, описанной Dr. Web:

Plugin id

Описание

ID PlugX.28

Название плагина

2

File system management

3

Disk

3

Interactive shell with PIPES

7

Shell

4

Proxy

11

Portmap

5

Screenshot

4

Screen

7

Logs keys and clipboard.

14

KeyLogger

6

Interactive shell with CONIN$, CONOUT$

0x71

Telnet

Заключение

В заключение отметим ключевые особенности найденного нами экземпляра PlugX. Он имеет ограниченное количество плагинов в сравнении с более старшей версией (6 из 13 плагинов), но зато имеет более богатый функционал для удобства сетевого взаимодействия:

  • построение туннелей, основанных на протоколе PlugX;

  • плагин Portmap позволяет устанавливать до 1024 соединений одновременно в отличие от предыдущей версии, где возможно только одно соединение.

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

IOC

Хеш-суммы файлов:

Filename

MD5

SHA256

dbgeng.dll.0

fcdf8aa50123aaf5fb6cbed60263d157

f52a69f048b8649a0c404d80d612f63f07fe6af01c1ea6927472acb6818e88a9

dbgeng.dll.1

677cbbcf6e2a6751fcda0b9418c408c8

6f8f7cc88d2d8367df63c1fd566044bcca3708f6a6fa9fa4a50608a6a87857dd

dbgeng.dll.2

d0d46a95cf902831874134c35eb4b740

d48b8be84b5ccd955aade8a467d33accfbb61b22529dbf3a73e23f27e87155ed

desktop.ini

af4103ad7339fc0c12362087c6c424f0

3560b8a7c076ed959190cc3910b776d0a4dcf9673aaa03778615cb775476b12b

Автор: Владимир Нестор, инженер технического расследования Solar JSOC CERT

Теги:
Хабы:
Всего голосов 7: ↑7 и ↓0+7
Комментарии1

Публикации

Информация

Сайт
rt-solar.ru
Дата регистрации
Дата основания
2015
Численность
1 001–5 000 человек
Местоположение
Россия