- Упаковщик: отсутствует
Даты компиляции:
- 30.07.2019 04:12:08 (версия для архитектуры x64)
- 30.07.2019 04:12:29 (версия для архитектуры x86)
SHA1-хеши:
- bfa1e457afbb1f160094f65b456503b64832d249 (версия для архитектуры x64)
- ce3fc5b40231b5a9dd4aeeb0f0c7ef6f7779c53e (версия для архитектуры x86)
Описание
Бэкдор, написанный на языке С++ и предназначенный для работы в 32- и 64-разрядных операционных системах семейства Microsoft Windows. Функциональность 32- и 64-битных версий идентична. Бэкдор слинкован с библиотекой OpenSSL, реализующей шифрование на основе AES и RSA, а также генерацию ключей. Используется для целевых атак на информационные системы и несанкционированного доступа к данным для их передачи на управляющие серверы. В зараженной системе исследуемый образец находился в System32 в виде динамической библиотеки с именем ssdtvrs.dll. Был установлен службой ssdtvrs. Данное описание построено на основе 64-битной версии.
Принцип действия
Экспортирует точку входа сервиса ServiceMain. В начале своей работы регистрирует функцию-обработчик управляющих запросов, затем создает поток, в котором выполняет основные функции, после чего в цикле ожидает остановки службы.
Главный поток
Вначале готовит конфигурацию, которая может храниться как в реестре зараженного компьютера, так и в теле бэкдора. Затем расшифровывает имя ключа реестра Software\Microsoft\Internet Explorer\Security.
Проверяет наличие этого ключа сначала в разделе HKCU, затем в разделе HKLM реестра. После чего из параметра, имя которого совпадает с именем файла вредоносной DLL (в данном случае ssdtvrs), загружает зашифрованную конфигурацию. Если конфигурация отсутствует в реестре, то использует ту, что находится в теле бэкдора.
Конфигурация зашифрована RC4, ключ генерируется по следующему алгоритму:
Конфигурация хранится в виде последовательности блоков.
BYTE | BYTE | BYTE[item_len] |
item_id | item_len | item_data |
Бэкдор поочередно проходит по всем блокам и сохраняет полученную конфигурацию в виде структуры:
//значения 0xXX - item_id
struct cfg
{
DWORD item_0x1E;
BYTE item_0x1F[32];
BYTE item_0x20[32];
BYTE item_0x21[64];
BYTE C2_0[64];
WORD C2_0_port;
BYTE C2_1[32];
WORD C2_1_port;
BYTE C2_2[32];
WORD C2_2_port;
BYTE item_0x0A[64];
WORD item_0x0A_word;
BYTE item_0x0B[32];
WORD item_0x0B_word;
BYTE item_0x0C[32];
WORD item_0x0C_word;
BYTE C2_index_0x0D;
BYTE item_0x14[32];
WORD item_0x14_word;
BYTE item_0x15[32];
BYTE item_0x16[32];
BYTE item_0x17;
BYTE item_0x28[32];
SYSTEMTIME time_1;
SYSTEMTIME time_2;
BYTE gap[16];
BYTE item_0x29[64];
BYTE module_file_name[16];
};
После подготовки конфигурации BackDoor.Siggen2.3268 проверяет, чтобы текущее системное время было в диапазоне между cfg.time_1 и cfg.time_2, и ожидает до тех пор, пока это условие не выполнится.
Затем переходит к подготовке и отправке регистрационного пакета на управляющий сервер. Вначале создает объект класса SBC02DEFE6 (RTTI-структуры остались в бэкдоре). Внутри этого объекта содержится другой объект, который хранит информацию о соединении, а также инкапсулирует объект AZ092342345, который отвечает за шифрование данных. После создания объекта SBC02DEFE6 бэкдор пытается помешать отладке путем закрытия заведомо неверного дескриптора. Возникшее исключение обрабатывается, и, если отладчик отсутствует, работа бэкдора продолжается.
После этого проверяется параметр cfg.C2_index_0x0D, в соответствии с которым выбирается конкретный управляющий сервер из конфигурации. В конфигурацию зашиты следующие адреса:
- 144.34.145.168
- snow.swingfished[.]com
Для соединения с сервером создает TCP-сокет, а затем подготавливает ключи шифрования. В бэкдоре зашит публичный RSA-ключ, который зашифрован по тому же алгоритму, что используется для шифрования ключа реестра, хранящего конфигурацию.
Ниже представлен расшифрованный RSA-ключ.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8W8cpiAwGjiSebyCFRQq
9Mxmdj6zIGGh6R9DJ+HD7KxZTU51y20YfQbNt0n6fSYkTfysuKanHaN59jnfk1mU
buXnoQDLc7GzCRk8f7Btumd251/v7eFXVsXA1qbZHucZpcy/t946VvY+txMbCduQ
7Wg7X+m2GJoQBX11th/1IWOoJ2usqZbzhlAJqR9B4q5xLiei/CbsbP6YFwBjpEb5
9kUOpT1D27LorxqIp9YqaqLtMh4PXLu3gcewN0rRGqHsBH4X2ZRs7yWvm8zMBPFS
HsTK9rTZqWS66WlCc9WS73NAnyFjrwam98aLVmuRkGMTRUFclQp8fd//NiKFeMBX
GQIDAQAB
-----END PUBLIC KEY-----
.\>openssl rsa -noout -text -inform PEM -in pubkey.pem -pubin
Public-Key: (2048 bit)
Modulus:
00:f1:6f:1c:a6:20:30:1a:38:92:79:bc:82:15:14:
2a:f4:cc:66:76:3e:b3:20:61:a1:e9:1f:43:27:e1:
c3:ec:ac:59:4d:4e:75:cb:6d:18:7d:06:cd:b7:49:
fa:7d:26:24:4d:fc:ac:b8:a6:a7:1d:a3:79:f6:39:
df:93:59:94:6e:e5:e7:a1:00:cb:73:b1:b3:09:19:
3c:7f:b0:6d:ba:67:76:e7:5f:ef:ed:e1:57:56:c5:
c0:d6:a6:d9:1e:e7:19:a5:cc:bf:b7:de:3a:56:f6:
3e:b7:13:1b:09:db:90:ed:68:3b:5f:e9:b6:18:9a:
10:05:7d:75:b6:1f:f5:21:63:a8:27:6b:ac:a9:96:
f3:86:50:09:a9:1f:41:e2:ae:71:2e:27:a2:fc:26:
ec:6c:fe:98:17:00:63:a4:46:f9:f6:45:0e:a5:3d:
43:db:b2:e8:af:1a:88:a7:d6:2a:6a:a2:ed:32:1e:
0f:5c:bb:b7:81:c7:b0:37:4a:d1:1a:a1:ec:04:7e:
17:d9:94:6c:ef:25:af:9b:cc:cc:04:f1:52:1e:c4:
ca:f6:b4:d9:a9:64:ba:e9:69:42:73:d5:92:ef:73:
40:9f:21:63:af:06:a6:f7:c6:8b:56:6b:91:90:63:
13:45:41:5c:95:0a:7c:7d:df:ff:36:22:85:78:c0:
57:19
Exponent: 65537 (0x10001)
После этого бэкдор генерирует случайное значение типа WORD, которое будет использовано для формирования пакета и проверки ответа от сервера.
Затем с использованием OpenSSL генерирует случайный AES-ключ (256 бит) и формирует ключи шифрования и дешифровки.
С помощью RSA-ключа шифрует сгенерированный ключ для дальнейшей его отправки на управляющий сервер.
Бэкдор хранит ключи в объекте AZ092342345. Его структуру можно представить следующим образом.
struct AZ092342345
{
vtable_AZ092342345 *vtable;
AB2952354 o_AB2952354_response_data;
AB2952354 o_AB2952354_decoded_data;
AB2952354 o_AB2952354_3;
AB2952354 o_AB2952354_4;
WORD check_word;
BYTE gap[6];
RSA **p_RSA; //RSA - структура из библиотеки OpenSSL
AES_key AES_key;
WORD rnd_word;
DWORD dword_362;
};
struct AB2952354 //объекты класса AB2952354 используются в качестве контейнеров данных, например, отправляемых и получаемых от сервера
{
vtable_AB2952354 *vtable;
BYTE *p_buffer;
BYTE *p_buffer_end;
DWORD data_size;
CRITICAL_SECTION crit_sect;
};
struct AES_key
{
char userKey[32];
char ivec[20];
int field_34;
QWORD field_38;
AES_KEY encryptKey; //AES_KEY структура из OpenSSL
AES_KEY decryptKey;
};
Пакет, отправляемый при рукопожатии, имеет длину 0x10A +
WORD | DWORD | DWORD | BYTE[] |
проверочное значение | случайное значение | случайная часть длины пакета | зашифрованный AES-ключ |
Первое проверочное значение (WORD) формируется следующим образом.
Пакет отправляется на сервер, затем запускается отдельный поток, который с помощью select ожидает поступления ответа на сокет, с которого отправлен handshake-пакет. При получении ответа проверяет первые 2 байта входящего пакета.
Если результат равен 1, то соединение сбрасывается. В противном случае бэкдор парсит пакет, который имеет следующий заголовок.
WORD | DWORD | DWORD | DWORD |
проверочное значение | длина пакета с заголовком | длина упакованных данных | длина распакованных данных |
Данные зашифрованы по алгоритму AES с ключом, отправленным серверу в handshake-пакете и упакованы библиотекой zlib.
Объект KCPOI982S инициализируется в основном потоке бэкдора и отвечает за обработку команд от управляющего сервера.
После инициализации процедуры рукопожатия BackDoor.Siggen2.3268 в главном потоке зашифровывает конфигурацию при помощи RC4, затем сохраняет ее в реестре. Далее подготавливает информацию о системе для последующей отправки на сервер. Заголовок пакета аналогичен заголовку пакета, полученному от сервера в процессе рукопожатия; данные упаковываются zlib и зашифровываются по алгоритму AES. Передаваемая информация о зараженной системе представляется структурой:
struct sysinfo
{
BYTE id;
OSVERSIONINFOEXA os_version;
DWORD CPU_MHz;
DWORD sin_addr;
BYTE cfg_item_0x29_or_hostname[64];
BYTE cfg_C2_index;
DWORD tick_count_diff;
char field_F0[64];
};
id — идентификатор пакета. В данном случае равен 0x66.
sin_addr — IP-адрес управляющего сервера, c которым установлено соединение.
cfg_item_0x29_or_hostname — значение параметра конфигурации с идентификатором, равным 0x29; если оно не задано, то в качестве значения используется имя зараженного компьютера.
field_F0 принимает значения в зависимости от параметра конфигурации с идентификатором 0x1E.
- cfg_item_0x1E == 0 => cfg.item_0x1F
- cfg_item_0x1E == 1 => cfg.item_0x21
- cfg_item_0x1E == 2 => "c"
- cfg_item_0x1E == 3 => "p"
После структуры sysinfo дописывается случайная последовательность длиной от 0 до 255 байт.
После отправки информации о системе создается объект класса KCPOI982S для обработки команд от управляющего сервера. Основное предназначение этого объекта — проверка идентификатора команды и создание объекта, предназначенного для обработки конкретной команды. Объект KCPOI982S и другие объекты-обработчики команд наследуются от класса AM1876234af3, который содержит лишь дескриптор события для синхронизации и ссылку на объект SBC02DEFE6 для работы с соединением.
KCPOI982S создает отдельные потоки для каждой команды и хранит в себе массив дескрипторов этих потоков, прерывает их в своем деструкторе.
Обработка команд управляющего сервера
Идентификатор команды содержится в 1-м байте нагрузки пакета, отправленного сервером (после расшифровки и распаковки).
id | Имя объекта-обработчика | Описание |
---|---|---|
0x10 | BCJI09RUC | Выслать список процессов. По каждому процессу формирует структуру:
|
0x15 | AS01243895 | Создать командную оболочку из cmd.exe. Запускает cmd.exe с перенаправлением StdIn,StdOut,StdErr в пайпы, затем отправляет пакет с байтом 0x76 в нагрузке. После этого в цикле пытается читать из пайпа результат и отправлять его на сервер. |
0x01 | AF434faf845 | Отправить информацию обо всех дисках (перебирает по буквам, кроме A и B). По каждому диску формирует структуру:
|
0x20 | AC92784f908234 | Отправить конфигурацию на сервер. Нагрузка пакета представляется структурой:
|
0x00 | - | Сбросить соединение |
Артефакты
BackDoor.Siggen2.3268 содержит множество отладочных строк, ссылки на них отсутствуют.
.rdata:00000001800D4DF8 00000008 C started
.rdata:00000001800D4E00 0000001B C get test connect style: %d
.rdata:00000001800D4E20 00000013 C Read config error!
.rdata:00000001800D4E38 00000024 C begin connecting, connect style: %d
.rdata:00000001800D4E60 00000015 C - main connect fail!
.rdata:00000001800D4E78 00000032 C !MainThread, sendLoginInfo error, reconnect again
.rdata:00000001800D4EB0 0000000F C - Not Actived!
.rdata:00000001800D4EC0 00000012 C ++ Server Actived
.rdata:00000001800D4ED8 00000027 C !send Heartbeat error, repeat connect.
.rdata:00000001800D4F00 0000000F C !in Debug,out\n
.rdata:00000001800D4F10 0000001B C TestConnectModeI %d Error!
.rdata:00000001800D4F30 00000020 C Test Connect BackDomain Succeed
.rdata:00000001800D4F50 00000016 C begin iBackStyle = %d
.rdata:00000001800D4F68 0000000F C con test again
.rdata:00000001800D4F78 0000001E C Succeed Test, iBackStyle = %d
.rdata:00000001800D4F98 0000001E C Test Failure, Sleep 10-30m!!!
.rdata:00000001800D4FB8 00000035 C Test toatl Failure, Sleep 20_50m!!!, totalcount = %d
.rdata:00000001800D5088 00000016 C configure data key:%s
.rdata:00000001800D50A0 0000000F C !read1 reg, %d
.rdata:00000001800D50B0 0000000F C !read2 reg, %d
.rdata:00000001800D50C0 00000010 C !write1 reg, %d
.rdata:00000001800D50D0 00000010 C !write2 reg, %d
.rdata:00000001800D50E0 00000010 C !write3 reg, %d
.rdata:00000001800D50F0 00000010 C !write4 reg, %d
.rdata:00000001800D5100 00000018 C Public Encrypt failed\n
.rdata:00000001800D5118 00000017 C !UnzipPacket: not flag
.rdata:00000001800D5130 00000016 C !UnzipPacket: Decrypt
.rdata:00000001800D5178 00000015 C @@ TCP Construct end
.rdata:00000001800D5190 0000001C C @@<- TCP begin DisConstruct
.rdata:00000001800D51B0 00000024 C @@-- TCP Disconnect in DisConstruct
.rdata:00000001800D51D8 0000001A C DisConstruct: closesocket
.rdata:00000001800D51F8 0000001C C Discontruct: close m_hEvent
.rdata:00000001800D5218 0000001A C @@-> TCP End DisConstruct
.rdata:00000001800D5238 00000027 C TCPConnecting begin, Host:%s, Port: %d
.rdata:00000001800D5260 00000018 C !Connect, lpszHost = %s
.rdata:00000001800D5278 00000015 C Create Socket error!
.rdata:00000001800D5290 00000021 C !TCP gethostbyname(),lpszHost=%s
.rdata:00000001800D52B8 00000013 C TCP connect error!
.rdata:00000001800D52D0 00000014 C new key buf error!\n
.rdata:00000001800D52E8 00000012 C const key failed\n
.rdata:00000001800D5300 00000013 C send askey failed\n
.rdata:00000001800D5318 00000017 C TCPConnecting succeed!
.rdata:00000001800D5330 00000018 C <-- TCP disconnect into
.rdata:00000001800D5348 00000019 C <-- TCP disconnect begin
.rdata:00000001800D5368 00000017 C --> TCP disconnect end
.rdata:00000001800D5380 00000018 C <-- TCP disconnect exit
.rdata:00000001800D5398 00000019 C !Send error, Disonnect()
.rdata:00000001800D53B8 0000001A C TCP send1 to SendRetry:%d
.rdata:00000001800D53D8 0000001A C TCP send2 to SendRetry:%d
.rdata:00000001800D53F8 00000017 C Create TCP WorkThread!
.rdata:00000001800D5410 0000001C C begin into WorkThread while
.rdata:00000001800D5430 00000028 C !WorkThread, select error, Disconnect()
.rdata:00000001800D5458 00000026 C !WorkThread, recv error, Disconnect()
.rdata:00000001800D5480 00000015 C Exit TCP WorkThread!
.rdata:00000001800D5498 00000024 C !OnRead, dwIoSize = 0, Disconnect()
.rdata:00000001800D54C0 00000025 C !recv only packet flag, Disconnect()
.rdata:00000001800D54E8 00000008 C bad buf
.rdata:00000001800D54F0 00000024 C !UnzipPacket failure!, Disconnect()
.rdata:00000001800D5528 0000000E C JnteroetPpenA