Perfecting Ransomware on AWS — Using keys to the kingdom to change the locks

Harsh Varagiya
9 min readJust now

--

If someone asked me what was the best way to make money from a compromised AWS Account (assume root access even) — I would have answered “dump the data and hope that no-one notices you before you finish it up.”

This answer would have been valid until ~8 months ago when I stumbled upon a lesser known feature of AWS KMS which allows an attacker to do devastating ransomware attacks on a compromised AWS account.

Now I know that ransomware attacks using cross-account KMS keys is already known (checkout the article below)— but even then, the CMK is managed by AWS and they can just block the attackers access to the CMK and decrypt data for the victim because the key is OWNED by AWS and attacker is just given API access to it under AWS TOS. Also there’s no way to delete the CMK but only schedule the key deletion (min 7 days) which means there’s ample time for AWS to intervene.

How it started — the launch of AWS KMS XKS

On 29th November 2022, AWS Released XKS (eXternal Key Store) for AWS KMS (Key Management Service).

How it works. Source: XKS announcement article

Here’s a short summary of what it does & how it works (generated using ChatGPT).

AWS Key Management Service (KMS) for AWS KMS External Key Store allows API calls to securely communicate with your On-Prem Hardware Security Module (HSM), keeping key material securely within your HSM. This feature enables encrypting data using external keys for over 100 AWS services, like Amazon EBS and S3, without modifying existing configurations. It’s beneficial for a small portion of regulated workloads but introduces additional operational burden and risks, making it suitable only for a limited number of customers.

In the context of encryption and key management, AWS KMS uses envelope encryption, where data keys are encrypted with specific customer managed keys (root keys). Root keys are securely generated and stored in HSM managed by the customer, ensuring they never leave the secured hardware. All encryption and decryption operations occur within the HSM environment. These root keys are used in combination with AWS CMK material to encrypt data if AWS KMS XKS is used and if any one of these two (Root key or AWS CMK backed by XKS) is not available then the data cannot be decrypted.

Effectively,

  1. Root Keys are Stored in Customer Managed External Key Stores.
  2. AWS KMS can leverage an on-prem HSM as an “External Key Store” (XKS) to do cryptographic operations.
  3. Whoever is in control of these Root Keys for the HSM is in control of the Data encrypted by the CMK backed by XKS in AWS.

Building an ‘Aws-RedTeam-Kit’ for Ransomware Simulation

We need a public domain with a valid HTTPS cert not signed by LetsEncrypt (read their spec for the details) where we will run our XKS Backend service. We can either buy a HSM and use it to do a ransomware attack on an AWS target.

I need me one of those

Or, we can leverage SoftHSM to simulate an HSM — https://www.opendnssec.org/softhsm/ along with the official aws-kms-xks-proxy https://github.com/aws-samples/aws-kms-xks-proxy to have an HTTP server that AWS can work with.

Note: the original aws-kms-xks-proxy repo is currently broken and the fork I have in my account currently is compiling correctly (aws signing library version tagging issue) hence if you are testing it out use https://github.com/HarshVaragiya/aws-kms-xks-proxy .

Putting it all together

I have created the infra setup using docker for running your own XKS based attack using cloudflare domain here:

Make sure to update the config/settings.toml file for testing — specifically, modify the following options as per your preference:


region = AWS region closest to your location
uri_path_prefix = can be anything you want
sigv4_access_key_id = can be anything you want that follows the given regex
sigv4_secret_access_key = can be anything you want that follows the given regex

Make sure to select the AWS region closest to you as XKS API needs low latency (<15–20 ms) otherwise it throws exceptions for all operations and is a nightmare to debug.

Also create a .env file with the Key CLOUDFLARE_TUNNEL_TOKEN and value of the cloudflare tunnel token from your cloudflare zero trust dashboard of your attacker controlled domain. This is the quickest way to expose an internal service with a reputed HTTPS certificate.

cloudflare tunnel setup for exposing xks-proxy service

Once that is done, we can run make infra to set up the needed docker containers.

building the tunnel and xks-proxy service infra

With all the needed infra (XKS-Proxy, Cloudflare Tunnel, SoftHSM) ready for action, we can validate that the xks-proxy service running locally on our laptop is accessible with a valid HTTPS certificate provided by cloudflare on the fly.

valid HTTPS certificate for publicly accessible xks-proxy service

Testing the Simulated HSM setup

We will use the test-client provided by AWS to test if our XKS is working as expected before using this to encrypt any data.

https://github.com/aws-samples/aws-kms-xksproxy-test-client.git

be sure to export all the values according to your setup like :

export XKS_PROXY_HOST="https://xks2.pubkeypair.com" # your CF tunnel domain
export URI_PREFIX="aws-redteam-kit"
# Access key ID must have between 20 and 30 characters. Valid characters are uppercase A-Z and 2–7
export SIGV4_ACCESS_KEY_ID="AKIAHPRO52CGOA4VJPU4"
# Secret access key must have between 43 and 64 characters. Valid characters are a-z, A-Z, 0–9, /, +, and =
export SIGV4_SECRET_ACCESS_KEY="yTBJ7hqzT7TTtqCHGqFjJQDTJaZolkCz5i5h5TUSwHNUK1glZ6rMpQ=="
export KEY_ID="thekey"
export REGION="ap-south-1"
export SCHEME=

And then we run the tests using :

./test-xks-proxy

We should see that all 35 Tests have Passed ✅. If this is not the case then there is some issue with the settings / parameters.

Now that all our simulated HSM infra is working and as the attacker, we can focus on the next step.

Attacking the AWS Target

1. Creating KMS Keys using AWS Console UI

Once the XKS is ready, we can make the kms:CreateExternalKeyStore API Call with the necessary details (copy paste from the test parameters) to set it up.

creating external key store using aws console UI

Once the keystore is created, we can go ahead and connect it using the key store actions > connect.

connected external key store

Next, we will create a CMK that is backed by this external key store allowing us to fully own the cryptographic process.

creating the XKS backed CMK using AWS Console UI
CMK Backed by XKS

Once the Symmetric ENCRYPT_DECRYPT key is created — which is backed by XKS — we can encrypt data with it and the sole control of the data & cryptographic operations would lie with the HSM owner (the attacker).

2. Attacking S3

Let’s assume that attacker starts batch operations / scripts to start encrypting data in S3 buckets, how would that look like ?

normal S3 operations when s3 has the KMS encryption with above CMK enabled

You can literally see the xks-server encrypting and decrypting data on the fly in docker logs!

xks server logs

And if the attacker were to stop the xks-server or their laptop went offline —

S3 objects being bricked after xks-server goes offline

This test was done manually but it proves the point. S3 does not use kms grants and hence the effect of xks-proxy going down is instant and data in s3 is completely inaccessible.

In the above example (not a versioned bucket) — an s3 bucket data was re-encrypted to use the attacker controlled KMS key. Once the re-encryption is complete, the data is accessible only till the xks-proxy controlled by attacker is up and running. The attacker can stop the xks-proxy docker container or cloudflare tunnel and all object operations will start failing immediately.

After the attacker start the xks-proxy docker container again (ex — after the ransom is paid), the data in S3 is immediately accessible.

starting xks-server allows access to the bricked data in S3

The exact error message for object access incase anyone is interested :

download failed: s3://ark-src-bucket/1.img to ./d2.img An error occurred 
(KMS.KMSInvalidStateException) when calling the GetObject operation:
AWS KMS rejected the request because the external key store proxy did not
respond in time. Retry the request. If you see this error repeatedly,
report it to your external key store proxy administrator.

Full attack in one screenshot truly shows the effect

Attack chain example of S3 data being re-encrypted with XKS CMK

3. Simulating an attack on EC2 instances — KeySwitch

This project is supposed to simulate how an APT might target EC2 instances (EBS Volumes) in order to hold the data for ransom.

KeySwitch

To test out this scenario, I built a tool called “KeySwitch” which helps create the Custom Key Store and KMS Keys and automates the process of re-encrypting EBS Volumes using a given KMS key. It is the perfect tool to hold data for ransom given AWS Access.

Generating a Symmetric AES_256 Key in AWS KMS which is backed by XKS

As a proof of concept and not wanting to harm any critical data stores in AWS like S3 , RDS , DynamoDB — I built the capability into KeySwitch to re-encrypt EBS Volumes with the XKS Key within minutes.

The EBS Module of KeySwitch does the following in order :

  1. List all EBS volumes in the AWS Region.
  2. Take snapshots of all the Volumes.
  3. Create new Volumes using the snapshots and encrypt them using the XKS Backed KMS key.
  4. Delete ALL the snapshots in the AWS Region (we nuke all snapshots — do not use this directly for testing PLEASE).
before keyswitch operates

Once all KMS Grants are revoked for the KMS Key and XKS-Proxy is shut down by the attacker — all data in the target environment’s EBS Volumes cannot be decrypted without attackers key (xks server being online).

KeySwitch In Action Holding data in EBS for Ransom

We can validate that there are newly encrypted EBS volumes in the AWS console within a minute! If an attacker were to detach the EBS volumes and then delete them — the only way to access the data would be to keep the xks-server running.

we created 4 new volumes encrypted with xks-backed key

Note: I had previously built in additional capabilities into the tool to Stop all EC2 instances and Detach EBS Volumes attached to them and then Subsequently delete all EBS Volumes that are not encrypted with XKS Backed KMS key. But since then I have decided to open-source this tool and removed that. An attacker won’t need my bare-bones single-service tool to do a ransomware attack anyways.

Preventing this attack

  • The External Key Store is an AWESOME feature of AWS and it should definitely not be taken as a downside. In no way is AWS responsible if an access key gets leaked and this attack vector is used to compromise the target account. Worse — they can’t do much to help in this case as according to them the key material is in control of the HSM owner.
  • The best way to defend against this is to use a SCP at organization level to block the kms:CreateCustomKeyStore API Call in-case your organization does not need it (90% AWS Accounts out there probably don’t)
  • Example SCP To deny the kms API Call for XKS.
{ 
"Version": "2012–10–17",
"Statement": [
{
"Sid": "PreventRansomwareAttacks",
"Effect": "Deny",
"Action": "kms:CreateCustomKeyStore",
"Resource": "*"
}
]
}

If you’re looking to collaborate on such random research projects, feel free to reach out to me on LinkedIn or email :)

--

--

Harsh Varagiya

I'm a curious individual passionate about cybersecurity, cloud technology, infrastructure, hardware, and all things STEM.