[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:12.020] So, I'm a huge cloud nerd, so instead of the traditional Who Am I slide, I did an AWS [00:12.020 --> 00:21.980] STS Git Caller Identity slide, which basically says what Jaren just shared. My name is Spencer [00:21.980 --> 00:26.800] Geetson. I'm a cloud security researcher at CrowdStrike. I previously was a penetration [00:26.800 --> 00:33.120] tester at Rhino Security Labs, and I've got an interest in technical writing, gaming, [00:33.120 --> 00:41.320] and programming. So first I want to start off with an agenda. We'll talk about AWS basics, [00:41.320 --> 00:47.540] just kind of a TLDR of the services and resources I'm going to go over. Ransomware in the cloud, [00:47.540 --> 00:52.620] simple storage service for AWS S3, we're going to talk about ransomware techniques, [00:52.620 --> 00:58.900] prevention, detection, and indicators. And then the same thing for DynamoDB techniques, [00:58.900 --> 01:04.380] prevention, detection, and indicators. And then at the end, we're going to talk about [01:04.380 --> 01:10.160] other potential targets, so other AWS services, other clouds, those kind of things, cloud provider [01:10.160 --> 01:15.640] intervention, and other takeaways from the presentation, and then just some additional [01:15.640 --> 01:25.780] resources and references at the end. So AWS basics. I imagine there's a wide range of skill [01:25.780 --> 01:33.200] set in the audience, so you may know this, you may not. AWS S3 is just object storage in the [01:33.200 --> 01:40.200] cloud. It's their offering. There's S3 buckets, which basically hold all your buckets of objects. [01:40.200 --> 01:46.560] Objects are essentially files that are stored in buckets, and then there are bucket policies [01:46.560 --> 01:53.840] which determine the access permissions and conditions that apply to a bucket and the [01:53.840 --> 02:01.620] objects within it. And we'll get more into that later on. DynamoDB, this one's pretty simple for [02:01.620 --> 02:09.040] our needs. It has tables. It's a NoSQL database offered by Amazon, and it has tables that hold [02:09.040 --> 02:14.500] data. That's as much as you really need to know if you're not familiar with the service right now, [02:14.500 --> 02:21.720] at least. Then there's KMS, Key Management Service. It has keys, which could be asymmetric [02:21.720 --> 02:28.860] or symmetric keys, depending on your use case, and they're typically AWS managed. [02:29.320 --> 02:34.940] They have key policies, which define who can use keys and what they can be used for, [02:34.940 --> 02:40.720] etc. And that's kind of the rundown of the different resources and services that I'll be [02:40.720 --> 02:48.140] talking about today. Ransomware in the cloud. I'm going to be comparing the state of ransomware [02:48.140 --> 02:55.840] today to soon, essentially. Right now, there's traditional ransomware like Locky, [02:56.680 --> 03:03.720] WastedLocker, things like those that target traditional infrastructure. [03:04.260 --> 03:11.780] Cloud-native ransomware is on the way. There's none yet, or none publicly. We don't know what's [03:11.780 --> 03:17.300] going on behind the scenes or in breaches that haven't been made public. But it's better to [03:17.300 --> 03:25.220] get ahead of these things before it becomes a problem. It's better to be ready for them. [03:25.840 --> 03:30.580] So traditional ransomware typically targets servers and workstations, [03:30.580 --> 03:35.140] while cloud ransomware would be targeting cloud-native resources. [03:36.340 --> 03:40.780] Traditionally, they're operating system dependent. Primarily, windows and active [03:40.780 --> 03:45.320] directory environments are being targeted. Where in the cloud, it's going to be cloud [03:45.320 --> 03:50.400] provider independent. We're focusing on AWS for this presentation, but all the concepts [03:50.400 --> 03:58.260] can be applied to other cloud providers like Google Cloud and Microsoft Azure and others. [03:58.800 --> 04:03.980] And then traditionally, they exploit zero-day or known vulnerabilities to spread and infect [04:03.980 --> 04:08.820] their targets. Where in the cloud, it's none of that. It's just feature abuse. There's no [04:08.820 --> 04:15.440] vulnerability abuse. It's just using features the way they were designed, essentially, [04:15.440 --> 04:22.840] in a little bit of a malicious way. So with that, we'll dive into S3. There's three techniques [04:22.840 --> 04:26.560] I'm going to cover. It doesn't mean they're the only three techniques, but these are three [04:26.560 --> 04:32.980] notable ones, at least. Local encryption is the first technique. It's very slow compared to the [04:32.980 --> 04:40.100] others, but it's got a critical impact. The detection likelihood, I rate it as likely. [04:40.100 --> 04:46.100] But this is only if you have monitoring in your environment. If you aren't monitoring [04:46.660 --> 04:51.000] what's going on in your environment, you're not going to catch this. This is for kind of a security [04:51.000 --> 04:57.320] mature organization that it would be likely to detect. And so some of the defenses I'll go over [04:57.320 --> 05:03.320] will help certain companies reach that point to where they can feel like they are going to detect [05:03.320 --> 05:10.380] these attacks. Second method is cross-account KMS encryption. It's fast-ish, depending on the [05:10.380 --> 05:16.220] size of the bucket you're targeting. It's got a high impact, and then it's unlikely to be detected [05:17.000 --> 05:25.720] based on my rating. And the last, and probably the best method, as an attacker, from my point of [05:25.720 --> 05:32.060] view, is the KMS key policy lockout method. It's instant because it's a single API call. [05:32.060 --> 05:38.080] It's got high impact, and it's very unlikely to detect because it's a single API call. You might [05:38.080 --> 05:41.780] be able to detect it after it's happened, but you're not going to be able to prevent it if you [05:41.780 --> 05:51.000] don't have the correct defenses in place. So for the first method, local encryption, [05:52.060 --> 05:57.240] obviously we're going to locate a target bucket. We're going to download each file in the bucket, [05:57.240 --> 06:02.420] and we're going to locally encrypt each of those files with something like AES-256, [06:02.420 --> 06:08.320] you know, if you're going to be basic. Upload each of those encrypted files back to the bucket. [06:08.620 --> 06:13.680] Or, in theory, you could just delete all the files from the bucket and keep your local copies, [06:13.680 --> 06:21.540] depending on the size of the bucket, because by the time you have access, you could just release [06:21.540 --> 06:25.580] it rather than encrypt it or something like that as the attacker. So there's a lot of different [06:25.580 --> 06:31.720] routes here, but for this route, essentially we're just downloading from a bucket, as you can see [06:31.720 --> 06:38.700] here, AES-256 encrypting, and then re-uploading over the top of the original file. So I wrote a [06:38.700 --> 06:46.480] one-liner command here to demonstrate the concept. It looks a little convoluted, but highlighted some [06:46.480 --> 06:52.080] of the important parts here. Essentially, in red, we're exporting an environment variable bucket [06:52.080 --> 06:59.380] equal to our target bucket. Then we're using the AWS CLI, so list objects for that bucket. We're [06:59.380 --> 07:05.320] getting a list of all the objects that are stored in there. We're piping that list into jq, which is [07:05.460 --> 07:11.120] a JSON parser, and essentially it's just grabbing the names of all those objects. We don't care [07:11.120 --> 07:16.520] about the rest right now, but the rest of their properties. We're piping all those names into [07:16.520 --> 07:24.120] xrs. We're saying each name should run this... the following command should be run for each name, [07:24.120 --> 07:29.040] and then wherever there's an open-close bracket in the following command, it should be replaced [07:29.040 --> 07:35.560] with the current object name. So essentially, we're running sh-c, here's this open quote, and [07:35.560 --> 07:42.640] at the very end is the close quote. We're running this entire thing for each name of an object in [07:42.640 --> 07:50.800] the bucket. In the red, it's going to be awss3cp, which is copy. We're copying it from our target [07:50.800 --> 07:58.920] bucket at the current key, object key, into standard in. Now we're piping the result of that into openssl, [07:58.920 --> 08:06.640] which we're using to aes256 encrypt the data, and then base64 encoding it. We're piping that data [08:06.640 --> 08:15.560] into another awss3 copy command, but this time it's from standard in into s3, or at that bucket, [08:15.560 --> 08:20.400] at that object. So we're just overriding the original object with an encrypted version of the [08:20.400 --> 08:27.760] object. So now even if the target user has s3 permissions to read those objects, they're going [08:27.760 --> 08:32.300] to get access denied because they don't have access... or well, I guess they won't get access [08:32.300 --> 08:36.620] denied. They just won't be able to read the contents because it's encrypted with your password. [08:37.420 --> 08:41.500] So essentially they would have to pay the ransom, and you give them the password, [08:41.500 --> 08:43.140] 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:58.540] Essentially you need an attacker AWS account for this one. You create a KMS key in that attacker [08:58.540 --> 09:06.140] AWS account. You modify the key policy to allow cross-account access to your target account, [09:06.640 --> 09:13.660] but only the encrypt permission and nothing else. So not the decrypt permission, especially. [09:13.860 --> 09:19.640] Next we're going to locate a target bucket, and we're going to use the s3 copy command to copy [09:19.640 --> 09:26.480] each object from itself to itself, which also s3 batch allows you to do at a greater scale [09:27.400 --> 09:32.640] without having to automate it yourself. And we're going to be specifying the KMS encryption key as [09:32.640 --> 09:38.240] the key we just created in step one. So I wrote another one-liner for this one. Again, [09:38.240 --> 09:42.280] it's a little convoluted, but this one's a little easier to understand. [09:43.400 --> 09:48.600] Pretty much everything is the same. We're getting the list of objects, the name of those objects, [09:48.600 --> 09:54.960] passing that into xargs in this shell command. But the shell command this time is AWS s3 copy [09:55.660 --> 10:01.320] from the s3 bucket of that object to the s3 bucket of that object. So basically just on top [10:01.320 --> 10:09.020] of itself. We're passing in SSE KMS key ID, and we're giving it our malicious key ID. So it's [10:09.020 --> 10:13.520] just encrypting each object in the bucket with our key instead of whatever it's currently encrypted [10:13.520 --> 10:20.220] or not encrypted with. And lucky for us, this is done on the server side, this copy, because it's [10:20.220 --> 10:26.040] s3 to s3, so we don't need to worry about our own upload and download speed like we would with the [10:26.770 --> 10:31.940] local encryption method. So this might be a better method for when there's larger files [10:32.470 --> 10:36.840] in the bucket that you don't want to be downloading terabytes of data to your [10:36.840 --> 10:46.050] system. You probably can't even. So the third method is KMS key policy lockout. [10:46.230 --> 10:54.470] This is my favorite method and probably the scariest method. So I'll get into why shortly. [10:55.290 --> 10:59.330] In this we're going to need our own attacker account again. This time we're going to allocate [10:59.330 --> 11:07.270] an elastic IP in there, and this is because there are a lot of restrictions on cross-account actions [11:07.270 --> 11:13.470] for KMS keys. So you can't update the policy of a KMS key cross-account, you can't disable a key [11:13.470 --> 11:20.490] cross-account, and you can't delete a key cross-account. So we have to do some trickery with [11:20.490 --> 11:27.450] conditions in the KMS key policy to actually lock the owner out. And again, I say the owner [11:27.450 --> 11:33.570] because we're targeting a key that our target owns. It's not our attacker key or anything like that. [11:35.310 --> 11:41.610] So we'll locate a target bucket and our target has to have a customer master key assigned to it [11:41.610 --> 11:46.290] as the default encryption method, or at least the objects in the bucket have to be encrypted [11:46.290 --> 11:53.470] with a customer master key. It can't be the default S3 KMS key and it can't be unencrypted [11:53.470 --> 11:59.570] because we're targeting the actual key behind the encryption which requires it to be a customer [11:59.570 --> 12:05.870] master key. Otherwise we can't mess with the policy. We're going to update the key policy [12:05.870 --> 12:13.590] of that KMS key to deny access to anything about it unless it's originating from your elastic IP [12:13.590 --> 12:21.910] address. So essentially no one can use the key unless they have control of the elastic IP address [12:21.910 --> 12:29.930] which you have control of the attacker. Then you demand ransom plus you know keys to unlock so you [12:29.930 --> 12:35.250] could have them give you keys that have put key policy on the key and you could use your elastic [12:35.250 --> 12:43.070] IP to restore their key policy or you can transfer them the IP allocated. It's a little risky because [12:43.070 --> 12:47.150] you would have to unallocate it in your own account then they would have to request it to be [12:47.150 --> 12:51.790] allocated in their account which if the timing doesn't match up they might miss it and another [12:51.790 --> 12:59.490] customer might randomly get it in AWS and at that point who knows what would happen. [13:01.550 --> 13:05.530] So another one-liner, this one doesn't look very simple because it's got a whole bunch of JSON in [13:05.530 --> 13:13.870] it but it's just a single command. So AWS CLI KMS put key policy pass in the target key ID for [13:13.870 --> 13:19.490] the key we want to target obviously. The policy name is always going to be default [13:20.690 --> 13:26.210] and then we're passing in a JSON policy which I have formatted to make it a little bit easier to [13:26.210 --> 13:34.630] read. For those of you who aren't aware of how policies work or the structure of them in AWS [13:34.630 --> 13:40.350] I'll kind of go over this. So there are two statements that are declaring something about [13:40.350 --> 13:48.830] the key. The first one is deny access to this principle which is everyone. Deny anyone from [13:48.830 --> 13:55.850] doing any KMS action on any resource under the condition that they're not coming from [13:55.850 --> 14:02.450] our Elastic IP address. So essentially if you aren't coming from our IP deny access to everything. [14:03.250 --> 14:09.770] Then the next statement is saying allow access to our target account's root user [14:10.340 --> 14:15.950] to do any KMS action on any resource under the condition that they're coming from our Elastic IP [14:15.950 --> 14:21.590] address. So overall this is saying if you're not coming from our Elastic IP you're blocked from [14:21.590 --> 14:28.170] everything. If you are and you're coming from the target account then you have access to do things. [14:28.710 --> 14:34.430] So what this means is because we have access or because we own the Elastic IP it's up to us to [14:34.430 --> 14:40.850] grant access to the target account where then they can update the policy and essentially gain access [14:40.850 --> 14:46.910] to their data again because this will deny them from using the decrypt permission which they need [14:46.910 --> 14:53.030] to obviously decrypt any data. Another reason this is kind of scary is because this could [14:53.030 --> 15:00.310] go across to multiple S3 buckets. In theory the same KMS key could be applied to three or four [15:00.310 --> 15:06.330] different S3 buckets. So if you ransom the key policy you've hit all of those buckets with it [15:06.330 --> 15:18.210] with one API call. So it's suddenly a very much more valuable attack for you. So S3 defenses. [15:18.210 --> 15:24.070] We're going to talk about prevention and detection. They're both very important. In terms of [15:24.070 --> 15:30.010] prevention, easy one is just follow the principle of least privilege. This applies to KMS key [15:30.010 --> 15:35.730] policies, S3 bucket policies, and the IAM privileges you're granting to your users and [15:35.730 --> 15:43.510] roles for those specific services. Off-site backups. So of course online backups are good. [15:43.510 --> 15:49.450] Maybe cross account or something like that. But off-site is good because even if you get [15:49.450 --> 15:54.190] ransomware and you lose access to your data, you can just restore from something completely [15:54.190 --> 16:00.570] unrelated. Organization service control policies are important. They're going to be customized [16:00.570 --> 16:04.730] to your environment. So I'm not going to go over any specific examples, but they can be used to [16:04.730 --> 16:12.510] enforce specific conditions and restrict certain permissions that may prevent or at least help [16:12.510 --> 16:22.530] detect a ransomware attack. S3 object versioning with MFA delete. It's very important. So object [16:22.530 --> 16:28.210] versioning makes it so that instead of your files getting overwritten when a new one with the same [16:28.210 --> 16:34.550] name is uploaded, it creates a new version. So if the attacker tried to do a local encrypt attack [16:34.550 --> 16:40.630] and uploaded their encrypted version over the top of an existing version, both versions would still [16:40.630 --> 16:44.890] exist and the defender could just delete the latest version, which is the encrypted version, [16:45.250 --> 16:49.610] and then restore the original version and still have access to all their data. [16:50.350 --> 16:56.970] But this is why MFA delete is important because an attacker could also just delete object versions [16:56.970 --> 17:01.730] if they had the permissions to do so. So they delete the old version and the only version left [17:01.730 --> 17:07.950] is the encrypted version. But with MFA delete, it requires you to have an active MFA device to [17:07.950 --> 17:13.510] delete objects and to disable object versioning. So in both cases, the attacker is going to be [17:13.510 --> 17:20.590] locked out. In most cases, they're not going to have access to an active MFA device, [17:20.590 --> 17:25.730] even if they've already bypassed MFA in the console or something along those lines. [17:28.010 --> 17:32.690] Another good defense is a bucket policy that enforces a specific KMS key. This will prevent [17:32.690 --> 17:39.230] the cross-account KMS encryption method. Here's an example bucket policy. We're denying anybody [17:39.810 --> 17:47.090] from using S3 put object to our bucket under the condition the encryption key is not this one here. [17:47.090 --> 17:53.470] So if someone tries to upload an object to our bucket and they specify an encryption key that is [17:53.470 --> 17:58.650] not this one that we've whitelisted, it's going to get access denied. And so this will prevent the [17:58.650 --> 18:02.750] 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:16.610] These are both pretty similar and give you visibility into the actual actions taking [18:16.610 --> 18:22.550] place within a bucket versus on a bucket. So this is like object level activity, essentially. [18:23.130 --> 18:28.010] They have slight differences, so it's worth looking into the comparison between the two [18:28.010 --> 18:35.250] and seeing which one you want or both, maybe. Another important thing is CloudTrail management [18:35.250 --> 18:41.610] event logging. You can hopefully trace the attack path through your environment and maybe [18:42.470 --> 18:47.070] kick them out before they start ransoming your buckets or something like that. [18:47.710 --> 18:52.490] CloudTrail KMS event logging is good, too, because you can see when maybe there's a high amount of [18:52.490 --> 18:58.430] decrypts going on, you can take that as an indicator that someone is reading lots of objects [18:58.430 --> 19:04.470] or something along those lines, which could be them downloading to locally encrypt and maybe [19:04.470 --> 19:12.230] you stop them before they re-upload. GuardDuty with S3 ingestion enabled. S3 ingestion was just [19:12.230 --> 19:19.150] released last week, I believe, and it is a great feature that's been added. It'll allow you to [19:19.150 --> 19:25.570] catch things like a Tor IP address interacting with your S3 buckets, so it'll make it easier to [19:27.130 --> 19:34.030] pull out malicious activity from your buckets compared to traditional activity or normal activity. [19:35.810 --> 19:43.430] In terms of indicators for S3, STS get caller identity, kind of like my Who Am I slide. This is [19:43.430 --> 19:51.350] Who Am I of the cloud, and you don't necessarily need to alert on this call because there are a lot [19:51.350 --> 19:58.330] of legitimate use cases, like EKS pods won't use it, I believe HashCorp Vault uses it, and then [19:58.330 --> 20:05.650] sometimes developers just need to do it themselves, but attackers will often use this, too, to identify [20:05.650 --> 20:12.250] who they are before expanding into the environment. So if you can create a baseline of what's normal [20:12.250 --> 20:19.310] and then alert on what's abnormal, this would be a good one to look into. Another obvious one is S3 [20:19.310 --> 20:24.570] list all my buckets. That's going to be used legitimately all the time, but if you could somehow [20:24.570 --> 20:28.510] identify when it's being used maliciously, it's going to be a really good one because [20:29.510 --> 20:34.750] this will probably be run before any ransomware attack unless they already have a bucket name, [20:34.850 --> 20:39.350] a target, or something along those lines. Maybe you pair it up with get caller identity, [20:39.350 --> 20:44.670] so you see get caller identity and then shortly after list all my buckets, that could [20:44.670 --> 20:51.870] be somewhat of an indicator and at least worth looking into. Attempts to disable object versioning [20:51.870 --> 20:58.510] on an S3 bucket and attempts to delete object versions in a bucket. An attacker could do this [20:58.510 --> 21:03.610] if they identified a bucket that has versioning enabled, they could disable it, and then they [21:03.610 --> 21:08.450] could go in and delete all the old versions and then make it so that the latest version [21:08.450 --> 21:15.310] is their encrypted file or encrypted object so it'd be just the same as if versioning was disabled. [21:16.810 --> 21:23.170] Attempts to disable S3 access logging to remove your visibility into the HTTP requests [21:23.170 --> 21:30.250] that are going on within your bucket. KMS key policy modifications. If it's the last [21:30.250 --> 21:36.390] KMS key policy lockout method, this is going to, or alerting on these modifications, [21:36.390 --> 21:42.450] it's going to be too late, but better late than never, I would say. You want to know [21:42.450 --> 21:49.190] when this stuff happens even if you weren't able to prevent it. S3 bucket policy modifications [21:49.190 --> 21:55.550] and S3 bucket ACL modifications. You want to know when your bucket gets granted cross-account access [21:55.550 --> 22:01.530] or public access, of course, but then if you're enforcing a specific KMS key in your policy [22:01.530 --> 22:06.970] for object uploads, an attacker could identify that and delete the bucket policy so that they [22:06.970 --> 22:11.990] can use their cross-account key. So this might be somewhere, again, where service control policies [22:11.990 --> 22:17.170] come into place and can prevent that kind of activity if you know you're not going to need [22:17.170 --> 22:27.450] that to be going on. High volume of S3 object downloads and uploads. If it's above your baseline, [22:27.450 --> 22:31.990] it might be worth looking into. Maybe someone's exfiltrating all the data in your bucket or [22:31.990 --> 22:38.750] they're downloading it for local encryption or something along those lines. A typical S3 batch [22:38.750 --> 22:45.110] usage. So like I talked about before, S3 batch could be used for the cross-account KMS key method. [22:46.070 --> 22:51.090] And so if you don't use S3 batch at all and then all of a sudden you see some jobs kicked off, [22:51.090 --> 22:55.670] that could be alarming and maybe you can stop those jobs before they complete and fully [22:56.190 --> 23:03.270] take control of your data. Guard duty alerts, again, those are great to look into and just [23:03.870 --> 23:07.690] great in general in terms of identifying compromise in your environment. [23:08.870 --> 23:16.370] So with that, we're going to be diving into DynamoDB. We'll cover three techniques again, [23:16.370 --> 23:22.570] and it doesn't mean they're the only three techniques, but maybe surprisingly or not, [23:22.570 --> 23:28.290] they're the same three methods. Local encryption, cross-account KMS encryption, and key policy [23:28.290 --> 23:34.490] lockout. They're a little bit different. They're done a little bit differently though. [23:34.870 --> 23:41.950] So for local encryption, we've got located the target table. We're going to export the entire [23:41.950 --> 23:49.630] table using the scan API, which is essentially just scan the table for data and download it. [23:50.190 --> 23:54.770] But we need to be careful hitting the read capacity of the table because we may cause [23:54.890 --> 24:00.410] a denial of service in the environment if we use up the read capacity, and that could trigger some [24:00.410 --> 24:05.550] alerts that then get us kicked out of the environment before we've actually downloaded [24:05.550 --> 24:11.310] any data or much data. Then we're going to locally encrypt the downloaded data with something like [24:11.310 --> 24:17.470] AES-256 again. We're going to overwrite the table's data with the encrypted data. So you can see [24:18.070 --> 24:23.910] target table, we scan it, locally encrypt it, and then use batch write item to write it back into [24:23.910 --> 24:30.010] the table. Alternatively, we could use get item and put item to encrypt items one at a time, [24:30.010 --> 24:34.990] but that would likely be much slower and there would be many more events for your actions than [24:34.990 --> 24:43.330] otherwise. Not so simple one-liner. I didn't write a one-liner for this one because the scan API [24:43.330 --> 24:50.750] returns a maximum of one megabyte of data per call. So that means you have to paginate the results, [24:50.750 --> 24:58.350] but essentially that's hard to do on the CLI. It's done a little bit funky and so [24:59.070 --> 25:04.750] I just didn't write one for this. It would be much easier to just write a quick Python [25:04.750 --> 25:08.330] script or something along those lines if you were going to try and abuse this method. [25:10.230 --> 25:16.890] So the next method for DynoDB is the cross-account KMS encryption method. We're going to create KMS [25:16.890 --> 25:22.210] key in our own attacker account like we did before for S3. We're going to configure that key policy [25:22.210 --> 25:29.030] to grant full access to the key cross-account to our target account. It's not going to let us apply [25:29.030 --> 25:33.890] the key to that table, to our target table essentially, unless you perform this step [25:33.890 --> 25:38.310] because there are a few different permissions that are required to successfully apply the key. [25:42.790 --> 25:50.250] So then you locate your target table. You modify the table and change the KMS key that's applied [25:50.250 --> 25:55.750] to it to be the key that you just created. It takes a minute to update, so you just wait for [25:55.750 --> 26:01.350] that for it to finish updating. Then you go into your own account and modify the KMS key policy [26:01.350 --> 26:10.690] to remove that cross-account access. So now, in theory, their DynamoDB database table has [26:10.690 --> 26:18.270] your encryption key applied to it and they don't have decrypt permission for that key. So if they [26:18.270 --> 26:22.810] try to view their table or the data within it, they're going to get non-authorized, as you can [26:22.810 --> 26:30.770] see here. Additionally, if they try and change the KMS key that's applied to the table, they're [26:30.770 --> 26:35.990] going to get access denied because it requires you to be able to decrypt the data of the table to [26:35.990 --> 26:40.570] then re-encrypt it with something else. So you essentially have full control of the table until [26:42.150 --> 26:43.920] 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 --> 26:59.690] And it's another reason why this technique is even more risky than we talked about before, [26:59.690 --> 27:06.290] because like I said, it could be applied to multiple S3 buckets at once, but then also, [27:06.290 --> 27:12.510] in theory, it could be applied to one or more DynamoDB tables. So a single key policy ransom [27:12.510 --> 27:18.190] attack could hit, you know, three, four, five DynamoDB tables and a bunch of S3 buckets. [27:18.390 --> 27:21.330] Not that that's good practice, they should be applied to all those, but [27:21.930 --> 27:28.590] not everyone follows best practices. 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:42.930] And again, the easy one, follow the principle of least privilege for KMS, key policies, and then [27:42.930 --> 27:48.130] IAM permissions for DynamoDB and KMS applied to your users and roles. [27:49.610 --> 27:56.550] AWS backups. So you want to use the backup feature of DynamoDB to create snapshots of your [27:56.550 --> 28:05.170] data, essentially, on some time period that you've set up. Offsite backups, those are important [28:05.170 --> 28:10.770] too, because an attacker, in theory, could just delete all your backups that are in AWS and then [28:10.770 --> 28:15.730] delete the database itself, and then there's no data anymore. Offsite backups could help prevent [28:15.730 --> 28:22.270] that, because you can just restore. And again, organization service control policies. I love [28:22.270 --> 28:26.950] these. There's lots you can do with them. And if you're not familiar, I really highly suggest [28:27.470 --> 28:32.490] looking into them and applying them to your organization. But again, they're going to be [28:32.490 --> 28:40.410] very customized. Use VPC endpoints for access. So essentially require your users to be within [28:40.410 --> 28:47.910] your VPC to access your DynamoDB tables. So that means an attacker would need to compromise your [28:47.910 --> 28:54.150] network prior to ransoming a DynamoDB table, which if they can do that, you're going to have [28:54.150 --> 29:02.070] far greater problems anyways. So it's a good practice to do this. And don't just let the [29:02.070 --> 29:09.590] entire internet access your table if they're aware of it. Point-in-time recovery. This is one I did [29:09.590 --> 29:14.710] have on here as a prevention, but as I did further testing, I found out it didn't actually work. [29:14.710 --> 29:22.130] So point-in-time recovery keeps snapshots over time in your database. And essentially, [29:22.130 --> 29:28.070] it allows you to go back to a specific time in the past. But what I found is if you enable it, [29:28.070 --> 29:35.230] and then you wait a little while, maybe mess with the data, then you apply a ransom KMS key to it, [29:36.510 --> 29:41.950] then you use point-in-time recovery to recover before that key was applied, it still doesn't [29:41.950 --> 29:48.350] work. It seems to be successful, and it starts creating the restored database, but then it just [29:48.350 --> 29:54.670] disappears from the console, and there's no trace of it. So my guess is that it just can't get to [29:54.670 --> 30:00.150] the data because it encrypted it all with the new key instead of the key that was present at the [30:00.150 --> 30:07.890] time. For detection, Cloud Trail Management event logging, again, very useful. KMS event [30:07.890 --> 30:14.370] logging, very useful. Guard duty, always very useful. CloudWatch alarms, you can use these to [30:14.370 --> 30:19.550] monitor the read and write capacity of your tables, so you know if there's a huge amount of reads or [30:19.670 --> 30:27.310] a huge amount of writes to your tables and could alert off of that. DynamoDB streams, scan, get [30:27.310 --> 30:32.330] item, and put item, and I think some others are not, or they're considered data events, so they're [30:32.330 --> 30:40.270] not logged by Cloud Trail. So you can use DynamoDB streams to stream those data events to a [30:40.270 --> 30:46.070] Lambda function and respond to them however you want, so that can be a way to monitor that [30:46.070 --> 30:52.730] data level activity. And maybe you can use AWS config to track changes to your tables, but usually [30:52.730 --> 31:00.310] this will be too late by the time it alerts you of anything. Indicators to look out for, again, [31:00.310 --> 31:07.470] STS get caller identity, KMS key policy modifications, high volume of table reads and writes, [31:08.090 --> 31:14.630] attempts to delete backups, guard duty alerts, attempts to increase the table's read capacity. [31:14.630 --> 31:19.870] If they find a large table that has a low read capacity, they might increase the read capacity [31:19.870 --> 31:25.210] so that they can run parallel queries and download the entire database quickly without causing a [31:25.210 --> 31:32.130] service in the environment. And that's kind of it for DynamoDB. I'm running out of time, [31:32.130 --> 31:38.350] so I'm trying to speed through a couple of these. Other potential targets, so there could be Elastic [31:38.350 --> 31:44.590] Walkstore and AWS, you can encrypt volumes or snapshots, relational database service, [31:44.590 --> 31:50.210] or RDS database and snapshots, Lambda function code and environment variables, [31:50.210 --> 31:58.730] secrets manager secrets, SNS topics, SQS queues, ECR repositories and images, which just got [31:58.730 --> 32:05.570] released last week, I believe, EFS file systems, and more. And then you can even do it for other [32:05.570 --> 32:09.550] cloud providers, but like I said earlier, we didn't dive into that, but something like Google [32:09.550 --> 32:16.470] Storage could be done the same way as S3. So cloud provider intervention and other takeaways. [32:16.470 --> 32:20.910] We don't know what a cloud provider could do to help you if you got targeted, so you can't rely [32:20.910 --> 32:26.590] on them for that. So you need to act as if they would not be able to help you under any condition. [32:26.730 --> 32:29.510] They can't help you with the local encryption anyways, because they're not going to know the [32:29.510 --> 32:35.110] password to your encrypted data. This means you need to evaluate your own defenses. You need to [32:35.110 --> 32:41.630] take care of your environment, monitor it, respond to things. You can't rely on the unknown, [32:41.630 --> 32:45.210] essentially. Can you keep attackers out of your environment? Can you prevent [32:45.210 --> 32:50.250] attackers from doing things once they're in your environment? Can you detect when they're [32:50.250 --> 32:56.170] doing things once they're in your environment? Can you match those detections to patterns? [32:56.610 --> 33:01.330] Can you tell that maybe a ransomware attack's coming because of these few API calls made in [33:01.390 --> 33:06.330] a row or something along those lines? And additionally, you need to ask, [33:06.330 --> 33:11.170] can I get back online after an attack? Am I ready? Do I know what to do if I got hit with [33:11.270 --> 33:14.650] a ransomware attack? If the answer is no, then you've got some work to do. [33:15.610 --> 33:20.330] And then how fast? Is it going to be fast enough before there's a major business impact? [33:20.510 --> 33:24.550] How much money are you going to lose in the meantime? 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:34.690] For some reason, what if you just can't get access? I mean, they are criminals. [33:34.690 --> 33:38.390] You can't necessarily trust them. Just because you pay them doesn't mean they're going to [33:38.390 --> 33:43.890] decrypt your data. So could you handle that? Are you going to go out of business? [33:44.870 --> 33:48.150] What's going to happen? That's something you need to think about. [33:49.050 --> 33:54.490] That kind of wraps things up. I have a slide here just of some additional resources and references. [33:55.790 --> 34:00.610] First one I always want to talk about is AWS documentation. I read that like it's the Bible. [34:01.750 --> 34:05.030] There are so many great things in there, and it's an easy way to learn [34:05.430 --> 34:11.770] in-depth about features of AWS that you might not know otherwise. So I'm constantly reading that. [34:11.830 --> 34:16.070] And then I wrote two blog posts on S3 ransomware in particular, [34:16.070 --> 34:19.150] while I ran a security labs. You can check those out. [34:20.010 --> 34:24.790] I want to give a special thanks to my team at CrowdStrike, just for helping with the [34:24.790 --> 34:31.910] presentation and the research, and giving me some feedback on that. Houston Hopkins from Capital One [34:31.910 --> 34:38.510] for some help with the one-liner commands and some cool tricks with the AWS CLI. And [34:38.510 --> 34:44.430] Rhino Security Labs for that previous research into ransomware and just AWS security in general. [34:45.370 --> 34:50.650] In the bottom right, you can see my Twitter handle there for if there's not sure how much time left [34:50.650 --> 34:55.090] we have for questions, but if there are any that don't get answered, feel free to reach out to me [34:55.090 --> 35:00.670] on there. But for that, I'll go ahead and just kind of open up and answer any questions that [35:00.670 --> 35:06.510] might be in the chat. Is object versioning and MFA delete good enough, or were you saying that [35:06.510 --> 35:14.130] you need to implement and do all five of those things? I think that object versioning and MFA [35:14.130 --> 35:23.130] delete are good for a couple of methods, but if you think of it like a local encryption method, [35:23.130 --> 35:28.290] if you downloaded the objects from the bucket, their threat could be we're going to release all [35:28.290 --> 35:35.710] this data. And so then versioning and MFA delete wouldn't do it. I like to always just follow [35:35.710 --> 35:43.050] defense in depth and implement as much as you can. Then it's hard to take into account [35:43.050 --> 35:49.730] the cost though, and then the work and changes that applies to your environment. But there's [35:49.730 --> 35:53.970] some of the best defenses, but it definitely won't protect you from everything essentially. [35:54.570 --> 36:01.130] Got it. And the second question from Skybound, I think you touched on this a little bit towards [36:01.130 --> 36:08.050] the end. For recovery in cases where decryption keys are within AWS, would AWS be able to help [36:08.050 --> 36:14.610] with their recovery and deal with the attacker? For example, with the KMS policy, basically [36:14.610 --> 36:21.250] expecting AWS to adjust the KMS policy so that the customer can get access back. [36:21.890 --> 36:28.970] So that's kind of where I was touching on. We don't know for sure. And then it brings up [36:28.970 --> 36:35.790] the question of how fast, you know, maybe it takes a support case and then a day or two goes by or [36:35.790 --> 36:42.010] something like that. And it's already, there's already a huge impact. I would say until there's [36:42.010 --> 36:46.750] an official statement or something along those lines, not that there needs to be one necessarily, [36:46.750 --> 36:52.590] but implementing your own defenses and detections is the way to go instead of relying [36:52.590 --> 36:56.310] on them to take care of you in the event that something goes wrong.