Даты компиляции:
- 02:57:54 31.03.2020 (версия для архитектуры x86)
- 02:57:51 31.03.2020 (версия для архитектуры x64)
SHA1-хеши:
- 2510e873e79cfb61533e9b5a124ddbec130c653c (версия для архитектуры x86)
- d6e84ad926cc1d5a3d300a98f492380a31b2427b (версия для архитектуры x64)
Описание
Бэкдор, написанный на языке С++ и предназначенный для работы как в 32-разрядных, так и в 64-разрядных операционных системах семейства Microsoft Windows. BackDoor.Whitebird.23 предназначен для установки зашифрованного соединения с управляющим сервером и несанкционированного управления зараженным компьютером.
Принцип действия
Начало работы
Вредоносная библиотека имеет две экспортируемые функции:
GooglePlay
Test
В начале своей работы расшифровывает зашитую в тело бэкдора конфигурацию алгоритмом на основе XOR-операции с байтом 0x99. Конфигурация имеет вид:
struct st_cfg
{
_DWORD dword0;
wchar_t campaign[64];
wchar_t cnc_addr[256];
_DWORD cnc_port;
wchar_t cnc_addr2[100];
wchar_t cnc_addr3[100];
_BYTE working_hours[1440];
wchar_t proxy_domain[50];
_DWORD proxy_port;
_DWORD proxy_type;
_DWORD use_proxy;
_BYTE proxy_login[50];
_BYTE proxy_password[50];
_BYTE gapa8c[256];
};
Для обеспечения своей постоянной работы бэкдор меняет значение, указанное в поле working_hours конфигурации. Поле содержит 1440 байтов, которые принимают значения 0 или 1 и представляют собой каждую минуту каждого часа в сутках. Создает для каждого сетевого интерфейса отдельный поток, который прослушивает интерфейс и ищет пакеты авторизации на прокси-сервере с зараженного компьютера. При обнаружении такого пакета бэкдор вносит информацию о прокси-сервере в свой список. Кроме того, проверяет наличие прокси через WinAPI InternetQueryOptionW. Список с информацией о прокси имеет следующую структуру:
struct st_proxy
{
st_proxy *next;
st_proxy *prev;
_DWORD proxy_type;
_DWORD proxy_addr;
unsigned __int16 proxy_port;
_DWORD got_proxy;
const char login[255];
const char password[255];
const char char216[255];
};
Конфигурации прокси-серверов дополнительно сохраняются в файл %TEMP%\\<computer_name>_r.xra.
Затем программа проверяет текущие минуту и час и сравнивает с данными, находящимися в поле working_hours конфигурации. Если значение для соответствующей минуты суток не нулевое, то устанавливает соединение с управляющим сервером.
В случае успешного соединения с сервером бэкдор собирает информацию о зараженном компьютере и формирует структуру:
#pragma pack(push, 1)
struct st_info
{
wchar_t campaign[64];
_DWORD dword80;
WCHAR username[64];
wchar_t macs[20];
RTL_OSVERSIONINFOW osversion;
_BYTE gap130[8];
WCHAR computer_name[16];
_BYTE gap24A[96];
st_drive_info drives[26];
_BYTE gap2D0[312];
_DWORD mem_total_phys;
_DWORD mem_available_phys;
DWORD cpu_nop;
DWORD cpu_freq;
_BYTE cpu_info[128];
_DWORD x64;
WCHAR locale[6];
};
#pragma pack(pop)
Программа отправляет собранную информацию на управляющий сервер и ждет в ответ 2 байта. Первый из этих двух байтов бэкдор будет посылать уже после обработки команды от сервера.
После чего отправляет байт 0x10, который является запросом команды у управляющего сервера. В ответ сервер должен прислать 16 байтов, где первый DWORD служит идентификатором команды.
Список команд представлен в следующей таблице:
Код команды | Команда |
---|---|
0x01 | Выслать список файлов в каталоге |
0x15 | Удалить файл |
0x16 | Удалить каталог |
0x17 | Переместить файл |
0x18 | Запустить файл |
0x19 | Записать файл |
0x1b | Прочесть файл |
0x32 | Выслать список процессов |
0x33 | Завершить указанный процесс |
0x50 | Выслать список служб |
0x51 | Выслать конфигурацию указанной службы |
0x52 | Запустить службу |
0x53 | Остановить службу |
0x54 | Удалить службу |
0x64 | Запустить командную оболочку с перенаправлением ввода/вывода в пайпы или выполнить команду в командной оболочке |
0x65 | Установить дополнительное соединение с управляющим сервером и запустить командную оболочку с перенаправлением ввода/вывода в сокет |
0x3e7 | Удалить себя из системы |
Протокол связи с управляющим сервером
Установка соединения с сервером имитирует создание соединения по протоколу TLS версии 1.0 между клиентом и сервером. В теле бэкдора содержатся два буфера.
Первый буфер содержит пакет Client Hello версии TLS 1.0.
Второй буфер содержит TLS 1.0 пакеты Client Key Exchange с длиной ключа 0x100 байт, Change Cipher Spec, Encrypted Handshake Message.
При отправке пакета Client Hello бэкдор записывает в поле Client Random 4 байта текущего времени и 28 байт псевдослучайных данных, вычисляемых следующим образом:
v3 = time(0);
t = (v3 >> 8 >> 16) + ((((((unsigned __int8)v3 << 8) + BYTE1(v3)) << 8) + BYTE2(v3)) << 8);
for ( i = 0; i < 28; i += 4 )
*(_DWORD *)&clientrnd[i] = t + *(_DWORD *)&cnc_addr[i / 4];
for ( j = 0; j < 28; ++j )
clientrnd[j] ^= 7 * (_BYTE)j;
Полученный пакет отправляется на управляющий сервер. В ответе (пакет Server Hello) проверяются:
- соответствие протокола TLS версии 1.0;
- соответствие временной метки (первые 4 байта поля пакет Random Data), указанной клиентом, временной метке, указанной сервером;
- совпадение первых 4 байтов после временной метки в поле Random Data у клиента и сервера.
В случае указанных соответствий бэкдор готовит пакет Client Key Exchange. Для этого он модифицирует Public Key в пакете Client Key Exchange, а также Encryption IV и Encryption Data в пакете Encrypted Handshake Message.
z = 17;
x = 17 * t;
do
{
client_key_exchange[z++] ^= BYTE1(x);
x += t;
}
while ( z < 272 );
p = &next_after_client_key_exchange;
c = 7;
do
{
*p ^= BYTE1(c);
c += t;
--p;
}
while ( (int)p > (int)&client_key_exchange[278] );
Затем бэкдор принимает пакет от управляющего сервера, проверяет что версия протокола TLS соответствует 1.0, после чего принимает еще 54 байта (тело пакета). На этом установка соединения завершается.
Все принимаемые и отправляемые пакеты передаются по протоколу TLS 1.0, при этом шифрование данных пакетов определяется алгоритмом:
for ( i = 0; i < size; ++i )
buffer[i] ^= 7 * (_BYTE)i;
Если клиенту или серверу не удалось за одну попытку принять весь пакет целиком, то он отправляет второй стороне пакет, который формируется следующим образом:
t = time(0);
...
for ( j = 0; j < 10; ++j )
Src[j] = (unsigned __int16)(0x71 * (t + 35)) >> 8;
tls_send_packet(socket, Src, 0xAu);