Compilation dates:
- 02:57:54 31.03.2020 (x86 version)
- 02:57:51 31.03.2020 (x64 version)
SHA1 hashes:
- 2510e873e79cfb61533e9b5a124ddbec130c653c (x86 version)
- d6e84ad926cc1d5a3d300a98f492380a31b2427b (x64 version)
Description
A backdoor written in C++ and designed to operate in both 32-bit and 64-bit Microsoft Windows operating systems. BackDoor.Whitebird.23 is designed to establish an encrypted connection with the C&C server and for unauthorized control over an infected computer.
Operating routine
Start of operation
The malicious library has two export functions:
GooglePlay
Test
At the beginning of its operation, the backdoor decrypts the hardcoded configuration using an algorithm based on the XOR operation with byte 0x99. The configuration:
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];
};
To ensure the backdoor is always running, it changes the value specified in the working_hours field of the configuration. The field contains 1440 bytes, which take the values 0 or 1 and represent every minute of every hour in a day. The program creates a separate thread for each network interface that listens to that interface and searches for authorization packets on the proxy server from the infected computer. When such a packet is detected, the backdoor adds information about the proxy server to its own list. It also checks for proxy via the InternetQueryOptionW WinAPI. The list with proxy information has the following structure:
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];
};
Proxy server configurations are additionally saved in the %TEMP file%\\<computer_name>_r.xra file.
The program then checks the current minute and hour and compares them with the data in the working_hours field of the configuration. If the value for the corresponding minute of the day is not zero, it establishes a connection to the C&C server.
If the connection to the server is successful, the backdoor collects information about the infected computer and forms the following structure:
#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)
The program sends the collected information to the C&C server and waits for 2 bytes in response. The first of these two bytes the backdoor will send after processing the server command.
Then it sends the byte 0x10, which is a command request from the C&C server. In response, the server must send 16 bytes, where the first DWORD serves as the command ID.
The list of commands is shown in the following table:
Command id | Action |
---|---|
0x01 | To send a list of files in the folder |
0x15 | To delete a file |
0x16 | To delete a directory |
0x17 | To move a file |
0x18 | To open a file |
0x19 | To write a file |
0x1b | To read a file |
0x32 | To send a list of processes |
0x33 | To terminate a specified process |
0x50 | To send a list of services |
0x51 | To send a configuration of the specified service |
0x52 | To run a service |
0x53 | To stop a service |
0x54 | To delete a service |
0x64 | To run the command shell with I/O redirecting to pipes or run the command in the command shell |
0x65 | To establish an additional connection with the C&C server and run the command shell with I/O redirecting to socket |
0x3e7 | To remove itself from the system |
Protocol for communicating with the C&C server
Establishing a connection to the server simulates creating a connection over TLS 1.0 protocol between the client and the server. The backdoor contains two buffers in its body:
The first buffer contains TLS 1.0 Client Hello packet.
The second buffer contains TLS 1.0 Client Key Exchange with a key length of 0x100 bytes, the Change Cipher Spec and Encrypted Handshake Message packets.
When sending a Client Hello packet, the backdoor writes to the Client Random field 4 bytes of the current time and 28 bytes of pseudo-random data, which are calculated as follows:
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;
The resulting packet is sent to the C&C server. The response (Server Hello packet) is checked for compliance with the following parameters:
- If the TLS Protocol version corresponds to version 1.0;
- The match between the timestamp (the first 4 bytes of the Random Data field) specified by the client and the timestamp specified by the server;
- The match between the first 4 bytes after the timestamp in the Random Data field specified by the client and these 4 bytes specified by the server.
In the case of these matches, the backdoor prepares the Client Key Exchange packet. To do this, it modifies Public Key in the Client Key Exchange packet, as well as the Encryption IV and Encryption Data in the Encrypted Handshake Message packet.
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] );
The backdoor then receives the packet from the C&C server, checks that the TLS Protocol version corresponds to version 1.0, and then receives another 54 bytes (the packet body). This completes the connection establishment.
All received and sent packets are transmitted over the TLS 1.0 protocol, and the encryption of these packets is determined by the following algorithm:
for ( i = 0; i < size; ++i )
buffer[i] ^= 7 * (_BYTE)i;
If the client or server failed to accept a packet in one attempt, it sends back a packet, which is formed as follows:
t = time(0);
...
for ( j = 0; j < 10; ++j )
Src[j] = (unsigned __int16)(0x71 * (t + 35)) >> 8;
tls_send_packet(socket, Src, 0xAu);