The group behind Emotet is the prime example of a very successful criminal enterprise. Emotet started out as a banking malware but over time evolved into a large botnet providing something akin to a malicious IaaS (Infrastructure-as-a-Service). It started providing access to its extensive list of infected devices to other threat actors and their malware (Trickbot, Dridex, IcedID). It started acting as their loader. Since the beginning of 2021, after a longer “break” which was the consequence of a coordinated take down of Emotet’s infrastructure by the law enforcement, Emotet resurfaced on the 14th of November 2021. Actively trying to rebuild its own infrastructure utilizing Trickbot. Many of the techniques stayed the same, but there are also some important differences.
The Emotet binaries, which were distributed starting from November 2021, come with two embedded elliptic-curve-based public keys of the server. The previous versions were using RSA as the primary asymmetric scheme. An RSA public key was embedded in the sample and used to encrypt the generated AES-128 key before sending it back to its C2. For message integrity, the packet was hashed with the SHA1 algorithm and the hash was appended to the request message. The new version comes with two public keys. One key is used for the Elliptic Curve Diffie–Hellman (ECDH) key exchange protocol while the other is used as part of the signature verification by the Digital Signature Algorithm (DSA). In this blog post, we’ll be looking at how Emotet uses elliptic curve cryptography to protect the network communication and verify the authenticity and integrity of the commands received from its C2.
Comparison: Past vs Present
Since the cryptographic part has changed in the newest version of Emotet we are providing a high level overview of the key steps taken by the older and new versions.
The previous version of Emotet that were using RSA roughly followed the following steps when encrypting a message:
For the newest version the flow and the packets it generates are different as seen below:
For the ECDH to work, the two communicating parties need to each have a key pair, a private and a public key. The public keys are points on an elliptic curve and are generated based on the private keys. The public keys are exchanged, i.e., known by both parties. For example, if s is a private key and P is a primitive element on the curve, then the public key S is calculated as sP=S, which is simply adding P to itself a times. The addition is a group operation. If both parties generate their public keys that way based on known domain parameters, they can calculate the same secret T(SM) (1).
(Figure 1: An example of a DH key exchange algorithm)
The malware already has the ECDH public key of the server. Its own key pair is generated during the execution. Analogues to the example above, it can now generate a secret from the public key of the server and its own private key. Now it only needs to sends its public key to the server for the server to also be able to derive the same secret.
Usage of ECDH
The Emotet’s cryptographic components are now utilizing Microsoft’s Cryptography API: Next Generation (CNG), most notably the BCrypt cryptographic primitive functions. Initially, the malware decrypts the two embedded public keys of the server (ECDH and ECDSA). It uses the same decryption method as with other strings. The keys are saved inside a BLOB structure which consists of a BCRYPT_ECCKEY_BLOB header immediately followed by the key data (Figure 2).
(Figure 2: Structure that windows uses for the ECC public keys)
The ECDH public key of the server is passed to a function responsible for generating the symmetric key (256-bit AES key). On a higher-level it can be described by the following steps:
In more detail, this function’s first step is to generate an ECDH key pair that is unique to the malware sample. It does so by calling BCryptOpenAlgorithmProvider to initialize a CNG provider with the AlgId ECDH_P256 which corresponds to the prime256v1 or P-256 elliptic curve. Next, it generates a new key pair using the combination of BCryptGenerateKeyPair and BCryptFinalizeKeyPair. The keys are then exported into a BLOB using BCryptExportKey for later use (Figure 3).
(Figure 3: VMRay function log – series of function calls responsible for creating a new EC key pair)
Having finalized its key pair, it now imports the servers public key to be able to use it in the generation of a shared secret. It’s using BCryptImportKeyPair that gets the public key as one of the arguments and returns a handle to it. This handle can then be passed to BCryptSecretAgreement together with a handle to it’s own key which it got in the previous step from calling BCryptExportKey (Figure 4). At this stage the secret agreement is equal to the T(SM) value from Figure 1 and Emotet can start deriving a symmetric key.
(Figure 4: VMRay function log – series of function calls responsible for creating the secret agreement)
The secret generated from the public key of the server and the private key of the malware sample is then used to generate an AES key. A new CNG provider is initialized with the AlgId = AES. The key is then derived using BCryptDeriveKey. This function takes the secret agreement as input and generates a key based on a key derivation function (KDF) and its parameters which are passed in the BCryptBufferDesc structure. For that Emotet uses HASH as the KDF and passes the SHA256 as the actual algorithm. This key is then imported using BCryptImportKey (for symmetric keys) so that it can also be later used when encrypting data. The KeyDataBlob passed as argument to BCryptImportKey describes the key. Based on the BCRYPT_KEY_DATA_BLOB_HEADER the key data size is 32 bytes, i.e., 256 bits (Figure 5). To generate the same symmetric key, the server needs the public key of the malware which it prepends to the request sent to the server.
(Figure 5: VMRay function log – sequence of BCrypt calls responsible for key derivation (left) and pseudo-code of the data structure describing the key (right).)
The server’s ECDSA public key is used to verify the response messages the malware receives. The server’s DSA public key is imported just like ECDH public key was. When an encrypted response from the server arrives, it is first decrypted with BCryptDecrypt (no padding is used). It then calculates the SHA256 hash of the decrypted data and uses BCryptVerifySignature to verify the integrity and authenticity, i.e., that it matches with the embedded signed hash – signature (Figure 6).
(Figure 6: VMRay function log – BCrypt functions used when verifying the response)
We have looked at one of the updated components of Emotet which involves the usage of cryptography. The most obvious element is that the malware developers switched from the RSA algorithm to using elliptic curves. Emotet has been encrypting its communication for a long time, but the recent change might be due to a lot of factors like, e.g., smaller key sizes and better security. The C2’s response is now checked for its integrity and authenticity by using ECDSA with a separate key. While using ECDH the symmetric key is never transmitted over the wire and instead the server generates the key from the public key of the malware. We have also observed the switch from CryptoAPI to CNG, which might be due to the fact that the CryptoAPI has been officially deprecated or that it simply didn’t support elliptic curve cryptography.
Initial Sample 7443d5335a207cca176825bd774a412e72882c815206c7f59ace1feb111bb4e9
Server’s ECC keys