Fidelis Cybersecurity
Fidelis Blog

Threat Research Team

The Fidelis Threat Research team is comprised of expert security researchers whose sole focus is generating accurate and actionable intelligence to better secure customers. Together, they represent over... Read More


Vawtrak C2 – Pin it

For several years now, the Vawtrak trojan has been targeting banking and financial institutions, most recently in Canada as reported last week. The Fidelis Threat Research team recently analyzed a new variant to Vawtrak using HTTPS for C2 communications. Given what we’ve seen previously with Vawtrak, simply switching to HTTPS is not a major update in terms of development — but it does show that the threat actors are interested in protecting their C2 communications.

Here are some significant updates to Vawtrak:

  • The malware now includes a DGA. Interestingly, it utilizes a pseudorandom number generator (PRNG) used in Vawtrak’s loader.
  • The DGA hosted site further serves up a list of domains that are cycled through for C2. In this respect, Vawtrak now has a 2-tier C2 discovery infrastructure.
  • It also includes SSL certificate checking (aka SSL pinning), allowing it to evade scenarios in which an SSL man-in-the-middle is present. These solutions are typical in enterprise environments.

Vawtrak has been a very successful banking trojan delivered via both mass spam campaigns as well as through exploit kits. Considering this, it’s not surprising that actors are adding new features. While the use of DGAs and TLS is widespread across various crime families, SSL pinning is still rare.

PhishLabs recently discussed their observations around Vawtrak’s DGA. This blog post covers our reversing of the DGA algorithm and the SSL pinning implementation.

The samples analyzed in this post are:



SHA256: 6f9727385d3bf55e1d57fe7606999db2bc29f21b7f9d1d3fa7073218d73ac28d


SHA256: 721b673777b927146b1a62fd2079f726624b3e7c789d6f04e5ccd6f122d44e2d



SHA256: a513fc3dd36d24ea9fd17596607278aa47a03b67a3c09aff72fc2a8b8a9e0636


SHA256: 37cf565b8ee6db67b11f2a084a11e30e14bfc8439c462270d01d50bdbae0ea61


The loader for Vawtrak, which has been updated numerous times over the years has one purpose:  To load the injected code that it keeps encoded and compressed in its RCDATA named resource. This data is decoded in a manner consistent with what we would expect from Vawtrak, using a PRNG known as Linear Congruential Generator (LCG) after which the data is then LZMAT decompressed to give us what you might call the initial inject. This inject contains just about everything needed by Vawtrak: The header, which historically has had a number of flags; the URI and domains to use; and, along with the header data, code for handling the injection process for the DLL (which is also included in this initial inject in both 32-bit and 64-bit form).


A broad overview of this new Vawtrak initial C2 system shows that a domain is generated, and then connected to and certificate validated, by the bot. If this fails, then the bot sleeps and continues N number of times:


The first action taken is a domain generation. This is done by using a seed found in the initial inject header and a tld which has, until now, been static – always ‘.ru’.


Figure 1: Vawtrak Generate Domain

The routine takes a seed and passes it through the LCG once, dividing the result by 5 and using the remainder + 7 as the length of the domain to be generated — which means our domain lengths fall within the range of [7,12] in length (not counting the TLD). Once the length is determined, the result of the previous PRNG is passed into another. The result is converted to a character using the formula ((result % 26) + 97). Some example python code follows:

seed_mask = 0x7FFFFFFF

seed = PRNG(init_seed)

rem = (seed & seed_mask) % 5

rem += 7

out = “”

for i in range(rem):

seed = PRNG(seed)

tmp = (seed & seed_mask) % 0x1a

out += chr(tmp + 0x61)


SSL Pinning

This new Vawtrak DLL contains code for performing an HTTPS connection as well, but it also performs some checks on the certificate it receives from the C2 server. It adds up all the characters in the Common Name and then divides the byte by 0x1a and adds 0x61, which should match the first character (Figure 5). It also uses a public key from the aforementioned initial inject header to verify the signature hash that was passed in the SubjectKeyIdentifier field of the certificate.


Figure 2: Connect over 443


Figure 3: Vawtrak Request setup


Figure 4: Vawtrak turn off cert validation and send request

In Figure 2 and Figure 3, we can see the bot setting up the HTTPS request; it is very particular to turn off as many certificate validations as possible in the options. The flags for HTTPOpenRequest are:


After the request is sent, the bot goes into checking the certificate along with decoding the RSA public key from the initial inject header.


Figure 5: Vawtrak CN check

Decoding the header

We’ve talked a lot about a header on the initial inject, because it contains a lot of information that we are now interested in. After mapping out how these values are parsed, and then subsequently used, we can discern the following structure of this updated Vawtrak.

struct Vawtrak_Hdr {

int total_length;

int header_length;

int offset_to_first_mz;

int offset_to_second_mz;

int project_id;

short unknown;

unsigned char exe_or_dll_flag;

int rsa_seed;

char rsapubkey_block[148];

int dga_seed;

int num_domains;


There are other data and flags that have yet to be discerned from this header, but this allows us to accomplish a number of things — such as pulling out the embedded DLLs, tracking the project ID, harvesting the RSA public keys and generating the DGA domains the bot uses for initial communications. This entire process can be seen in python code on our github.

To further complicate this new C2 hand off, the developers have added another section — near the top of the module URLs in the Vawtrak config — which when decoded will have a list of C2 domains that the bot will also use for C2 communications. To accommodate this new section, the developers added a command to the C2 data parsing section. This command is 41, which is the highest-numbered command at the moment.

struct CMD_41 {

int total_length;

char signature[0x80];

int seed;

int length;

char c2s[length];


Once decoded, the C2s are a collection of structures with length and C2 string. Creating a Vawtrak config parser now just becomes a matter of parsing the sections and looking for the commands we are interested in — such as the webinject config (CMD 2), the C2 domains (CMD 41) and the modules  (CMD 3). To help demonstrate this, we have supplied python code on our github.


Vawtrak has been a very successful banking trojan, delivered via both mass-spam campaigns as well as through exploit kits. Keeping this in consideration, it’s not surprising that new features and techniques are being introduced. The use of DGAs and TLS is widespread across various crime families, but SSL pinning is still rare.

To access the python scripts referenced in this post, please visit our Github repository. Decoders created as part of this analysis have been added to Fidelis Barncat.

-Jason Reaves, Fidelis Threat Research

Stay up to date on all things security

Subscribe to the Threat Geek Blog