A backdoor designed to infect Linux computers. Its main purpose is to steal confidential information (logins, passwords), execute key logger functions (log keystrokes) and proxy server functions, and make screenshots. This backdoor can be used as an application for a secure access protection to a computer but in fact it is a spyware. Modifications of this Trojan exist for Windows and Mac OS Х.
Configuration file
A configuration file is encrypted with a special modification of the RC4 algorithm. The encryption context is specified only once and does not undergo any changes in the future. This makes the modification rather unique. In other words, for every subsequent call of the RC4_crypt functions the same context is used.
The configuration file contains the following data:
- Address and port of the command and control server in the “address:port;” format
- Address, port, login, proxy password (if available) in the “type:address:port:login:pass;” format
- File name under which the backdoor will be installed
- Backdoor installation directory
- Backdoor logging directory
- Installation parameters
The structure containing the command and control server address looks as follows:
#pragma pack(push, 1)
struct st_cnc
{
char szCnC[64];
_DWORD port;
st_cnc *Next;
};
#pragma pack(pop)
The backdoor can use a list containing three such structures.
The structure that sets the proxy server parameters looks as follows:
#pragma pack(push,1)
struct st_proxy
{
_DWORD type;
char szCnc[64];
_DWORD port;
char login[32];
char pass[32];
st_proxy *pNext;
};
#pragma pack(pop)
The backdoor can establish a connection to three command and control servers if they are specified in the configuration file and use one proxy (if it is set). The code allows to use only one secure channel; in other words, when three command and control servers are available, only one connection with one server will be secured.
How it works
Once the configuration file is decrypted, the Trojan installs itself in the system saving its copy with the name mspv in the folder “~/.Install/”.
Then the installation proceeds in accordance with the parameters specified in the configuration file. To specify these parameters, the backdoor reads the string (“121”) in the configuration file, modifies it into a digit, and uses it as a bit field. Every bit in this field is responsible for a corresponding installation parameter.
- 0x01—copy the Trojan’s file to the directory specified in the configuration file.
- 0x02—delete the dropper’s file once the installation is complete.
- 0x04—block the Trojan’s file.
- 0x08—add the Trojan’s copy to autorun using “~/.config/autostart/”.
- 0x10—add the Trojan’s copy to autorun using crontab.
- 0x20—use only one process instance.
- 0x40—run keylogger.
- 0x80—do not show any messages.
The installation will be run if the configuration file contains a corresponding parameter. During the installation, the Trojan adds itself to autorun creating the file “~/.config/autostart/mspv/mspv.desktop” with the following contents:
\n[Desktop Entry]\nType=Application\nExec=\"~/.Install/mspv\"\nHidden=false\nName=mspv\n
If the bit 0x40 is specified, at the end of the installation the backdoor creates a separate stream for the keylogger.
Network traffic is encrypted using the AES algorithm with the 256-bit key. During the process, the backdoor generates encryption tables.
Generating the AES 256-bit key
The Trojan determines the current time value and uses it as the seed for the pseudorandom number generator.
int __cdecl RndGenerator::Init(int num)
{
int v1;
int result;
v1 = currentstate_w ^ currentstate_z & num;
currentstate_w = v1;
result = currentstate_z ^ (num | v1);
currentstate_z = result;
return result;
}
unsigned int RndGenerator::Generate()
{
currentstate_z = (currentstate_z << 16) + 0x9069 * (unsigned __int16)currentstate_z;
currentstate_w = (currentstate_w << 16) + 0x4650 * (unsigned __int16)currentstate_w;
return (currentstate_z << 12) + currentstate_w;
}
unsigned int __cdecl RndGenerator::GenerateInLimits(unsigned int low_limit, unsigned int upper_limit)
{
return RndGenerator::Generate() % (upper_limit - low_limit + 1) + low_limit;
}
int __cdecl RndGenerator::FillBuffer(_BYTE *pBuffer, int size)
{
int i;
time_t v3;
int rnd;
i = 0;
v3 = time(0);
rnd = RndGenerator::Init(size ^ v3);
while ( i < size )
{
rnd = RndGenerator::GenerateInLimits(1, 255);
pBuffer[i++] = rnd;
}
return rnd;
}
Thus, the 32-byte buffer is filled up. Then the value of one of the keys (encryption key) is extracted and is modified using the following algorithm:
int __cdecl GenerateAesKey(const char *key, _BYTE *random, _BYTE *aes_key)
{
const char *key_; // edx@1
signed int z; // eax@1
unsigned int key_len; // kr04_4@1
signed int key_len_; // ecx@1
int i; // eax@4
int result; // eax@7
int v9; // edx@7
int v10; // edi@8
int v11; // edi@8
int v12; // edx@8
_DWORD state[32]; // [sp+0h] [bp-90h]@2
key_ = key;
key_len = strlen(key) + 1;
z = 0;
key_len_ = key_len - 1;
while ( z < key_len_ )
{
state[z] = (unsigned __int8)((key[z] >> 4) | 16 * key[z]);
++z;
}
for ( i = key_len - 1; i <= 31; ++i )
{
key_ = (const char *)(unsigned __int8)(i & (8 * i | ((signed int)(unsigned __int8)i >> 5)));
state[i] = key_;
}
LOBYTE(key_) = state[key_len_ >> 2];
result = 0;
v9 = key_len_ ^ (unsigned int)key_;
do
{
LOBYTE(v9) = random[result] ^ v9;
v10 = v9;
LOBYTE(v9) = state[result];
v11 = v9 ^ v10;
aes_key[result] = v11;
v12 = 4 * v11;
LOBYTE(v12) = random[result] ^ 4 * v11;
aes_key[result] = result ^ (result + key_len_) | ((signed int)(unsigned __int8)v11 >> 5) | 8 * v11;
++result;
v9 = ~v12;
}
while ( result != 32 );
return result;
}
The modification results in 32 bytes for the AES session key.
Requests to the command and control server
To be able to exchange data with the command and control server, the Trojan uses the binary protocol. All packages sent to the server have the same structure.
#pragma pack(push,1)
struct st_packet
{
_DWORD size;
_BYTE cmd;
_BYTE buffer[];
};
#pragma pack(pop)
The first package sent by the Trojan contains data that will be used by the command and control server for reading the session key. The Trojan will utilize this key in the future. The payload structure looks as follows:
#pragma pack(push, 1)
struct st_hello
{
_BYTE rnd_data[32];
_BYTE iv[16];
_BYTE hello[16];
};
#pragma pack(pop)
“hello” stands here for the encryption key from the backdoor’s configuration file; iv and rnd_data stand for the data generated while obtaining the AES session key. The st_packet.cmd field's value for this package is 3.
The command is executed in four following steps:
- The backdoor sends the ReadyToReceive package.
#pragma pack(push,1) struct st_packet_rdytorecv { _DWORD size; // 5 _BYTE cmd; // 2 _BYTE buffer[]; // NULL }; #pragma pack(pop)
- As a reply, the server sends the value DWORD, which stands for the size of the next package. This size cannot exceed 0x800, and for the first reply it should be equal to 0x41.
- Once the backdoor checks the received data, it sends the ReadyToReceive package once again.
- The server replies with the package containing a command and arguments for its execution.
#pragma pack(push,1) struct st_srv_answer { _BYTE cmd; _BYTE args[0x7FF]; // 0x7FF is a max value }; #pragma pack(pop)
The first package sent by the server is not encrypted and has an operational code of 0x05 and the length of 0x41.
Keylogger
It is implemented on the basis of the API X server. Once a key is pressed, the information about the date, the active window, and the code of the pressed key is saved. The path to the log file is written in the configuration file.
Before the data are entered into the log file, they are encrypted with the XOR algorithm as follows:
int __usercall CryptLog(_BYTE *data, DWORD size)
{
BYTE x;
for (DWORD i = 0; i != size; ++i )
{
x = data[i];
x = (x ^ 0x9D) + 0x24;
data[i] = x;
}
return i;
}
System of commands
Ping (0x01)
cmd == 0x01. There are no arguments for the command and the reply is the same (st_packet.cmd == 1, st_packet.buffer == NULL).
InitSecureConnection (0x05)
To obtain the AES-256 key, the server sends 32 bytes of data encrypted with the master key from the configuration file. Using the AES-256 key, the command buffer is decrypted to verify the accuracy of the сlient-server connection’s encryption.
The command looks as follows:
#pragma pack(push,1)
struct st_packet_initsecureconn
{
_BYTE cmd;
_BYTE key_data[32];
_BYTE signature[16];
};
#pragma pack(pop)
Once the initialization of the AES context is performed, the Trojan saves the socket's descriptor that sent the command and the AES context for further command decryption.
Moreover, the Trojan sends the server the command with the following parameters:
st_packet.cmd = 4;
st_packet.buffer = NULL;
Then the malware collects the following information about the computer and sends it to the server:
- The Trojan retrieves or generates (if it is not available) the HostId (computer’s unique identifier). For this purpose, it checks the system for the file “%backdoor_filename%.Identifier”. If the file exists, it contains the string with the HostId. If the file does not exist, the backdoor creates it with the “HostId-%Rand%” string inside. The value “%Rand%” is replaced with a random character from the [A-Za-z] range.
- The Trojan retrieves the user name.
- The Trojan retrieves the computer name.
- The Trojan retrieves the OS version. For this purpose, it reads the file “/etc/lsb-release”. If the Trojan cannot find this file, it tries to open the file “/etc/redhat-release”. If the file “/etc/redhat-release” cannot be found either, the Trojan checks the folder “/etc/” for the file with the name containing “release” or “version”.
All this data is packed into the buffer.
snprintf(&s, 0x800u, "%c%.8x%s\a%s @ %s\a%s\a", 2, 0x1056100, hostid, username,
hostname, release);
Then the data is sent to the server using the following command:
st_packet.cmd = 5
st_packet.buffer = s (specified above).
Download To /tmp/ and Run File (0x06)
The received command contains the information about the host, the port, the path to the location where the file is to be saved, and the instructions regarding whether this file should be run or not. The backdoor forwards the progress status to the server in the st_packet.cmd = 0x2E package with the “%d\a%d\ahttp://%s%s\a%s” payload. Parameters in this payload correspond to the download file counter, the command execution status, the host, the path to the file, and the path to the location where the file is to be saved.
Once the file is running, the backdoor sends the st_packet.cmd = 0x08, st_packet.buffer = NULL package.
Run File (0x07)
Runs the file whose path is specified in the command.
Once the file is running, the backdoor sends the following command:
st_packet.cmd = 0x08
st_packet.buffer = NULL
Exit (0x09)
Shuts down the backdoor’s working process and deletes the TMP file.
Close connection (0x0A)
Closes the connection with the current command and control server.
Uninstall (0x0B)
Removes the Trojan from autorun.
SetHostId (0x0C)
Sets the HostId. The setting value is specified in the command.
Download File To /tmp/ (0x0D)
This command is similar to the 0x2D command
Dummy (0x0E)
As a reply, sends the st_packet.cmd = 0x0E, st_packet.buffer = NULL package
Upload file (0x10)
Uploads the file to the server. During the upload, two following packages are sent to the server:
- The package st_packet.cmd = 0x10 containing log files
- The st_packet.cmd = 0x11, st_packet.buffer = NULL package is sent after the file is uploaded or if the file does not exist
Takes two following arguments: the directory name (the size of 0x1100 bytes) and the file search mask (the size of 0x1000 bytes).
The command runs a recursive search for directories and files that correspond to the specified parameters. During the search, the st_packet.cmd == 0x13 packages are sent to the server. The buffer can look as follows:
- 16\a%root_dir%\a%dir_name%\a — if the specified directory was found during the search (root_dir—the directory specified for the search)
- 0\a%filename%\a%filesize%\a%dir%\a — if the specified file was found during the search. %filename%—the file name, %filesize%—the file size, %dir%—the directory where the file is located
Once the search is complete, the following package is sent to the server:
st_packet.cmd = 0x14
st_packet.buffer = NULL
Stop Recursive File Search (0x14)
Stops the recursive file search. The following package is sent to the server:
st_packet.cmd = 0x14
st_packet.buffer = NULL
Upload File or File Content (0x15)
Save Data To Disk (0x16)
Saves the command’s data in the file.
Close File Handle (0x17)
Copy File (0x18)
Takes two following arguments: the path to the file that needs to be copied and the path to the target folder. Each buffer has the size of 0x1100 bytes.
Run file or set access rights(0x19)
Parses the arguments to find the following strings:
- filename — the file path and the running arguments;
- rights — the string representation of the number, which stands for the file access rights;
- flag — flag. If the value is other than zero, the file will be run. Otherwise, access rights will be set.
Rename file (0x1A)
Renames the file. The buffer contains two strings—the original file name and the modified file name.
If the command is completed successfully, the Trojan sends the server the same command.
Delete file (0x1B)
Deletes the file whose location is specified in the buffer.
If the command is completed successfully, the Trojan sends the server the same command.
Create Directory (0x1C)
Creates the directory. The path is specified in the buffer.
If the command is completed successfully, the Trojan sends the server the same command.
Delete Direcroty Recursively (0x1D)
Deletes the directory recursively.
List Or Create Dir(0x1E)
Depending on the parameter, the command creates the directory or sends the list of the existing directory contents to the server.
Close File Handle (0x1F)
Remote Shell (0x20)
Execute Shell Command (0x21)
Disconnect Remote Shell (0x22)
Get System Info (0x24)
Archives the information about the system and sends it to the server. The following information is collected:
- OS version
- User name
- Computer name
- PATH environment variable
- HOME environment variable
- Command and control server’s address
- AES key from the configuration file
- Command and control server’s type
- Its own PID
- Its own process’s name
- Directory containing key logs
- Keylogger’s working status
Get Logon Sessions (0x26)
Get General Info (0x28)
Sends the server the information about the time when the system was loaded and the list of processes.
Kill process by PID (0x2A)
Takes a string value of the PID process, which needs to be killed.
Enum Windows (0x2B)
Creates the buffer with the data regarding all open windows. Once the buffer is created, sends the server the st_packet.cmd = 0x2B command. The st_packet.buffer value can be NULL or an array of “%s\a%d\a” strings, where %s stands for the title bar and %d stands for the window.
Work With Window (0x2C)
Depending on the argument, executes the following commands: MAP, UNMAP, close the window, change the name in the title bar or change the window’s icon.
Download File (0x2D)
The received command contains the information about the host, the port, the path to the location where the file is to be saved, and the instructions regarding whether this file should be run or not. The backdoor sends the progress status to the server in the st_packet.cmd = 0x2E package with the “%d\a%d\ahttp://%s%s\a%s” payload. Parameters in this payload correspond to the download file counter, the command execution status, the host, the path to the file, and the path to the location where the file is to be saved.
Send Key Released (0x2F)
The input parameter is a string representation of the key code.
Send Key Pressed (0x30)
The input parameter is a string representation of the key code.
Send Notify Event (0x31)
Send Crossing Event (0x32)
Upload Screenshot (0x33)
The backdoor makes a screenshot and sends it to the command and control server. While the command is executed, the following packages are sent:
- First, the st_packet.cmd = 0x33 package containing the QWORD value of the log size is sent.
- Then the st_packet.cmd = 0x34 packages are sent. They contain screenshots data fragmented in packets of 2,048 bytes.
- Once the log is sent, the package st_packet.cmd = 0x35, st_packet.buffer = NULL will be sent.
Upload Keylogger Logs (0x36)
The backdoor uploads the key logs to the command and control server. During the upload, two following packages are sent to the server:
- The package st_packet.cmd = 0x36 with the key logs.
- The package st_packet.cmd = 0x37, st_packet.buffer = NULL (after the key logs are sent or if they do not exist).
Get Keylogger Logs Size (0x38)
The package st_packet.cmd = 0x38 containing “%s\a%d” is sent to the server. %s stands for the path to the directory with the key logs, %d stands for the size of the directory.
Delete Logs By Date (0x39)
Deletes the keylogger's log file for the date specified in the argument.
Upload Keylogger Logs By Date (0x3A)
Uploads the keylogger's log file for the date specified in the argument to the command and control server. While the command is executed, the following packages are sent:
- If the requested keylogger's log file does not exist, the package st_packet.cmd = 0x3C, st_packet.buffer = NULL is sent and the command is terminated. Otherwise, the st_packet.cmd = 0x3A package containing the QWORD value of the log size is sent first.
- Then the st_packet.cmd = 0x3B packages are sent. They contain keylogger's log file data fragmented in packets of 2,048 bytes.
- Once the log is sent, the package st_packet.cmd = 0x3C, st_packet.buffer = NULL will be sent.
Steal Browser's Accounts (0x3D), (0x3E)
Steals user account details stored in different applications. The command takes DWORD as an argument. The argument stands for the browser’s account that needs to be stolen.
- 1 — Mozilla FireFox
- 3 — Opera
- 4 — Google Chrome
- 5 — Chromium
- 6 — Mozilla SeaMonkey
If the argument does not correspond to any of the browsers listed above, the backdoor sends account data stored in all browsers to the command and control server.
Steal Pidgin's Accounts (0x3F), (0x40)
Searches in the file “~/.purple/accounts.xml” for the account. If the account is found, the backdoor sends the file contents to the command and control server. The command code is the same.
Steal Accounts from Mozilla Thunderbird (0x41), (0x42)
Steals Mozilla Thunderbird accounts. Does not need any arguments. The reply to the server has the same command operation’s code.
Make proxy (0x43)
Takes dword4 and the port as an argument.
- Establishes a connection to the current command and control server using the port from the command.
- The backdoor sends the package to the server.
#pragma pack(push,1) struct st_packet_proxy_create { _BYTE cmd; // 0x03 _DWORD size; // dword4 from command's arg }; #pragma pack(pop)
- As a reply, the server sends 1 byte. If it is equal to 1, the next reply will contain the port and the IP address, to which the traffic should be forwarded. Otherwise, the next package will contain the domain and the port.
- The server sends 6 bytes (WORD port, DWORD ip) or the buffer with the size of 0x100 bytes containing the domain and the port’s values.
- The client sends one status byte to the server. 1—could not create a socket, 2—could not connect to the target, 3—ОК. If the are no errors, starts to transfer the traffic.