In Part 1, we explained what Intel SGX enclaves are and how they benefit ransomware authors. In Part 2, we explore a hypothetical step-by-step implementation and outline the limitations of this method.
Watch this live attack demo to see how the CrowdStrike Falcon® platform and the CrowdStrike Falcon Complete™ managed detection and response team protect against ransomware.
Table of Contents
Implementation
In this section, we build out a step-by-step example of a ransomware that uses enclaves for asymmetric encryption. The ransomware is divided into two parts:
- The enclave, which is in charge of cryptographic operations, such as keys generation
- The untrusted area, where the regular core of the application is responsible for the enclave load, file opening and writing operations
Extracts of code presented here will be coming from the regular core of the application (main.c) or from the enclave (enclave.c). The enclave will generate a pair of RSA keys, seal the private key and encrypt the victim’s data inside the enclave using the Intel SGX API. Let’s take a look at how this is done and how the core of the application interacts with the enclave.
Initialization
First, the regular core of the application initializes the resources required for the ransomware execution, including creating and setting up the enclave. To load the enclave, we use the function sgx_create_enclave()
, from sgx_urts.lib.1 The function prototype is:
sgx_status_t sgx_create_enclave (
const char *file_name, const int debug,
sgx_launch_token_t *launch_token,
int *launch_token_updated,
sgx_enclave_id_t *enclave_id,
sgx_misc_attribute_t *misc_attr
);
Arguments of this function represent some of the enclave attributes, such as the compilation mode or information about previous loads. For instance, sgx_launch_token_t
is an opaque structure that represents the enclave launch token. The token information holds information about the enclave throughout its execution and can be saved to facilitate future loads of the enclave.
Once the enclave is loaded, the regular core of the application can execute an ECALL to start the key generation process.
Key Generation
Inside the enclave, the key generation is based on the Intel SGX SDK dubbed sgx_tcrypto.lib. This is a documented API that can be directly called from the enclave. Under the hood, the API is based on other cryptographic libraries developed by Intel: the Integrated Performance Primitives (Intel® IPP) and the Intel® Software Guard Extensions SSL cryptographic library (Intel® SGX SSL),2 both of which are based on OpenSSL.
The first step in this process is to generate RSA components for the private and the public keys from the enclave using the function sgx_create_rsa_key_pair()
. This is a preliminary call, performed prior to the function calls that create keys, used in order to generate components that comply with the predefined RSA key modulus size and public exponent.
From these RSA key components, we use the function sgx_create_rsa_pub1_key()
to generate the RSA public key that will be used to encrypt the victim’s files.
Sealing the Private Key
The next logical step-up would typically be to generate the private key, as we did with the public key. In this case, however, we don’t yet need the private key, as the private key will only be used for deciphering purposes, should the victim comply with the demands of the ransomware authors. At this time, we just need to safely store and hide the private key components to allow for future retrieval. To this end, we use the data sealing method to ensure that the private key can be written and stored encrypted on disk, without ever appearing as clear-text in the OS regular memory.
One way we could do this is by generating the private key and then sealing it directly on disk, but we won’t proceed this way. Consider the function prototype from the Intel SGX SDK3 that generates the private key shown below.
sgx_status_t sgx_create_rsa_priv2_key(
int mod_size,
int exp_size,
const unsigned char *p_rsa_key_e,
const unsigned char *p_rsa_key_p,
const unsigned char *p_rsa_key_q,
const unsigned char *p_rsa_key_dmp1,
const unsigned char *p_rsa_key_dmq1,
const unsigned char *p_rsa_key_iqmp,
void **new_pri_key2
);
Note that the private key value is written onto a void**
but under the hood, the actual structure used is an EVP_PKEY
structure, a complex structure that originates from the OpenSSL library.
Therefore, if we wanted to seal the private key, we would need to use the EVP_PKEY
structure. Nonetheless, enclave’s development architecture is not designed to readily import external libraries, so using the Open SSL library directly would be cumbersome. Otherwise, we could attempt to recreate the structure from scratch, but this would require several parsing operations. Given the complexity of storing the private key in the appropriate structure, it is much easier to save the private key components and build the private key at a later stage. To support this process, we created a structure to collect the private key components.
We now have the means to seal the private key components for a potential future decryption. We’ll use the same values produced when we generated the key components, and assign them to the appropriate fields in our custom PrivKeyComp
structure. Once the structure is correctly set up, we can seal the private key components with sgx_seal_data_ex()
, from sgx_tservice.lib.4
Here, we use sgx_seal_data_ex()
, the extended version of sgx_seal_data()
, which allows us to use the MRENCLAVE policy. We chose this policy because it guarantees that other enclaves signed by the same enclave’s authors won’t be able to access the sealed data. Should the attacker’s enclave signature be stolen, it could be used to unseal the data.
Once sealed, the private key components can be returned to the regular core of the application and written on disk.
Encryption
From this point, we have two options for encrypting the victim’s data. The first option is to return the public key to the regular core of the application and to encrypt the victim’s files outside of the enclave. The other option is to keep the public key inside the enclave and use functions from the Intel SGX API to encrypt the victim’s data. The latter is more complex than a classic encryption process outside of the enclave, but we’ll use this method to demonstrate possibilities of SGX programming.
The untrusted part of the application is in charge of opening and reading the victim’s file. To get the encrypted data that will be generated within the enclave, we need to initialize the output buffer in the regular core of the application. Otherwise, the buffer generated within the protected memory won’t be able to be sent to the untrusted space.
The encryption is done with the function sgx_rsa_pub_encrypt_sha256()
, which performs a RSA-OAEP encryption scheme with SHA-256. This computes an encryption and an encoding operation for buffers, which is limited to the size of the RSA modulus n, and results in a buffer of the same length. In this case, given a RSA modulus n of 256 bytes, the output buffer of sgx_rsa_pub_encrypt_sha256()
will be 256 bytes long.5 As such, we allocate a buffer of 256 bytes for the output buffer that will hold the encrypted data.
Next, we’ll send this output buffer with the buffer containing the data to encrypt.
The enclave receives the buffers and uses the public key that has been generated previously to perform the encryption. This is done in three steps. The first step is calling sgx_rsa_pub_encrypt_sha256()
to get the size of the resulting encrypted buffer. Once the size is returned, we check that it corresponds to 256 bytes (the size we allocated to the output buffer). If it matches, we perform a second call to sgx_rsa_pub_encrypt_sha256()
to get the encrypted data in the output buffer.
Finally, the regular core of the application overrides the original file content with the encrypted content, returned from the enclave.
Unsealing and Decryption
The same logic applies to the decryption process. The sealed data is sent to the enclave, which unseals it with sgx_unseal_data()
and stores the private key components in the PrivKeyComp
global variable. Encrypted data is sent to the enclave, builds the private key using the global variable PrivKeyComp
as parameters for sgx_create_rsa_priv2_key()
, and then decrypts the data with the function sgx_rsa_priv_decrypt_sha256()
. The deciphered data is then returned to the regular core of the application, which overrides encrypted files with the original clear-text.
SGX’s Operational Limits
As we’ve established, using enclaves has considerable benefits such as ensuring that targets of ransomware won’t be able to retrieve their deciphering keys. However, this tactic also has considerable limitations, which account for its limited prevalence in ransomware attacks.
Hardware Requirements
First, enclaves have strict hardware specifications. Since SGX is a proprietary technology, it requires an Intel CPU. Although AMD has an equivalent technology called ARM TrustZone, code compiled based on Intel SGX libraries will not work on non-Intel CPUs. Furthermore, only certain Intel CPU models support SGX, as Intel has deprecated the feature for the 11th and 12th core processor desktop generations.6 As a final hardware requirement, the Intel SGX feature needs to be enabled from the BIOS, which is not done by default.
Given all of these requirements, the probability that a targeted system can execute a binary using enclaves is very low. What’s more, as the SGX technology use might not be enabled on every infected system, the chances of successfully infecting a target are considerably low, especially in comparison to more common ransomware methods.
Signature Requirements
Earlier in this blog, we explained that enclaves need to complete a verification process to be compiled in release mode. Nonetheless, an enclave compiled in debug mode can still be executed on an Intel SGX-enabled machine if the required libraries are imported with the malicious binary. The size of the binaries required for the attack would be much bigger than that of a classic ransomware binary, but such a scenario is plausible.
Moreover, if attackers intend to use an enclave in release mode, they might go undetected by the Intel verification process if the enclave only appears to generate a pair of RSA keys, and receive buffers to encrypt and seal data. In such a situation, how would Intel determine whether the enclave serves malicious purposes?
Researchers from Graz University of Technology claim that “Intel does not inspect and sign individual enclaves but rather white-lists signature keys to be used at the discretion of enclave developers for signing arbitrary enclaves.”7 They cite the example of an independent student that has successfully completed Intel’s process to get a signing key. This raises the question of whether malware authors could use enclaves by going through Intel’s allowlisting process.
Another possibility for ransomware authors would be to steal a legitimate signature. This adds another level of complexity to the attack, but it has been done in the past. In this case, as soon as the attack is detected and reported to Intel, Intel revokes the enclave signature used from the allowlist, preventing the malicious enclave from loading. Whether the signature is stolen or acquired legitimately, the risk of discovery quickly grows as soon as the ransomware campaign is underway, raising the issue of the signature’s validity lifetime.
To provide more flexibility in the use of enclaves, in 2018 Intel released the flexible launch control alternative.8 This feature allows third parties to control which enclaves can be loaded on appropriately configured machines, bypassing the Intel verification process. It requires the targeted machines to support and enable the flexible launch control feature, configured in each machine’s BIOS. This approach requires having access to the BIOS prior to the infection and having administrator’s rights to configure the environment, both of which add complexity to the attack.
Surely but Slowly
Within the enclave, code is executed in a specific context, which results in a slower execution than in a regular OS environment. The longer the ransomware takes to execute, the more likely the user will be alerted to suspicious activity and have time to react to it, further jeopardizing the chances of conducting a successful attack.
Vulnerabilities to Side Channel Attacks
Intel does not consider side channel attacks as part of the SGX threat model. The Intel® Software Guard Extensions Developer Guide9 states, “Intel SGX does not provide explicit protection from side-channel attacks. It is the enclave developer’s responsibility to address side-channel attack concerns.”
This implies that there are ways to observe what is happening inside an enclave and thus potentially intercept the deciphering key, further underscoring that using enclaves is far from foolproof and has been successfully leaked in the past, which is discussed in the paper “SGAxe: How SGX Fails in Practice.”10
Safety of the Sealed Private Key
There are also limits to the safety of the sealed key written on disk.
Intel’s Developer guide states, “Enclaves, regardless of the number of trusted threads defined, must not be designed with the assumption that the untrusted application will invoke the ISV interface functions following a specific order. Once the enclave is initialized, an attacker may invoke any ISV interface function, arrange the calls in any order and provide any input parameters. Keep these ploys in mind to prevent opening an enclave up to attacks.”11
A recent question on Intel’s community forum posed whether different applications use the same enclave, to which Intel replied, “There is no built-in way to prevent one untrusted app from loading another’s enclave.”12 As such, should forensic investigators retrieve the enclave binary used in a ransomware attack and the sealed private key, they might be able to recreate an application that interacts with the enclave to make it unseal the private key, at the very least in debug mode.
In practice, creating such an application requires importing the enclave .edl file, containing the ECALLs definition. Since it is unlikely that this file would be imported in the attack’s binaries, the only option would be to reconstitute the .edl file, which could be further complicated should attackers obfuscate the enclave binaries.
In a scenario where the private key has been sealed using the MRSIGNER policy, the safety of the sealed key is in even greater question. If forensic investigators are able to retrieve the enclave author’s signature, they could recreate an enclave similarly signed with Intel’s support and make this new enclave unseal the data. Indeed, since the data was sealed using the enclave author’s signature, another enclave with the same signature would be able to unseal it.
While each of these limitations adds constraints to the attack, they can all still be mitigated. Having the SGX feature enabled can be bypassed with a few pre-infection steps. To facilitate the use of enclaves, Intel released an activation app13 that allows users to enable Intel SGX on compatible Intel Core based processor-based platforms, simply by clicking on the “Activate” button, as shown in Figure 9. The application needs to be run with administrator privileges, but a social engineering approach could easily make a victim click on one button from a legitimate application.
Once the targeted system has the Intel SGX feature enabled, an attacker could bypass signature requirements by using an enclave binary compiled in debug mode to embed dependencies in the attack. To accelerate the execution of their code, they could use a multi-threading implementation or an externalized encryption process within the regular core of the application. Furthermore, if the enclave binary is completely removed from the infected system after the attack, the attacker can be confident that the sealed private key won’t be unsealed until they allow it. Finally, it is very unlikely that side-channel attacks would be set up prior to infection, making it highly improbable that these would successfully thwart a ransomware attack using enclaves.
Conclusion
The Intel SGX technology offers developers a unique opportunity to protect their code. We reviewed how the architecture of enclaves provides an environment that is conducive to protecting sensitive data and embeds different mechanisms to safely manipulate it, such as with sealing.
Although this can be beneficial in day-to-day operations, it can also be exploited for malicious purposes, as we saw with the case of cryptographic key management by ransomware authors. Enclaves allow ransomware authors to safely and securely generate cryptographic keys, preventing victims of attacks from leveraging two of the most common scenarios ransomware authors want to avoid: retrieving deciphering keys and preventing infection with offline targets.
The low prevalence of enclave use by ransomware is largely due to the technical limitations imposed by the Intel SGX. Its hardware requirements and deprecation for future CPU generations reduce the chances that targeted systems will be able to meet all of the conditions required for the enclave execution. Furthermore, releasing an enclave in production mode requires going through Intel’s signing process, which, if completed successfully, results in a signature that can be quickly revoked overnight, further reducing the ransomware’s chances of successful execution.
As we have demonstrated, ransomware authors can’t rely exclusively on enclaves to orchestrate attacks but may benefit from their use for cryptographic key management. As there are legitimate uses for enclaves, a preventative approach to these ransomware attacks should not exclusively rely on the detection of an enclave’s load.
As part of our commitment to enabling customers to have continuous visibility across their organization, the CrowdStrike Falcon sensor has visibility on the use of enclaves and uses this data alongside event telemetry to determine whether a process is malicious and to respond to detected threats. In the end, an enclave is just a clue — nothing more, nothing less.
See for yourself how the industry-leading CrowdStrike Falcon platform protects against modern threats like ransomware. Start your 15-day free trial today.
Additional Resources
References
- “Intel® Software Guard Extensions SDK for Windows* OS Developer reference,” revision 2.7, March 2020
- “Intel® Software Guard Extensions SDK for Windows* OS Developer reference,” revision 2.7, March 2020
- “Intel® Software Guard Extensions SDK for Windows* OS Developer reference,” revision 2.7, March 2020
- “Intel® Software Guard Extensions SDK for Windows* OS Developer reference,” revision 2.7, March 2020
- “RSA Cryptography Specifications Version 2.2,” November 2016, IEETF
- 11th Generation Intel® Core™ Processor Desktop, Datasheet, Volume 1 of 2, Rev 004, May 2022
- Michael Schwarz, Samuel Weiser, Daniel Gruss, “Practical Enclave Malware with Intel SGX,” 2019
- Intel, 2018
- “Intel® Software Guard Extensions (Intel® SGX) Developer Guide,” revision 2.7, page 51, March 2020
- Stephan van Schaik, Andrew Kwong, Daniel Genkin, Yuval Yarom, “SGAxe: How SGX Fails in Practice,” 2020
- “Intel® Software Guard Extensions (Intel® SGX) Developer Guide,” revision 2.7, page 51, March 2020
- Intel’s communities forum, 2017
- Intel Software Guard Extensions Activation App, Microsoft Store
Leave a Reply