Упаковщик: нет
Дата компиляции:
11.01.2018 12:16:21 (версия для архитектуры x86)
SHA1-хеш:
- 7797107eb4a9a9e4359413c15999603fa27714b3
Описание
Многофункциональный троян-бэкдор, работающий в среде 32- и 64-битных операционных систем семейства Microsoft Windows. Представляет собой исполняемую библиотеку, написанную на C++. Использует классы векторов и строк из библиотеки стандартных шаблонов (STL). Основная функция трояна — получение несанкционированного доступа к зараженным компьютерам и выполнение вредоносных действий по команде злоумышленников.
Принцип действия
Библиотека содержит следующие экспортируемые функции:
ServiceMain
mymain
Основная функциональность трояна представлена в mymain.
Функция mymain
При вызове функция через GetTempFileNameW генерирует имя временного файла с префиксом rar и открывает его для записи. Этот файл используется в качестве журнала. Запись в него происходит в следующем формате:
[%d-%02d-%02d %02d:%02d:%02d] %d %d\n%s\n\n" => "[YYYY-MM-DD HH:MM:SS] <rec_id>
<error_code>\n<record>\n\n
где:
- rec_id — идентификатор типа записи;
- error_code — код ошибки (в большинстве случаев имеет значение 0); если возникает ошибка в процессе выполнения, записывается значение GetLastError() или WSAGetLastError();
- record — дополнительные данные.
Перед добавлением в журнал записываемые данные побайтно кодируются операцией XOR с байтом 0x31. Таблица значений идентификаторов rec_id представлена в конце описания.
Далее выполняется сбор информации о зараженной системе:
struct sysinfo
{
DWORD dword_0;
DWORD is_VMWare;
WCHAR str_test[8]; //возможно ID
DWORD dword_1;
BYTE user_name[64];
BYTE gap_0[64];
WCHAR host_IP[20];
DWORD osver_Major;
DWORD osver_Minor;
DWORD uiANSI_CP;
DWORD uiOEM_CP;
WCHAR host_name[15];
BYTE gap_1[98];
BYTE user_SID[128]; //string SID
DWORD osver_ProductType;
BYTE is_Wow64process;
BYTE mac_address[12];
BYTE gap_2[3];
DWORD number_of_processors;
DWORD total_phys_mem_MBytes;
};
Затем происходит проверка, работает ли библиотека в среде виртуальной машины VMWare. Если это так, соответствующая информация добавляется к собранным сведениям о системе, при этом троян не прекращает свою работу.
В исходном коде BackDoor.Logtu.1 прописаны адреса нескольких управляющих серверов, которые зашифрованы операцией XOR с байтом 0x11. Однако для управления бэкдором используется только первый адрес из списка ниже:
104.194.215[.]199;
192.168.1[.]115;
www.test[.]com.
Кроме того, в трояне хранится массив портов, каждый элемент которого соответствует одному из серверов выше:
443, 443, 80
В BackDoor.Logtu.1 предусмотрено использование прокси-сервера, однако в рассматриваемом примере он отсутствует. Адрес прокси-сервера при его наличии также побайтно закодирован операцией XOR с байтом 0x11.
По завершении предварительной подготовки троян запускает цикл подключений к управляющему серверу через TCP-сокет. При первом соединении BackDoor.Logtu.1 пытается подключиться к серверу напрямую. В случае неудачи он использует прокси-сервер HTTP, если его адрес зашит в теле трояна. Если это не удалось, троян извлекает параметры прокси-сервера из ключа реестра HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer и пытается установить соединение. В случае очередной неудачи бэкдор пытается получить данные прокси-сервера через WinHTTP API, отправляя запрос к google[.]com с помощью функции WinHttpGetProxyForUrl. Если и эта попытка оказывается неудачной, BackDoor.Logtu.1 пытается извлечь соответствующие настройки из ключа реестра HKU\<session_user_SID>\...\ProxyServer. Цикл повторяется до тех пор, пока трояну не удастся подключиться к серверу.
После успешного подключения BackDoor.Logtu.1 отправляет на сервер сведения о системе. Отправка данных и получение ответа от сервера проходит в два этапа:
- отправка пакета с длиной полезной нагрузки;
- отправка полезной нагрузки.
Значение пакета длины размером 4 байта равно <payload_len>+4. Это объясняется тем, что в пакете с нагрузкой есть четырехбайтный префикс, содержащий идентификатор нагрузки. В результате полезная нагрузка имеет следующий формат:
struct payload
{
DWORD payload_id;
BYTE payload[payload_len];
}
Передаваемые от трояна на сервер и обратно данные шифруются алгоритмом RC4. Ключ шифрования зашит в трояне в виде отдельной строки, но вычисляется с использованием следующего алгоритма:
from hashlib import md5
password = "123456"
salt = md5("").hexdigest()
key = md5(password + salt).hexdigest()
Идентификатор пакета с информацией о системе имеет значение 0.
После отправки данных о системе и получения ответа троян запускает поток, который раз в минуту отправляет пакеты-маячки. Их идентификатор имеет значение 1, а значение длины нагрузки — 0. После отправки 10 таких пакетов подключение к серверу завершается и выполняется вновь.
В ответ от сервера бэкдор ожидает пакет со значением длины, которая не должна превышать 0x1F40. Затем он ожидает сам пакет, в котором содержится полезная нагрузка в виде команды. После его расшифровки выполняется проверка значения первого DWORD, который является идентификатором команды. Значение идентификатора не должно превышать 0x34.
В некоторых случаях команда содержит дополнительные параметры в виде строк, разделенных символом |. Структура такой команды имеет вид "param_0"|"param_1"|...|"param_n".
Список команд, которые может принимать и выполнять троян, представлены в следующей таблице:
Идентификатор команды | Описание команды |
---|---|
0x00 | NOP |
0x01 | Вызывает GetTickCount(), записывает результат в глобальную переменную. |
0x02 | В команде поступает 2 параметра, разделенные символом |. Первый параметр является путем к файлу. Троян формирует из него два новых пути:
Затем он проверяет, существует ли файл с исходным именем, указанным в команде. Если да, троян отправляет на сервер ответ <param_1>|01. Если нет — проверяет наличие файла <param_0>.tu. Если такой файл существует, троян отправляет на сервер его размер в виде <param_1>|<size>. Если файл <param_0>.tu не существует, троян создает файл <param_0>tut, записывает в него строку из 32 нулей и удаляет его. В зависимости от результатов выполнения команды троян может передавать на сервер различные варианты ответов. В случае неудачи на каком-либо этапе выполнения команды он отправляет <param_1>|<code>, где code может иметь значение от 01 до 05. |
0x03 | Создать процесс приложения с именем <param_0> и параметрами командной строки <param_1>. |
0x04 | Запустить в отдельном потоке перечисление процессов и поочередно отправить информацию о них на сервер. Перед началом перечисления на сервер отправляется пакет с идентификатором 0x17 и полезной нагрузкой в виде DWORD 0x47. Отправка происходит в следующем виде:
При этом self_module_path передается только тогда, когда процесс не работает в среде WOW64. В противном случае данная строка заполнена нулевыми значениями. |
0x05 | Запускает поток командной строки cmd.exe. Создает процесс cmd.exe с перенаправлением ввода-вывода в именованные каналы (пайпы). После создания процесса либо отправляет пакет с идентификатором 0x17 и нагрузкой 0x3D в случае успешного создания, либо 0x3E при неудаче. При этом параметры ввода для командной строки получает из сообщения c помощью функции GetMessage. Результаты выполнения отправляются с идентификатором 0x06. |
0x06 | Ввод параметров для cmd.exe. При помощи PostThreadMessage отправляет потоку cmd.exe сообщение 0x464 и помещает данные из команды в lParam. |
0x08 | Закрывает соединение, отправляя перед этим пакет с идентификатором 0x17 и нагрузкой в виде DWORD 0x3E, после чего удаляет службу и свой исполняемый файл. |
0x09 | Открывает файл для записи с конца и пишет в него буфер из полученной команды. Параметры команды:
К param_0 дописывает расширение .tu, открывает (или создает) получившийся файл для записи, устанавливает указатель на конец файла, записывает буфер param_4. Если param_3 равен 1, то удаляет файл param_0 и переименовывает файл <param_0>.tu в param_0. |
0x14 | Получить размер заданного в команде файла. |
0x15 | Считать из файла param_0 0x1000 байт, начиная с param_2, и отправить на сервер результаты с идентификатором 0x15. |
0x16 | Удалить заданный файл. В случае успеха передает на сервер пакет с идентификатором 0x17 и нагрузкой в виде DWORD 0x1F; в случае ошибки передается пакет с идентификатором 0x20. |
0x17 | Если первый DWORD тела команды равен 1, то засыпает на 1 секунду; если 2 — закрывает дескриптор (handle) файла. |
0x18 | Завершить процесс с заданным PID. В ответ передает на сервер пакет с идентификатором 0x17. В случае успеха с этим идентификатором также отправляется DWORD 0x0B, в случае неудачи — 0x0C. |
0x19 | Получение информации о дисках. Получив эту команду, троян проверяет все доступные диски от A до Z и отправляет информацию по каждому из них на сервер.
Информация о дисках передается в виде следующей структуры:
При этом, если обнаруженный диск имеет тип DRIVE_REMOVABLE или DRIVE_CDROM, в параметре cdrom_or_removable указывается значение 1. Перед перечислением дисков троян отправляет структуру disk_info со значением dword_1, равным 1, а также остальными членами, равными 0. |
0x20 | Получить список файлов в заданной директории. Список формируется в виде строк формата <file_name>;<file_size>;<last_write_time(YYYY-MM-DD hh:mm:ss)>;<is_dir>, разделенных символом |.
Если объект представляет собой каталог, значение <is_dir> указывается равным 1; если это файл — 0. |
0x22 | Создание TCP-туннеля. Эта команда содержит параметры хоста, к которому необходимо подключиться. Параметры поступают в виде следующей структуры:
где index — индекс туннеля. После подключения к заданному хосту троян получает от него блок размером до 0x400 байт и пересылает его на управляющий сервер в виде такой структуры:
После отправки последнего блока троян передает индекс с идентификатором 0x24. |
0x23 | Отправить данные в туннель. Управляющий сервер передает структуру tunnel_data, после чего троян пересылает данные в туннель с индексом tunnel_data.index. |
0x24 | В этой команде содержится индекс туннеля, который необходимо закрыть. |
0x25 | В этой команде приходит структура tunnel_host. Троян создает TCP-сокет, привязывает его на порт tunnel_host.port (port binding) и ожидает входящее соединение.
При приеме входящего соединения троян отправляет на сервер пакет нулевой длины без полезной нагрузки с идентификатором 0x25, после чего принимает данные от нового соединения и вместе с идентификатором 0x26 пересылает их на управляющий сервер. |
0x26 | Команда содержит структуру tunnel_data. Получив эту команду, троян отправляет данные в соединение, принятое по команде 0x25. |
0x28 | Завершить поток, отсылающий маячки. |
0x29 | Переместить файл из param_0 в param_1. |
0x31 | Создать скриншот рабочего стола. |
0x33 | Получить список работающих служб в виде строк <service_name>;<service_display_name>;<current_state>, разделенных символом |. |
0x34 | Команда управления службами.
Если param_0 имеет значение 0, останавливает службу param_1; Если param_0 имеет значение 1, запускает службу param_1. |
При получении команды с идентификатором 0x17 троян закрывает дескриптор файла, который хранится в глобальной переменной. Этот файл используется только дважды: при получении указанной команды, а также в функции записи в журнал.
Закрытие дескриптора файла:
Запись в журнал:
Таблица значений идентификаторов типа записи в журнале
Идентификатор rec_id | Код ошибки | Тип записи в журнале | Описание |
---|---|---|---|
0x01 | 0 | Нет | Записывается в начале исполнения. |
0x0E | 0 | Имя управляющего сервера | |
0x0F | WSAGetLastError() | Нет | Вносится при ошибке подключения к управляющему серверу. |
0x07 | 0 | Имя прокси-сервера | |
0x08 | 0 | Нет | Вносится перед подключением к прокси-серверу. |
0x09 | GetLastError() | Нет | Вносится, если не удалось подключиться к прокси-серверу. |
0x0A | 0 | CONNECT <proxy_addr>:<proxy_port>
HTTP/1.1\r\nProxy-Authorization: Basic <proxy_auth>\r\n\r\n
либо CONNECT <proxy_addr>:<proxy_port> HTTP/1.1\r\n\r\n, если Отсутствуют параметры авторизации на прокси-сервере |
Строка подключения к HTTP-прокси. |
0x0B | GetLastError() | Нет | Вносится при возникновении ошибки подключения к прокси-серверу. |
0x0C | GetLastError() | Нет | Вносится при получении пустого ответа от прокси-сервера. |
0x0D | 0 | Ответ от прокси-сервера | Вносится при успешном подключении к прокси-серверу. |
0x05 | GetLastError() | Нет | Вносится, когда не удалось открыть ключ реестра HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings. |
0x06 | 0 | Строка not find proxy address, зашитая в теле трояна | Вносится, если не удалось получить значение параметра ProxyServer из реестра. |
0x03 | 0 | Нет | Вносится, когда пакет с информацией о системе отравлен через прокси-сервер, адрес которого зашит в теле трояна. |
0x04 | 0 1 2 |
Нет Нет Нет |
Вносится, когда информация о системе отправлена через прокси-сервер:
из реестра в разделе HKCU; полученный с помощью WinHTTP API; из реестра в разделе HKU\<session_user_SID> |
0x02 | 0 | Нет | Вносится, когда информация о системе отправлена на сервер напрямую. |
0 | Нет | Вносится после отправки на сервер информации о системе и перед запуском потока с пакетами-маячками. |