WEBVTT

00:00.000 --> 00:04.580
My name is Spencer Geetson, and today I'm going to be talking about ransomware in the cloud.

00:06.320 --> 00:21.000
So, I'm a huge cloud nerd, so instead of the traditional Who Am I slide, I did an AWS STS Git Caller Identity slide, which basically says what Jaren just shared.

00:21.000 --> 00:22.660
My name is Spencer Geetson.

00:22.660 --> 00:25.520
I'm a cloud security researcher at CrowdStrike.

00:25.640 --> 00:34.300
I previously was a penetration tester at Rhino Security Labs, and I've got an interest in technical writing, gaming, and programming.

00:35.940 --> 00:38.720
So first I want to start off with an agenda.

00:39.060 --> 00:45.420
We'll talk about AWS basics, just kind of a TLDR of the services and resources I'm going to go over.

00:45.800 --> 00:55.680
Ransomware in the cloud, simple storage service for AWS S3, we're going to talk about ransomware techniques, prevention, detection, and indicators.

00:55.820 --> 01:01.200
And then the same thing for DynamoDB techniques, prevention, detection, and indicators.

01:02.440 --> 01:18.700
And then at the end, we're going to talk about other potential targets, so other AWS services, other clouds, those kind of things, cloud provider intervention, and other takeaways from the presentation, and then just some additional resources and references at the end.

01:20.040 --> 01:22.320
So AWS basics.

01:23.180 --> 01:30.000
I imagine there's a wide range of skill set in the audience, so you may know this, you may not.

01:30.340 --> 01:33.620
AWS S3 is just object storage in the cloud.

01:33.620 --> 01:34.940
It's their offering.

01:34.940 --> 01:40.200
There's S3 buckets, which basically hold all your buckets of objects.

01:40.200 --> 01:55.420
Objects are essentially files that are stored in buckets, and then there are bucket policies which determine the access permissions and conditions that apply to a bucket and the objects within it.

01:55.420 --> 01:58.460
And we'll get more into that later on.

01:59.100 --> 02:02.460
DynamoDB, this one's pretty simple for our needs.

02:02.460 --> 02:03.740
It has tables.

02:03.740 --> 02:09.680
It's a NoSQL database offered by Amazon, and it has tables that hold data.

02:09.680 --> 02:15.300
That's as much as you really need to know if you're not familiar with the service right now, at least.

02:15.860 --> 02:18.580
Then there's KMS, Key Management Service.

02:18.780 --> 02:28.860
It has keys, which could be asymmetric or symmetric keys, depending on your use case, and they're typically AWS managed.

02:29.320 --> 02:35.300
They have key policies, which define who can use keys and what they can be used for, etc.

02:35.720 --> 02:42.180
And that's kind of the rundown of the different resources and services that I'll be talking about today.

02:43.600 --> 02:45.320
Ransomware in the cloud.

02:45.380 --> 02:51.840
I'm going to be comparing the state of ransomware today to soon, essentially.

02:52.340 --> 03:03.720
Right now, there's traditional ransomware like Locky, WastedLocker, things like those that target traditional infrastructure.

03:04.260 --> 03:07.460
Cloud-native ransomware is on the way.

03:07.460 --> 03:10.480
There's none yet, or none publicly.

03:10.480 --> 03:15.980
We don't know what's going on behind the scenes or in breaches that haven't been made public.

03:16.020 --> 03:22.120
But it's better to get ahead of these things before it becomes a problem.

03:22.520 --> 03:25.220
It's better to be ready for them.

03:25.840 --> 03:35.140
So traditional ransomware typically targets servers and workstations, while cloud ransomware would be targeting cloud-native resources.

03:36.340 --> 03:39.340
Traditionally, they're operating system dependent.

03:39.340 --> 03:43.160
Primarily, windows and active directory environments are being targeted.

03:43.160 --> 03:46.820
Where in the cloud, it's going to be cloud provider independent.

03:46.820 --> 03:58.260
We're focusing on AWS for this presentation, but all the concepts can be applied to other cloud providers like Google Cloud and Microsoft Azure and others.

03:58.800 --> 04:05.020
And then traditionally, they exploit zero-day or known vulnerabilities to spread and infect their targets.

04:05.020 --> 04:07.140
Where in the cloud, it's none of that.

04:07.140 --> 04:08.240
It's just feature abuse.

04:08.240 --> 04:10.900
There's no vulnerability abuse.

04:10.980 --> 04:17.780
It's just using features the way they were designed, essentially, in a little bit of a malicious way.

04:18.840 --> 04:21.900
So with that, we'll dive into S3.

04:22.000 --> 04:23.600
There's three techniques I'm going to cover.

04:23.600 --> 04:28.140
It doesn't mean they're the only three techniques, but these are three notable ones, at least.

04:28.900 --> 04:31.200
Local encryption is the first technique.

04:31.200 --> 04:35.600
It's very slow compared to the others, but it's got a critical impact.

04:36.580 --> 04:40.100
The detection likelihood, I rate it as likely.

04:40.100 --> 04:44.940
But this is only if you have monitoring in your environment.

04:44.940 --> 04:49.160
If you aren't monitoring what's going on in your environment, you're not going to catch this.

04:49.160 --> 04:55.260
This is for kind of a security mature organization that it would be likely to detect.

04:55.440 --> 05:04.460
And so some of the defenses I'll go over will help certain companies reach that point to where they can feel like they are going to detect these attacks.

05:05.440 --> 05:08.440
Second method is cross-account KMS encryption.

05:08.440 --> 05:13.160
It's fast-ish, depending on the size of the bucket you're targeting.

05:13.160 --> 05:18.560
It's got a high impact, and then it's unlikely to be detected based on my rating.

05:19.100 --> 05:28.480
And the last, and probably the best method, as an attacker, from my point of view, is the KMS key policy lockout method.

05:28.520 --> 05:32.060
It's instant because it's a single API call.

05:32.060 --> 05:37.640
It's got high impact, and it's very unlikely to detect because it's a single API call.

05:37.680 --> 05:46.660
You might be able to detect it after it's happened, but you're not going to be able to prevent it if you don't have the correct defenses in place.

05:48.340 --> 05:54.560
So for the first method, local encryption, obviously we're going to locate a target bucket.

05:54.860 --> 06:03.920
We're going to download each file in the bucket, and we're going to locally encrypt each of those files with something like AES-256, you know, if you're going to be basic.

06:05.320 --> 06:08.320
Upload each of those encrypted files back to the bucket.

06:08.620 --> 06:24.700
Or, in theory, you could just delete all the files from the bucket and keep your local copies, depending on the size of the bucket, because by the time you have access, you could just release it rather than encrypt it or something like that as the attacker.

06:24.700 --> 06:37.360
So there's a lot of different routes here, but for this route, essentially we're just downloading from a bucket, as you can see here, AES-256 encrypting, and then re-uploading over the top of the original file.

06:37.540 --> 06:42.220
So I wrote a one -liner command here to demonstrate the concept.

06:42.220 --> 06:48.140
It looks a little convoluted, but highlighted some of the important parts here.

06:48.420 --> 06:53.980
Essentially, in red, we're exporting an environment variable bucket equal to our target bucket.

06:54.480 --> 06:59.320
Then we're using the AWS CLI, so list objects for that bucket.

06:59.320 --> 07:02.180
We're getting a list of all the objects that are stored in there.

07:02.360 --> 07:10.560
We're piping that list into jq, which is a JSON parser, and essentially it's just grabbing the names of all those objects.

07:10.560 --> 07:13.760
We don't care about the rest right now, but the rest of their properties.

07:14.280 --> 07:17.500
We're piping all those names into xrs.

07:17.980 --> 07:30.980
We're saying each name should run this... the following command should be run for each name, and then wherever there's an open-close bracket in the following command, it should be replaced with the current object name.

07:31.100 --> 07:37.480
So essentially, we're running sh-c, here's this open quote, and at the very end is the close quote.

07:37.480 --> 07:43.560
We're running this entire thing for each name of an object in the bucket.

07:44.240 --> 07:48.700
In the red, it's going to be awss3cp, which is copy.

07:48.700 --> 07:55.760
We're copying it from our target bucket at the current key, object key, into standard in.

07:56.040 --> 08:05.000
Now we're piping the result of that into openssl, which we're using to aes256 encrypt the data, and then base64 encoding it.

08:05.180 --> 08:16.480
We're piping that data into another awss3 copy command, but this time it's from standard in into s3, or at that bucket, at that object.

08:16.480 --> 08:21.320
So we're just overriding the original object with an encrypted version of the object.

08:21.380 --> 08:32.760
So now even if the target user has s3 permissions to read those objects, they're going to get access denied because they don't have access... or well, I guess they won't get access denied.

08:32.760 --> 08:36.620
They just won't be able to read the contents because it's encrypted with your password.

08:37.420 --> 08:43.140
So essentially they would have to pay the ransom, and you give them the password, and then they can decrypt all their data.

08:45.540 --> 08:49.200
So the next method is cross-account KMS encryption.

08:52.360 --> 08:56.180
Essentially you need an attacker AWS account for this one.

08:56.180 --> 09:00.160
You create a KMS key in that attacker AWS account.

09:00.460 --> 09:09.680
You modify the key policy to allow cross-account access to your target account, but only the encrypt permission and nothing else.

09:10.180 --> 09:13.660
So not the decrypt permission, especially.

09:13.860 --> 09:29.520
Next we're going to locate a target bucket, and we're going to use the s3 copy command to copy each object from itself to itself, which also s3 batch allows you to do at a greater scale without having to automate it yourself.

09:29.520 --> 09:35.120
And we're going to be specifying the KMS encryption key as the key we just created in step one.

09:35.620 --> 09:37.980
So I wrote another one-liner for this one.

09:37.980 --> 09:42.280
Again, it's a little convoluted, but this one's a little easier to understand.

09:43.400 --> 09:45.100
Pretty much everything is the same.

09:45.100 --> 09:52.060
We're getting the list of objects, the name of those objects, passing that into xargs in this shell command.

09:52.060 --> 10:00.060
But the shell command this time is AWS s3 copy from the s3 bucket of that object to the s3 bucket of that object.

10:00.060 --> 10:02.160
So basically just on top of itself.

10:02.560 --> 10:08.280
We're passing in SSE KMS key ID, and we're giving it our malicious key ID.

10:08.720 --> 10:15.220
So it's just encrypting each object in the bucket with our key instead of whatever it's currently encrypted or not encrypted with.

10:15.920 --> 10:28.280
And lucky for us, this is done on the server side, this copy, because it's s3 to s3, so we don't need to worry about our own upload and download speed like we would with the local encryption method.

10:28.280 --> 10:37.660
So this might be a better method for when there's larger files in the bucket that you don't want to be downloading terabytes of data to your system.

10:37.660 --> 10:39.420
You probably can't even.

10:42.410 --> 10:46.050
So the third method is KMS key policy lockout.

10:46.230 --> 10:50.410
This is my favorite method and probably the scariest method.

10:51.630 --> 10:54.470
So I'll get into why shortly.

10:55.290 --> 10:58.070
In this we're going to need our own attacker account again.

10:58.070 --> 11:08.650
This time we're going to allocate an elastic IP in there, and this is because there are a lot of restrictions on cross-account actions for KMS keys.

11:08.650 --> 11:16.610
So you can't update the policy of a KMS key cross-account, you can't disable a key cross-account, and you can't delete a key cross-account.

11:17.170 --> 11:25.350
So we have to do some trickery with conditions in the KMS key policy to actually lock the owner out.

11:25.890 --> 11:30.730
And again, I say the owner because we're targeting a key that our target owns.

11:30.730 --> 11:33.570
It's not our attacker key or anything like that.

11:35.310 --> 11:48.150
So we'll locate a target bucket and our target has to have a customer master key assigned to it as the default encryption method, or at least the objects in the bucket have to be encrypted with a customer master key.

11:48.370 --> 12:00.550
It can't be the default S3 KMS key and it can't be unencrypted because we're targeting the actual key behind the encryption which requires it to be a customer master key.

12:00.550 --> 12:02.750
Otherwise we can't mess with the policy.

12:03.870 --> 12:14.410
We're going to update the key policy of that KMS key to deny access to anything about it unless it's originating from your elastic IP address.

12:14.410 --> 12:24.290
So essentially no one can use the key unless they have control of the elastic IP address which you have control of the attacker.

12:25.230 --> 12:41.150
Then you demand ransom plus you know keys to unlock so you could have them give you keys that have put key policy on the key and you could use your elastic IP to restore their key policy or you can transfer them the IP allocated.

12:41.570 --> 12:59.490
It's a little risky because you would have to unallocate it in your own account then they would have to request it to be allocated in their account which if the timing doesn't match up they might miss it and another customer might randomly get it in AWS and at that point who knows what would happen.

13:01.550 --> 13:07.850
So another one-liner, this one doesn't look very simple because it's got a whole bunch of JSON in it but it's just a single command.

13:07.930 --> 13:16.110
So AWS CLI KMS put key policy pass in the target key ID for the key we want to target obviously.

13:16.430 --> 13:26.730
The policy name is always going to be default and then we're passing in a JSON policy which I have formatted to make it a little bit easier to read .

13:28.310 --> 13:36.730
For those of you who aren't aware of how policies work or the structure of them in AWS I'll kind of go over this.

13:36.730 --> 13:41.390
So there are two statements that are declaring something about the key.

13:41.410 --> 13:47.190
The first one is deny access to this principle which is everyone.

13:47.510 --> 13:57.970
Deny anyone from doing any KMS action on any resource under the condition that they're not coming from our Elastic IP address.

13:57.990 --> 14:02.450
So essentially if you aren't coming from our IP deny access to everything.

14:03.250 --> 14:16.990
Then the next statement is saying allow access to our target account's root user to do any KMS action on any resource under the condition that they're coming from our Elastic IP address.

14:17.090 --> 14:22.390
So overall this is saying if you're not coming from our Elastic IP you're blocked from everything.

14:22.390 --> 14:28.170
If you are and you're coming from the target account then you have access to do things.

14:28.710 --> 14:49.150
So what this means is because we have access or because we own the Elastic IP it's up to us to grant access to the target account where then they can update the policy and essentially gain access to their data again because this will deny them from using the decrypt permission which they need to obviously decrypt any data.

14:50.430 --> 14:56.230
Another reason this is kind of scary is because this could go across to multiple S3 buckets.

14:56.230 --> 15:02.010
In theory the same KMS key could be applied to three or four different S3 buckets.

15:02.010 --> 15:08.010
So if you ransom the key policy you've hit all of those buckets with it with one API call.

15:08.010 --> 15:13.190
So it's suddenly a very much more valuable attack for you.

15:16.070 --> 15:18.210
So S3 defenses.

15:18.210 --> 15:20.890
We're going to talk about prevention and detection.

15:20.890 --> 15:23.270
They're both very important.

15:23.270 --> 15:28.530
In terms of prevention, easy one is just follow the principle of least privilege.

15:28.530 --> 15:38.230
This applies to KMS key policies, S3 bucket policies, and the IAM privileges you're granting to your users and roles for those specific services.

15:38.610 --> 15:40.470
Off-site backups.

15:40.470 --> 15:43.510
So of course online backups are good.

15:43.510 --> 15:46.590
Maybe cross account or something like that.

15:46.690 --> 15:55.110
But off-site is good because even if you get ransomware and you lose access to your data, you can just restore from something completely unrelated.

15:56.650 --> 15:59.630
Organization service control policies are important.

15:59.850 --> 16:01.770
They're going to be customized to your environment.

16:01.770 --> 16:15.130
So I'm not going to go over any specific examples, but they can be used to enforce specific conditions and restrict certain permissions that may prevent or at least help detect a ransomware attack.

16:17.150 --> 16:20.430
S3 object versioning with MFA delete.

16:20.430 --> 16:21.810
It's very important.

16:22.150 --> 16:31.570
So object versioning makes it so that instead of your files getting overwritten when a new one with the same name is uploaded, it creates a new version.

16:31.570 --> 16:49.610
So if the attacker tried to do a local encrypt attack and uploaded their encrypted version over the top of an existing version, both versions would still exist and the defender could just delete the latest version, which is the encrypted version, and then restore the original version and still have access to all their data.

16:50.350 --> 16:59.070
But this is why MFA delete is important because an attacker could also just delete object versions if they had the permissions to do so.

16:59.070 --> 17:03.230
So they delete the old version and the only version left is the encrypted version.

17:03.230 --> 17:11.210
But with MFA delete, it requires you to have an active MFA device to delete objects and to disable object versioning.

17:11.250 --> 17:14.650
So in both cases, the attacker is going to be locked out.

17:14.650 --> 17:25.730
In most cases, they're not going to have access to an active MFA device, even if they've already bypassed MFA in the console or something along those lines.

17:28.010 --> 17:32.170
Another good defense is a bucket policy that enforces a specific KMS key.

17:32.170 --> 17:35.410
This will prevent the cross-account KMS encryption method.

17:35.770 --> 17:38.010
Here's an example bucket policy.

17:38.010 --> 17:47.090
We're denying anybody from using S3 put object to our bucket under the condition the encryption key is not this one here.

17:47.090 --> 17:57.070
So if someone tries to upload an object to our bucket and they specify an encryption key that is not this one that we've whitelisted, it's going to get access denied.

17:57.070 --> 18:02.750
And so this will prevent the cross-account attacker key from getting applied to any of our objects.

18:04.630 --> 18:11.770
In terms of detection, there's going to be S3 access logging and CloudTrail S3 data event logging.

18:11.770 --> 18:19.570
These are both pretty similar and give you visibility into the actual actions taking place within a bucket versus on a bucket.

18:19.750 --> 18:22.550
So this is like object level activity, essentially.

18:23.130 --> 18:32.130
They have slight differences, so it's worth looking into the comparison between the two and seeing which one you want or both, maybe.

18:32.950 --> 18:36.410
Another important thing is CloudTrail management event logging.

18:36.410 --> 18:47.070
You can hopefully trace the attack path through your environment and maybe kick them out before they start ransoming your buckets or something like that.

18:47.710 --> 19:07.090
CloudTrail KMS event logging is good, too, because you can see when maybe there's a high amount of decrypts going on, you can take that as an indicator that someone is reading lots of objects or something along those lines, which could be them downloading to locally encrypt and maybe you stop them before they re-upload.

19:08.330 --> 19:10.950
GuardDuty with S3 ingestion enabled.

19:10.950 --> 19:18.250
S3 ingestion was just released last week, I believe, and it is a great feature that's been added.

19:18.250 --> 19:34.030
It'll allow you to catch things like a Tor IP address interacting with your S3 buckets, so it'll make it easier to pull out malicious activity from your buckets compared to traditional activity or normal activity.

19:35.810 --> 19:43.190
In terms of indicators for S3, STS get caller identity, kind of like my Who Am I slide.

19:43.190 --> 20:01.410
This is Who Am I of the cloud, and you don't necessarily need to alert on this call because there are a lot of legitimate use cases, like EKS pods won't use it, I believe HashCorp Vault uses it, and then sometimes developers just need to do it themselves,

20:01.410 --> 20:09.250
but attackers will often use this, too, to identify who they are before expanding into the environment.

20:09.290 --> 20:16.610
So if you can create a baseline of what's normal and then alert on what's abnormal, this would be a good one to look into.

20:17.530 --> 20:20.650
Another obvious one is S3 list all my buckets.

20:20.650 --> 20:34.750
That's going to be used legitimately all the time, but if you could somehow identify when it's being used maliciously, it's going to be a really good one because this will probably be run before any ransomware attack unless they already have a bucket name,

20:34.850 --> 20:36.850
a target, or something along those lines.

20:36.930 --> 20:48.510
Maybe you pair it up with get caller identity, so you see get caller identity and then shortly after list all my buckets, that could be somewhat of an indicator and at least worth looking into.

20:49.930 --> 20:56.310
Attempts to disable object versioning on an S3 bucket and attempts to delete object versions in a bucket.

20:57.350 --> 21:15.310
An attacker could do this if they identified a bucket that has versioning enabled, they could disable it, and then they could go in and delete all the old versions and then make it so that the latest version is their encrypted file or encrypted object so it'd be just the same as if versioning was disabled.

21:16.810 --> 21:25.610
Attempts to disable S3 access logging to remove your visibility into the HTTP requests that are going on within your bucket.

21:26.350 --> 21:28.710
KMS key policy modifications.

21:28.990 --> 21:41.310
If it's the last KMS key policy lockout method, this is going to, or alerting on these modifications, it's going to be too late, but better late than never, I would say.

21:41.390 --> 21:46.290
You want to know when this stuff happens even if you weren't able to prevent it.

21:47.570 --> 21:51.690
S3 bucket policy modifications and S3 bucket ACL modifications.

21:51.690 --> 22:08.830
You want to know when your bucket gets granted cross-account access or public access, of course, but then if you're enforcing a specific KMS key in your policy for object uploads, an attacker could identify that and delete the bucket policy so that they can use their cross-account key.

22:09.170 --> 22:18.530
So this might be somewhere, again, where service control policies come into place and can prevent that kind of activity if you know you're not going to need that to be going on.

22:20.510 --> 22:24.590
High volume of S3 object downloads and uploads.

22:24.690 --> 22:28.810
If it's above your baseline, it might be worth looking into.

22:28.810 --> 22:35.990
Maybe someone's exfiltrating all the data in your bucket or they're downloading it for local encryption or something along those lines.

22:37.330 --> 22:39.450
A typical S3 batch usage.

22:39.450 --> 22:45.110
So like I talked about before, S3 batch could be used for the cross-account KMS key method.

22:46.070 --> 22:57.890
And so if you don't use S3 batch at all and then all of a sudden you see some jobs kicked off, that could be alarming and maybe you can stop those jobs before they complete and fully take control of your data.

22:58.750 --> 23:07.690
Guard duty alerts, again, those are great to look into and just great in general in terms of identifying compromise in your environment.

23:08.870 --> 23:11.850
So with that, we're going to be diving into DynamoDB.

23:13.670 --> 23:24.690
We'll cover three techniques again, and it doesn't mean they're the only three techniques, but maybe surprisingly or not, they're the same three methods.

23:24.690 --> 23:29.370
Local encryption, cross-account KMS encryption, and key policy lockout.

23:29.370 --> 23:31.090
They're a little bit different.

23:32.070 --> 23:34.490
They're done a little bit differently though.

23:34.870 --> 23:40.810
So for local encryption, we've got located the target table.

23:40.810 --> 23:49.630
We're going to export the entire table using the scan API, which is essentially just scan the table for data and download it.

23:50.190 --> 24:07.330
But we need to be careful hitting the read capacity of the table because we may cause a denial of service in the environment if we use up the read capacity, and that could trigger some alerts that then get us kicked out of the environment before we've actually downloaded any data or much data.

24:08.450 --> 24:13.250
Then we're going to locally encrypt the downloaded data with something like AES-256 again.

24:13.330 --> 24:16.650
We're going to overwrite the table's data with the encrypted data.

24:16.650 --> 24:24.790
So you can see target table, we scan it, locally encrypt it, and then use batch write item to write it back into the table.

24:25.850 --> 24:36.030
Alternatively, we could use get item and put item to encrypt items one at a time, but that would likely be much slower and there would be many more events for your actions than otherwise.

24:37.490 --> 24:39.090
Not so simple one-liner.

24:39.090 --> 24:46.910
I didn't write a one-liner for this one because the scan API returns a maximum of one megabyte of data per call.

24:48.170 --> 24:55.070
So that means you have to paginate the results, but essentially that's hard to do on the CLI.

24:55.070 --> 25:01.350
It's done a little bit funky and so I just didn't write one for this.

25:02.090 --> 25:08.330
It would be much easier to just write a quick Python script or something along those lines if you were going to try and abuse this method.

25:10.230 --> 25:15.310
So the next method for DynoDB is the cross-account KMS encryption method.

25:15.510 --> 25:20.130
We're going to create KMS key in our own attacker account like we did before for S3.

25:20.390 --> 25:26.730
We're going to configure that key policy to grant full access to the key cross-account to our target account.

25:27.510 --> 25:38.310
It's not going to let us apply the key to that table, to our target table essentially, unless you perform this step because there are a few different permissions that are required to successfully apply the key.

25:42.790 --> 25:46.130
So then you locate your target table.

25:46.590 --> 25:53.450
You modify the table and change the KMS key that's applied to it to be the key that you just created.

25:53.710 --> 25:57.970
It takes a minute to update, so you just wait for that for it to finish updating.

25:58.090 --> 26:03.770
Then you go into your own account and modify the KMS key policy to remove that cross-account access.

26:04.210 --> 26:17.790
So now, in theory, their DynamoDB database table has your encryption key applied to it and they don't have decrypt permission for that key.

26:17.790 --> 26:23.830
So if they try to view their table or the data within it, they're going to get non-authorized, as you can see here.

26:24.390 --> 26:38.010
Additionally, if they try and change the KMS key that's applied to the table, they're going to get access denied because it requires you to be able to decrypt the data of the table to then re-encrypt it with something else.

26:38.010 --> 26:43.920
So you essentially have full control of the table until you grant them access again.

26:46.830 --> 26:53.230
So the third method, KMS key policy lockout, is essentially the exact same method as S3.

26:53.370 --> 27:10.830
And it's another reason why this technique is even more risky than we talked about before, because like I said, it could be applied to multiple S3 buckets at once, but then also, in theory, it could be applied to one or more DynamoDB tables.

27:10.830 --> 27:18.190
So a single key policy ransom attack could hit, you know, three, four, five DynamoDB tables and a bunch of S3 buckets.

27:18.390 --> 27:23.970
Not that that's good practice, they should be applied to all those, but not everyone follows best practices.

27:24.490 --> 27:28.590
And so it's something to be aware of and hopefully prevent.

27:30.850 --> 27:35.850
In terms of defenses for DynamoDB, we'll do prevention and detection again.

27:36.590 --> 27:48.130
And again, the easy one, follow the principle of least privilege for KMS, key policies, and then IAM permissions for DynamoDB and KMS applied to your users and roles.

27:49.610 --> 27:51.110
AWS backups.

27:51.110 --> 28:02.150
So you want to use the backup feature of DynamoDB to create snapshots of your data, essentially, on some time period that you've set up.

28:03.130 --> 28:14.290
Offsite backups, those are important too, because an attacker, in theory, could just delete all your backups that are in AWS and then delete the database itself, and then there's no data anymore.

28:14.290 --> 28:17.750
Offsite backups could help prevent that, because you can just restore.

28:18.730 --> 28:21.490
And again, organization service control policies.

28:21.490 --> 28:22.710
I love these.

28:22.710 --> 28:24.470
There's lots you can do with them.

28:24.470 --> 28:31.210
And if you're not familiar, I really highly suggest looking into them and applying them to your organization.

28:31.210 --> 28:33.730
But again, they're going to be very customized.

28:34.810 --> 28:36.870
Use VPC endpoints for access.

28:36.870 --> 28:43.810
So essentially require your users to be within your VPC to access your DynamoDB tables.

28:43.810 --> 28:56.030
So that means an attacker would need to compromise your network prior to ransoming a DynamoDB table, which if they can do that, you're going to have far greater problems anyways.

28:56.570 --> 29:00.710
So it's a good practice to do this.

29:00.710 --> 29:05.430
And don't just let the entire internet access your table if they're aware of it.

29:07.110 --> 29:08.510
Point-in-time recovery.

29:08.510 --> 29:14.710
This is one I did have on here as a prevention, but as I did further testing, I found out it didn't actually work.

29:14.710 --> 29:19.370
So point-in-time recovery keeps snapshots over time in your database.

29:19.490 --> 29:25.030
And essentially, it allows you to go back to a specific time in the past.

29:25.030 --> 29:42.790
But what I found is if you enable it, and then you wait a little while, maybe mess with the data, then you apply a ransom KMS key to it, then you use point-in-time recovery to recover before that key was applied, it still doesn't work.

29:43.290 --> 29:52.490
It seems to be successful, and it starts creating the restored database, but then it just disappears from the console, and there's no trace of it.

29:52.490 --> 30:01.010
So my guess is that it just can't get to the data because it encrypted it all with the new key instead of the key that was present at the time.

30:02.330 --> 30:07.250
For detection, Cloud Trail Management event logging, again, very useful.

30:07.250 --> 30:09.610
KMS event logging, very useful.

30:09.630 --> 30:11.790
Guard duty, always very useful.

30:12.430 --> 30:24.210
CloudWatch alarms, you can use these to monitor the read and write capacity of your tables, so you know if there's a huge amount of reads or a huge amount of writes to your tables and could alert off of that.

30:24.550 --> 30:34.490
DynamoDB streams, scan, get item, and put item, and I think some others are not, or they're considered data events, so they're not logged by Cloud Trail.

30:35.290 --> 30:47.230
So you can use DynamoDB streams to stream those data events to a Lambda function and respond to them however you want, so that can be a way to monitor that data level activity.

30:48.190 --> 30:55.310
And maybe you can use AWS config to track changes to your tables, but usually this will be too late by the time it alerts you of anything.

30:57.190 --> 31:14.630
Indicators to look out for, again, STS get caller identity, KMS key policy modifications, high volume of table reads and writes, attempts to delete backups, guard duty alerts, attempts to increase the table's read capacity.

31:14.630 --> 31:27.190
If they find a large table that has a low read capacity, they might increase the read capacity so that they can run parallel queries and download the entire database quickly without causing a service in the environment.

31:28.910 --> 31:31.130
And that's kind of it for DynamoDB.

31:31.130 --> 31:34.390
I'm running out of time, so I'm trying to speed through a couple of these.

31:34.570 --> 31:53.530
Other potential targets, so there could be Elastic Walkstore and AWS, you can encrypt volumes or snapshots, relational database service, or RDS database and snapshots, Lambda function code and environment variables, secrets manager secrets, SNS topics,

31:53.530 --> 32:04.010
SQS queues, ECR repositories and images, which just got released last week, I believe, EFS file systems, and more.

32:04.010 --> 32:12.150
And then you can even do it for other cloud providers, but like I said earlier, we didn't dive into that, but something like Google Storage could be done the same way as S3.

32:13.310 --> 32:16.470
So cloud provider intervention and other takeaways.

32:16.470 --> 32:22.570
We don't know what a cloud provider could do to help you if you got targeted, so you can't rely on them for that.

32:22.570 --> 32:26.590
So you need to act as if they would not be able to help you under any condition.

32:26.730 --> 32:31.350
They can't help you with the local encryption anyways, because they're not going to know the password to your encrypted data.

32:32.010 --> 32:34.610
This means you need to evaluate your own defenses.

32:34.670 --> 32:38.810
You need to take care of your environment, monitor it, respond to things.

32:38.970 --> 32:42.470
You can't rely on the unknown, essentially.

32:42.630 --> 32:44.610
Can you keep attackers out of your environment?

32:44.610 --> 32:48.710
Can you prevent attackers from doing things once they're in your environment?

32:48.950 --> 32:53.230
Can you detect when they're doing things once they're in your environment?

32:53.290 --> 32:56.170
Can you match those detections to patterns?

32:56.610 --> 33:03.150
Can you tell that maybe a ransomware attack's coming because of these few API calls made in a row or something along those lines?

33:04.170 --> 33:08.650
And additionally, you need to ask, can I get back online after an attack?

33:08.670 --> 33:09.430
Am I ready?

33:09.430 --> 33:12.230
Do I know what to do if I got hit with a ransomware attack?

33:12.230 --> 33:14.650
If the answer is no, then you've got some work to do.

33:15.610 --> 33:16.770
And then how fast?

33:16.770 --> 33:20.330
Is it going to be fast enough before there's a major business impact?

33:20.510 --> 33:22.430
How much money are you going to lose in the meantime?

33:22.430 --> 33:24.550
It's a big, big question.

33:25.070 --> 33:30.290
And finally, the last big takeaway is, what if the attacker never decrypts your data?

33:30.950 --> 33:33.430
For some reason, what if you just can't get access?

33:33.430 --> 33:34.690
I mean, they are criminals.

33:34.690 --> 33:36.270
You can't necessarily trust them.

33:36.270 --> 33:39.850
Just because you pay them doesn't mean they're going to decrypt your data.

33:40.570 --> 33:42.730
So could you handle that?

33:42.730 --> 33:43.890
Are you going to go out of business?

33:44.870 --> 33:45.950
What's going to happen?

33:45.950 --> 33:48.150
That's something you need to think about.

33:49.050 --> 33:50.730
That kind of wraps things up.

33:50.730 --> 33:54.490
I have a slide here just of some additional resources and references.

33:55.790 --> 33:58.850
First one I always want to talk about is AWS documentation.

33:58.930 --> 34:00.610
I read that like it's the Bible.

34:01.750 --> 34:09.530
There are so many great things in there, and it's an easy way to learn in-depth about features of AWS that you might not know otherwise.

34:09.530 --> 34:11.770
So I'm constantly reading that.

34:11.830 --> 34:17.570
And then I wrote two blog posts on S3 ransomware in particular, while I ran a security labs.

34:17.570 --> 34:19.150
You can check those out.

34:20.010 --> 34:29.710
I want to give a special thanks to my team at CrowdStrike, just for helping with the presentation and the research, and giving me some feedback on that.

34:29.710 --> 34:37.730
Houston Hopkins from Capital One for some help with the one-liner commands and some cool tricks with the AWS CLI.

34:38.190 --> 34:44.430
And Rhino Security Labs for that previous research into ransomware and just AWS security in general.

34:45.370 --> 34:55.930
In the bottom right, you can see my Twitter handle there for if there's not sure how much time left we have for questions, but if there are any that don't get answered, feel free to reach out to me on there.

34:56.070 --> 35:02.110
But for that, I'll go ahead and just kind of open up and answer any questions that might be in the chat.

35:02.130 --> 35:09.690
Is object versioning and MFA delete good enough, or were you saying that you need to implement and do all five of those things?

35:10.710 --> 35:29.250
I think that object versioning and MFA delete are good for a couple of methods, but if you think of it like a local encryption method, if you downloaded the objects from the bucket, their threat could be we're going to release all this data.

35:29.650 --> 35:33.770
And so then versioning and MFA delete wouldn't do it.

35:34.150 --> 35:39.630
I like to always just follow defense in depth and implement as much as you can.

35:39.990 --> 35:47.610
Then it's hard to take into account the cost though, and then the work and changes that applies to your environment.

35:47.610 --> 35:53.970
But there's some of the best defenses, but it definitely won't protect you from everything essentially.

35:54.570 --> 35:55.610
Got it.

35:55.730 --> 36:02.170
And the second question from Skybound, I think you touched on this a little bit towards the end.

36:02.170 --> 36:11.290
For recovery in cases where decryption keys are within AWS, would AWS be able to help with their recovery and deal with the attacker?

36:11.290 --> 36:21.250
For example, with the KMS policy, basically expecting AWS to adjust the KMS policy so that the customer can get access back.

36:21.890 --> 36:24.290
So that's kind of where I was touching on.

36:24.290 --> 36:26.310
We don't know for sure.

36:27.550 --> 36:36.450
And then it brings up the question of how fast, you know, maybe it takes a support case and then a day or two goes by or something like that.

36:36.450 --> 36:38.970
And it's already, there's already a huge impact.

36:39.710 --> 36:56.310
I would say until there's an official statement or something along those lines, not that there needs to be one necessarily, but implementing your own defenses and detections is the way to go instead of relying on them to take care of you in the event that something goes wrong.

