In order to profit effectively from a ransomware attack, a threat actor needs to have something to offer in return for payment. This blog post outlines a process to encrypt AWS resources and then revoke access to the secret material until the ransom is paid.
Apparently, this post caused some consternation at AWS, and perhaps this technique is too effective to publish here. So, the original post has been revised to remove the actual scripts, include some mitigations, and provide commentary on how both Public Cloud (AWS Included) and Generative AI are dangerous tools in the hands of the general public and need more regulation.
Typical ransomware attacks involving AWS have involved deleting data with a “promise to give it back” or outright extortion — we’ll release sensitive data on the dark web if you don’t pay us. Both are difficult for a threat actor to do at scale with large AWS Datasets. Downloading data means you need a storage location as big as the source.
But what if there was a way to conduct a more traditional encrypt-everything-and-hold-the-key ransom attack?
AWS provides an encryption service called KMS. One method that has not seen widespread adoption is to encrypt a victim’s data with a KMS key from an attacker or third-party compromised account. KMS keys are generally secure, and there are ways to make it difficult to decrypt the data. However, they rely on the core principles of IAM, and at the core of IAM is the root user. This user is as much a commercial and billing construct as it is a technical control. This means that if an attacker uses a KMS key from another account, I, as the victim, would have my attorney file an emergency order at a local court, demanding AWS turn over or reset the root credentials for the account with the KMS key 1. At the end of the day, AWS is subject to the law 2, and I can recover my data by leveraging the law.
There are two other methods that neither AWS nor the legal system can prevent. The first is to use an external key store (XKS), as outlined here. This is generally complex and probably has scaling issues. It’s also more complicated to explain to the victim (who, let’s face it, screwed up Shared Responsibility to the point you encrypted their data). Effective ransom operators have to operate on trust - trust that a one-way Bitcoin operation will lead to a victim recovering. Finally, as the attacker, you’d have to put the external infra back online, potentially opening you up to detection. While XKS could work, it’s not super effective.
The other method uses KMS Bring Your Own Key Material (BYOKM). In this scenario, rather than letting KMS generate the random key, the customer (or attacker) generates it and uploads it to the KMS Service. The catch is that a customer (or attacker) can also delete the material from the KMS service, rendering all data useless until the key is re-uploaded.
The original post outlines how such an attack would take place:
- Create a new BYOKM KMS Key, create and save a 256bit random number, upload the material, and replicate to all regions for good measure
- Enable Default Encryption using the BYOKM-Key and re-encrypting existing data with that key
- When ready to execute the ransom attack, delete the key material
- Profit
Documenting the Attack
The original post had the bash and python scripts to execute this, and embedded in it was the attack sequence. Now only the AWS CLI and Boto3 calls are shown. This should allow a sufficiently resourced defender to build a detection or implement preventative guard rails.
BYOKM requires a 256-bit random number. While that seems pretty small, it’s probably not going to be brute-forced.
You can start your detections with the CLI commands to create and populate the BYOKM Key:
aws kms create-key --origin EXTERNAL
aws kms get-parameters-for-import
aws kms import-key-material
aws kms replicate-key
Step 2 is to start encrypting resources. There are several ways resources get encrypted in AWS, but EBS Volumes are a big one. AWS supports EBS default encryption, which we will now set using our ransom KMS key. Once this is done, all new volumes and snapshots are encrypted with the attacker-provided key material. You can do the same for any RDS Snapshots. Copy the snapshot and use the new ransom key.
Enable Default EBS Encryption:
aws ec2 enable-ebs-encryption-by-default
aws ec2 modify-ebs-default-kms-key-id
Boto3 calls to copy and encrypt EBS Snapshots:
ec2.describe_volumes()
ec2.create_snapshot()
ec2.copy_snapshot()
ec2.delete_snapshot()
RDS Database encryption
rds.describe_db_instances()
rds.create_db_snapshot()
rds.copy_db_snapshot()
rds.delete_db_snapshot()
Python was used for concurrency. I don’t normally work with Python threading, but ChatGPT made these multi-threaded very easily.
AWS Batch could be used to re-encrypt data in S3. AWS Versioning complicates the attack but comes with its own disadvantages for defenders ($$$$). Lifecycle policies are the best attack vector, but they’re not instant and can be mitigated if you’re paying attention. The IAM action to enable and disable versioning is the same, so there is no way a defender can define a security invariant of “don’t let my users disable versioning” unless they also prevent their users from enabling versioning. If Security were actually Job Zero, the two pizza teams would be required to implement condition keys or different IAM Actions to enable and disable security control. But in AWS, PR is Job Zero.
The final step is the Rug Pull. Delete the custom KMS key material, terminate all the running instances, delete any stray volumes, and delete the RDS databases. Your victim will have their data and will be able to recover, but only after they pay you for the 256 bits that only you possess.
Recovery for the victim is straightforward. They take the base64-encoded 256-bit secret, re-upload it to the KMS key, and their data is accessible again. If they’re absolutely panicked, the AWS CIRT is a free resource to help them recover. But… be wary; that team is probably also looking for you.
Can you prevent this?
Yes. Uploading KMS Key material is a distinct IAM Action, which you can theoretically block via an SCP. A number of CloudTrail events are generated when this activity occurs. You can create detections around those eventName/eventSource pairs. This sort of attack would never go off at the speed of something like NotPetya, which took down Maersk in minutes.
The rug-pull operation is easy to identify and block. kms:DeleteImportedKeyMaterial is what you need to look for and block.
The question is not so much could customers prevent this, but will they?
GenAI is a danger to us all.
One reason for publishing the scripts for this was to demonstrate that GenAI guard rails are a joke. It was trivial to start the conversation and expand from there:
It even helped tutor me on the fastest way to execute Impact:
I made 15 polar bears homeless to create something that was dangerous enough to be unpublished.
-
The new controls around root users and credentials probably don’t materially impact this courtroom-based recovery method. Just demand the root credentials of the Org Management account of the Org that contains the KMS Key. It takes a few extra steps, but recovery is still possible. ↩︎
-
Now that the law is about to be controlled by a hypersensitive narcissist with immunity for all “official” actions, you should be seriously reevaluating your threat model of being in the cloud. Just ask CNN about that. ↩︎