From 2855978a6ce36bad137a357dea8e3db4bc01f97f Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Wed, 30 Mar 2022 18:53:08 +0200 Subject: [PATCH] Exfiltration of EBS snapshots and AMIs: Handle error when EBS encryption by default is enabled (closes #109) --- .../aws/exfiltration/ec2-share-ami/main.go | 8 +++++++ .../ec2-share-ebs-snapshot/main.go | 9 ++++++++ internal/utils/aws_utils.go | 23 +++++++++++++++++++ internal/utils/aws_utils_test.go | 20 ++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 internal/utils/aws_utils_test.go diff --git a/internal/attacktechniques/aws/exfiltration/ec2-share-ami/main.go b/internal/attacktechniques/aws/exfiltration/ec2-share-ami/main.go index e24eea3b..f4fc29fb 100644 --- a/internal/attacktechniques/aws/exfiltration/ec2-share-ami/main.go +++ b/internal/attacktechniques/aws/exfiltration/ec2-share-ami/main.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/datadog/stratus-red-team/internal/providers" + "github.com/datadog/stratus-red-team/internal/utils" "github.com/datadog/stratus-red-team/pkg/stratus" "github.com/datadog/stratus-red-team/pkg/stratus/mitreattack" "log" @@ -73,6 +74,13 @@ func detonate(params map[string]string) error { }, }) + if err != nil && utils.IsErrorDueToEBSEncryptionByDefault(err) { + log.Println("Note: Stratus detonated the attack, but the sharing was unsuccessful. " + + "This is likely because EBS default encryption is enabled in the region. " + + "Nonetheless, it did simulate a plausible attacker action.") + return nil + } + if err != nil { return errors.New("Unable to share AMI with external AWS account: " + err.Error()) } diff --git a/internal/attacktechniques/aws/exfiltration/ec2-share-ebs-snapshot/main.go b/internal/attacktechniques/aws/exfiltration/ec2-share-ebs-snapshot/main.go index 6317fd35..b4e1f3f5 100644 --- a/internal/attacktechniques/aws/exfiltration/ec2-share-ebs-snapshot/main.go +++ b/internal/attacktechniques/aws/exfiltration/ec2-share-ebs-snapshot/main.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/datadog/stratus-red-team/internal/providers" + "github.com/datadog/stratus-red-team/internal/utils" "github.com/datadog/stratus-red-team/pkg/stratus" "github.com/datadog/stratus-red-team/pkg/stratus/mitreattack" "log" @@ -73,6 +74,14 @@ func detonate(params map[string]string) error { Add: []types.CreateVolumePermission{{UserId: &ShareWithAccountId}}, }, }) + + if err != nil && utils.IsErrorDueToEBSEncryptionByDefault(err) { + log.Println("Note: Stratus detonated the attack, but the sharing was unsuccessful. " + + "This is likely because EBS default encryption is enabled in the region. " + + "Nonetheless, it did simulate a plausible attacker action.") + return nil + } + return err } diff --git a/internal/utils/aws_utils.go b/internal/utils/aws_utils.go index 218fffd4..b90b4e72 100644 --- a/internal/utils/aws_utils.go +++ b/internal/utils/aws_utils.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/sts" "log" + "strings" ) func GetCurrentAccountId(cfg aws.Config) (string, error) { @@ -29,3 +30,25 @@ func AwsConfigFromCredentials(accessKeyId string, secretAccessKey string, sessio return cfg } + +func IsErrorDueToEBSEncryptionByDefault(err error) bool { + if err == nil { + return false + } + errorMessage := strings.ToLower(err.Error()) + + // EBS snapshots + // error: operation error EC2: ModifySnapshotAttribute, https response error StatusCode: 400, RequestID: 12f44aeb-7b3b-4488-ac46-a432d20cc7a9, api error OperationNotPermitted: Encrypted snapshots with EBS default key cannot be shared + if strings.Contains(errorMessage, "operationnotpermitted") && strings.Contains(errorMessage, "ebs default key") { + return true + } + + // AMIs + // error: operation error EC2: ModifyImageAttribute, https response error StatusCode: 400, RequestID: 85f85eff-4114-4861-a659-f9aeea48d78b, api error InvalidParameter: Snapshots encrypted with the AWS Managed CMK can't be shared. Specify another snapshot. + if strings.Contains(errorMessage, "invalidparameter") && strings.Contains(errorMessage, "snapshots encrypted with the aws managed cmk") { + return true + } + + return false + +} diff --git a/internal/utils/aws_utils_test.go b/internal/utils/aws_utils_test.go new file mode 100644 index 00000000..ceca43ac --- /dev/null +++ b/internal/utils/aws_utils_test.go @@ -0,0 +1,20 @@ +package utils + +import ( + "errors" + "github.com/aws/aws-sdk-go-v2/service/cloudtrail/types" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestIsErrorRelatedToEbsEncryptionByDefault(t *testing.T) { + assert.False(t, IsErrorDueToEBSEncryptionByDefault(nil)) + assert.False(t, IsErrorDueToEBSEncryptionByDefault(errors.New("foo"))) + assert.False(t, IsErrorDueToEBSEncryptionByDefault(&types.OperationNotPermittedException{})) + assert.True(t, IsErrorDueToEBSEncryptionByDefault( + errors.New("operation error EC2: ModifySnapshotAttribute, https response error StatusCode: 400, RequestID: 12f44aeb-7b3b-4488-ac46-a432d20cc7a9, api error OperationNotPermitted: Encrypted snapshots with EBS default key cannot be shared"), + )) + assert.True(t, IsErrorDueToEBSEncryptionByDefault( + errors.New("operation error EC2: ModifyImageAttribute, https response error StatusCode: 400, RequestID: 85f85eff-4114-4861-a659-f9aeea48d78b, api error InvalidParameter: Snapshots encrypted with the AWS Managed CMK can't be shared. Specify another snapshot"), + )) +}