- Thursday, 5 November 2015

Peering into Dyre's Traffic

Real World Traffic Image
Written by: Sergei Shevchenko, Cyber research

Dyre (also known as Dyreza) is a banking trojan that has got quite a bit attention over the last few months. Nevertheless, it's always interesting to re-visit a known threat to see what has changed.

This post provides an insight into the traffic encryption used by Dyre and what additional components it relies on. The provided source code allows decryption of downloaded Dyre configurations and plugins from the known C&C hosts.

But let's start from the dropper.

The sample of Dyre (MD5:b7db8e9943ab39a60d8470fe2f859164) is delivered in form of a dropper that performs several stages of memory allocation and decryption operations until the actual payload code gets control.

The dropper first allocates memory, decrypts a decoder in it, and then passes control to it. Once the decoder gets control, it will reconstruct a PE-file back at the original virtual address. The PE file is then restored section-by-section. Next, its import table is fully reconstructed. These steps are well outlined in this post.

The restored PE file is a 2nd-stage dropper. It registers itself as a service "gupdate", and then injects a final payload DLL into the svchost.exe or explorer.exe process.

This 2nd-stage dropper carries the following randomly-named resources:

  •   •  uzgn23wmb - 256-byte key
  •   •  twry615nl - 32-bit resource DLL
  •   •  ysfh426g0 - 64-bit resource DLL

Depending on whether the target is running a 32-bit or 64-bit system, it will either inject a 32-bit payload DLL, or a 64-bit one.

The injection is achieved with the ZwQueueApcThread() API call. This injection method has already been used by Carberp, and its source code is available publicly.

The injected DLL

The DLL injected by the 2nd stage dropper into svchost.exe or explorer.exe contains the following 5 randomly named resources:

  •   •  7GEYB8BZ3 (48 bytes) - XOR key for the following 2 resources:
  •   •  0KYOX5YCG (4,900 bytes) - VNC server module (has a debug string 'F:\cppgit\mose\Release\vnchelper.pdb' in it)
  •   •  5DQRM0TQI (53,224 bytes) - keylogger plugin
  •   •  8HRUV7NZJ (160 bytes) - 384-bit elliptic curve DSA public key, used to check the validity of digital signatures
  •   •  9JTIC6HXH (1,184 bytes) - encrypted & signed configuration file with the list of C&C hosts

The most important resource is the encrypted configuration file. The encryption algorithm used to protect this file is based on standard AES 256-bit (ECB mode) and SHA-256 algorithms.

The algorithm has changed since its last known implementation described by Lexsi's researchers.

At the moment, the encrypted data starts from a 48-byte header. The header is used to calculate an AES key by hashing with SHA-256 and shuffling its bytes repeatedly. Once the key is calculated, it will be used to decrypt the rest of data - this time by decrypting it with AES 256-bit, also shuffling the data bytes repeatedly.

The decryption algorithm used by the attackers is best illustrated with the source code below:

The source code below illustrate the decryption algorithm used by the attackers:

void build_complex_hash(int iterations,
unsigned char *data,
int data_size,
unsigned char *hash,
int hash_size)
unsigned char block[48];
unsigned char temp_hash[32];
sha256(data, data_size, temp_hash);
for (int i = 0; i < iterations; i++)
memcpy(block, temp_hash, 32);
for (int j = 0; j < 16; j++)
block[j + 32] = temp_hash[j] + 1;
sha256(block, 48, temp_hash);
memcpy(hash, temp_hash, hash_size);
void decrypt_data(unsigned char *data, int data_size)
unsigned char hash[0x30];
build_complex_hash(0x80, data, 0x20, hash + 0x10, 0x20);
build_complex_hash(0x40, data + 0x20, 0x10, hash, 0x10);
aes256_context ctx;
aes256_init(&ctx, hash + 0x10);
unsigned char temp[16];
for (int i = 0; i < ((data_size - 0x31) >> 4) + 1; i++)
memcpy(temp, data + 0x30 + i * 0x10, 16);
aes256_decrypt_ecb(&ctx, data + 0x30 + i * 0x10);
for (int j = 0; j < 16; j++)
data[0x30 + i * 0x10 + j] ^= hash[j];
memcpy(hash, temp, 16);

In the code above, the sha256() function takes data, its size, and a digest pointer - the call matches standard SHA-256 implementations such as this one.

The AES-related calls/declarations above rely on this implementation of the AES algorithm.

The decrypted resource contains the list of hosts (IP and port), and is trailed with a digital signature, as shown below:

         00000401 - size of data
         ↓                       08 - size of campaign name

00000000 01 04 00 00 83 A8 15 0E 08 00 30 38 30 37 75 6B ..........0807uk
00000010 37 37 D3 03 32 31 32 2E 33 37 2E 38 31 2E 39 36 77..
00000020 3A 34 34 34 33 0D 0A 31 39 34 2E 32 38 2E 31 39 :4443..194.28.19
...                    host names ↵
00000400 30 2E 73 75 33 62 FE 3A D6 85 A2 BC 7B 39 43 F1 0.su3b.:....{9C.
...                digital signature (0x60 bytes) ↵
00000460 F0 7A C8 2C FA 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B .z.,............
                        0B - 11 padded bytes ↵

In order to check the integrity of decrypted host configuration data, Dyre does the following:

  •   •  loads its 8HRUV7NZJ resource
  •   •  decrypts it using SHA/AES-derived algorithm explained above - the decrypted key starts from BCRYPT_ECCKEY_BLOB structure that contains 'ECS3' token followed with 0x30 - the size of key (BCRYPT_ECDSA_PUBLIC_P384_MAGIC, 48-byte/384-bit)
  •   •  loads it with BCryptImportKeyPair(.."ECCPUBLICBLOB") function call
  •   •  hashes the decrypted configuration data with BCryptHashData()
  •   •  calls BCryptVerifySignature() to make sure the obtained hash matches the appended digital signature, which is the signed hash of the data


The activated DLL thus obtains the list of C&C servers.

As soon as the user launches a browser, the DLL will migrate into a running browser process to control online banking sessions. A code running under the browser cannot do high-privilege work (due to low integrity/sandbox restrictions) such as storing configuration data in the arbitrary files. Because of that, Dyre splits its functionality between the instances running under svchost.exe/explorer.exe and a browser process.

The instance running under svchost.exe/explorer.exe serves as a proxy for the browser instance, serving all its requests such as configuration data requests. All the requests and responses are wrapped into IPC (inter-process communication) messages over a named pipe (\\.\pipe\g2fabg5713).

For example, the following communication was logged by hooking the IPC communication between two instances of Dyre code. The first line shows commands received by the proxy instance from the browser. The second line shows its reponse written back into the pipe.

> btid
< TEST-PC_W617600.18875F835C6EE27D8FD0EE9B05225DD7

> slip
< [local host's IP address]

> btnt
< 0807uk77

> ccsr

< dpsr
> [no_data]

> rpls
< no\r\n\r\n\r\n

> newp ... iexplore.exe!test
< success

> ccsr

> dpsr

> rpls
< <serverlist><server><sal>srv_name</sal><saddr>

> rspp
< <rpci>*/bbw/cmserver/* <ssq>1</ssq>...


The communication above shows that at the start, there is no valid response for 'rpls' command - hence the answer is 'no'. However, as soon as a new online banking injection configuration is fetched by the proxy instance from C&C and decrypted, it is transferred via the pipe in clear text back to the browser instance, allowing it to apply the parsing/manipulation logic to the online banking sessions.

C&C Protocol

Using the list of C&C servers obtained from the decrypted resource, Dyre tries contacting them one-by-one until one of the live hosts responds.

The first thing the bot tries to do is to fetch a new public key that will be used to check the validity of digital signature appended to all received files.

It sends a GET request in the following format:

/[campaign name]/[unique string based on computer name, OS version]/[type of command]/[command]/[local host's IP]

for example, to fetch a new 256-bit public key, it issues the 'spk' command with the following GET request:

/0807uk77/TEST-PC_W617600.3F30949AD42522B2140387EBD65001CF/5/spk/[local host's IP]/

The received data is then decrypted using the same SHA/AES-derived algorithm. The decrypted data starts from the 'Ok' marker. Within its body it contains a new 256-bit ECDSA public key that starts from 'ECS1' signature followed with 0x20 (BCRYPT_ECDSA_PUBLIC_P256_MAGIC, 32-byte/256-bit). The entire blob is trailed with a digital signature to be verified with the earlier obtained 384-bit ECDSA public key:

00000000 4F 6B BB 7E 3E 5A A3 60 F8 3B D4 B1 F9 92 B0 14 Ok.~>Z.`.;......
00000050 00 48 00 45 43 53 31 20 00 00 00 E8 E4 09 A6 13 .H.ECS1 ........
00000060 A9 57 1C 24 08 3D 61 B5 C9 F3 12 57 11 E8 25 7C .W.$.=a....W..%|
00000070 0B A9 B4 5A DD 7D AF E5 DE 82 25 9B B1 F3 6F 34 ...Z.}....%...o4
00000080 93 53 0F DF 43 FE DA BC 0C 93 57 7E 81 61 30 88 .S..C.....W~.a0.
00000090 10 FD B5 2C F9 7C 1E 34 3E 31 60 07 51 9D 4E 7C ...,.|.4>1`.Q.N|

Following the 'spk' command, Dyre reports back the victim's OS version using command type 0, with an example GET request below:

/0807uk77/TEST-PC_W617600.3F30949AD42522B2140387EBD65001CF/0/Win_7_32bit/1139/[local host's IP]/

Next, Dyre requests 2 types of configuration files that contain online banking injection logic, by issuing the commands 'httprex' and 'rps'.

The downloaded files are decrypted with the SHA/AES-derived algorithm as before. The integrity of the files is secured with the attached digital signature.

The 'httprex' command fetches the configuration data that specifies web servers that will receive intercepted online banking sessions data. This file starts from 'srv_name' and 'werserv' aliases that are further used within the configuration. The intercepted data is submitted with a POST request to the specified servers, so that any data that the user enters during online banking is hijacked.


The 'rps' command fetches redirection logic that specifies patterns of the targeted online banking pages along with the redirect URLs:


After that, Dyre collects system information and submits it to the C&C using 'generalinfo' command, with a POST request:

/0807uk77/TEST-PC_W617600.3F30949AD42522B2140387EBD65001CF/63/generalinfo/[local host's IP]/

Example of the POST request characteristics:

Content-Type:multipart/form-data; boundary=FegLIfmpQmhVejXbound-690375

The submitted data is not encrypted (all communications still go over HTTPS). For example, it contains the following system information:

CPU: Intel(R) Core(TM) i7-3770S CPU @ 3.10GHz
Processors: 1
Memory: 1023 MB


[list of active programs]

[list of system services and drivers]

If the user navigates to one of the online banking sites targeted within the configuration file, the proxy instance of Dyre will request the content of a 'backconnect' configuration file. This file is requested with 'bccfg' command. Once received and decrypted, the 'backconnect' configuration file will specify the host IP and port numbers where the bot should back-connect to, to make remote VNC/RDP control possible behind NAT/firewall:

  •   •
  •   •
  •   •
  •   •
  •   •
  •   •

After that, the bot will fetch additional plug-ins that enable VNC/RDP remote control and data stealing capabilities, using the following commands (either 32-bit or 64-bit version, depending on the OS version):

  •   •  'pfc32', 'pfc64' - 'Outlook 2010 & 2013 Profile Manager' tool that controls user Outlook profiles
  •   •  'pn32', 'pn64' - email password harvester DLL, targets a number of email clients
  •   •  'rdpp32', 'rdpp64' - RDP Wrapper tool that enables/facilitates remote RDP access
  •   •  'tv32', 'tv64' - VncDLL.dll, used by VNC server
  •   •  'vnc32', 'vnc64' - another VncDLL.dll, used by VNC server
  •   •  'wg32', 'wg64' - a data-grabber/password-stealer DLL (parses browsers' local storage, saved session data/cache, saved passwords)

Dyre contains code that allows adding a new user to the administrator group (having password "1qazxsw2"), logging that user on to the local computer, and loading its profile. Armed with the RDP/VNC plugins, Dyre establishes control over the victim's online banking session.

One of the nasty parameters found in the bot's configuration parser is called AUTOKILLOS. If it's set to TRUE, the bot will delete users from the local computer with NetUserDel() API call, including its own previously created user. Next, it will overwrite boot sectors of the drives C: and D: with random bytes, terminate itself, and shut the system down. These steps are designed to render the system unbootable. The AUTOKILLOS parameter was not found in the live configurations so far, but the bot is capable of executing it if the attackers decide to add it in the future.

No comments:

Post a Comment