diff --git a/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.go b/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.go index a4761f56..379b3291 100644 --- a/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.go +++ b/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.go @@ -32,7 +32,7 @@ Detonation: Calls ModifySnapshotAttribute to share the snapshot. } func detonate(params map[string]string) error { - ec2Client := ec2.NewFromConfig(providers.GetAWSProvider()) + ec2Client := ec2.NewFromConfig(providers.AWS().GetConnection()) // Find the snapshot to exfiltrate ourSnapshotId := params["snapshot_id"] diff --git a/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.tf b/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.tf index 3c4bdaa1..ee42120a 100644 --- a/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.tf +++ b/internal/attacktechniques/aws/exfiltration/ebs_snapshot_share/main.tf @@ -6,6 +6,12 @@ terraform { } } } +provider "aws" { + skip_region_validation = true + skip_credentials_validation = true + skip_get_ec2_platforms = true + skip_metadata_api_check = true +} data "aws_availability_zones" "available" { state = "available" diff --git a/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.go b/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.go index 942c0137..e1fa4d21 100644 --- a/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.go +++ b/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.go @@ -27,7 +27,7 @@ Detonation: Create the access key. MitreAttackTactics: []mitreattack.Tactic{mitreattack.Persistence}, PrerequisitesTerraformCode: tf, Detonate: func(terraformOutputs map[string]string) error { - iamClient := iam.NewFromConfig(providers.GetAWSProvider()) + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) log.Println("Creating access key on legit IAM user to simulate backdoor") result, err := iamClient.CreateAccessKey(context.Background(), &iam.CreateAccessKeyInput{UserName: aws.String("sample-legit-user")}) if err != nil { @@ -37,7 +37,7 @@ Detonation: Create the access key. return nil }, Cleanup: func() error { - iamClient := iam.NewFromConfig(providers.GetAWSProvider()) + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) log.Println("Removing access key from IAM user") result, err := iamClient.ListAccessKeys(context.Background(), &iam.ListAccessKeysInput{UserName: aws.String("sample-legit-user")}) if err != nil { diff --git a/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.tf b/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.tf index c0623a57..44c4b86f 100644 --- a/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.tf +++ b/internal/attacktechniques/aws/persistence/backdoor_iam_user/main.tf @@ -6,6 +6,12 @@ terraform { } } } +provider "aws" { + skip_region_validation = true + skip_credentials_validation = true + skip_get_ec2_platforms = true + skip_metadata_api_check = true +} resource "aws_iam_user" "legit-user" { name = "sample-legit-user" # TODO parametrize diff --git a/internal/attacktechniques/aws/persistence/backdoor_role/main.go b/internal/attacktechniques/aws/persistence/backdoor_role/main.go index 14f9ffda..02001f7a 100644 --- a/internal/attacktechniques/aws/persistence/backdoor_role/main.go +++ b/internal/attacktechniques/aws/persistence/backdoor_role/main.go @@ -31,7 +31,7 @@ Detonation: Updates the assume role policy of the IAM role to backdoor it. MitreAttackTactics: []mitreattack.Tactic{mitreattack.Persistence}, PrerequisitesTerraformCode: tf, Detonate: func(terraformOutputs map[string]string) error { - iamClient := iam.NewFromConfig(providers.GetAWSProvider()) + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) log.Println("Backdooring IAM role by allowing sts:AssumeRole from an extenral AWS account") _, err := iamClient.UpdateAssumeRolePolicy(context.Background(), &iam.UpdateAssumeRolePolicyInput{ RoleName: aws.String("sample-legit-role"), diff --git a/internal/attacktechniques/aws/persistence/backdoor_role/main.tf b/internal/attacktechniques/aws/persistence/backdoor_role/main.tf index c0306a5e..25e8b2d5 100644 --- a/internal/attacktechniques/aws/persistence/backdoor_role/main.tf +++ b/internal/attacktechniques/aws/persistence/backdoor_role/main.tf @@ -6,6 +6,12 @@ terraform { } } } +provider "aws" { + skip_region_validation = true + skip_credentials_validation = true + skip_get_ec2_platforms = true + skip_metadata_api_check = true +} resource "aws_iam_role" "legit-role" { name = "sample-legit-role" # TODO parametrize diff --git a/internal/attacktechniques/aws/persistence/malicious_iam_user/main.go b/internal/attacktechniques/aws/persistence/malicious_iam_user/main.go index 032d5640..766f8ae0 100644 --- a/internal/attacktechniques/aws/persistence/malicious_iam_user/main.go +++ b/internal/attacktechniques/aws/persistence/malicious_iam_user/main.go @@ -28,7 +28,7 @@ Detonation: Creates the IAM user and attached 'AdministratorAccess' to it. Platform: stratus.AWS, MitreAttackTactics: []mitreattack.Tactic{mitreattack.Persistence}, Detonate: func(terraformOutputs map[string]string) error { - iamClient := iam.NewFromConfig(providers.GetAWSProvider()) + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) log.Println("Creating a malicious IAM user") _, err := iamClient.CreateUser(context.TODO(), &iam.CreateUserInput{ UserName: userName, @@ -61,7 +61,7 @@ Detonation: Creates the IAM user and attached 'AdministratorAccess' to it. return nil }, Cleanup: func() error { - iamClient := iam.NewFromConfig(providers.GetAWSProvider()) + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) result, err := iamClient.ListAccessKeys(context.Background(), &iam.ListAccessKeysInput{UserName: userName}) if err != nil { return errors.New("unable to clean up IAM user access keys: " + err.Error()) diff --git a/internal/providers/aws.go b/internal/providers/aws.go index 92d67401..9c060bee 100644 --- a/internal/providers/aws.go +++ b/internal/providers/aws.go @@ -4,26 +4,35 @@ import ( "context" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/sts" "log" ) -var isAuthenticated = false -var hasDeterminedIfAuthenticated = false +var awsProvider = AWSProvider{} -func init() { - /*aws, _ := config.LoadDefaultConfig(context.TODO()) - stsClient := sts.NewFromConfig(aws) - _, err := stsClient.GetCallerIdentity(context.Background(), &sts.GetCallerIdentityInput{}) - isAuthenticated = err == nil*/ +func AWS() *AWSProvider { + return &awsProvider +} + +type AWSProvider struct { + awsConfig *aws.Config } -func GetAWSProvider() aws.Config { - /*if !isAuthenticated { - log.Fatal("You are not authenticated to AWS, or have not set your default AWS region.") - }*/ - cfg, err := config.LoadDefaultConfig(context.TODO()) - if err != nil { - log.Fatalf("unable to load SDK config, %v", err) +func (m *AWSProvider) GetConnection() aws.Config { + if m.awsConfig == nil { + cfg, err := config.LoadDefaultConfig(context.Background()) + if err != nil { + log.Fatalf("unable to load AWS configuration, %v", err) + } + m.awsConfig = &cfg } - return cfg + + return *m.awsConfig +} + +func (m *AWSProvider) IsAuthenticatedAgainstAWS() bool { + m.GetConnection() + stsClient := sts.NewFromConfig(m.GetConnection()) + _, err := stsClient.GetCallerIdentity(context.Background(), &sts.GetCallerIdentityInput{}) + return err == nil } diff --git a/internal/runner/runner.go b/internal/runner/runner.go index dbe7ad10..b27b8a5e 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -3,6 +3,7 @@ package runner import ( "encoding/json" "errors" + "github.com/datadog/stratus-red-team/internal/providers" "github.com/datadog/stratus-red-team/internal/utils" "github.com/datadog/stratus-red-team/pkg/stratus" "io/ioutil" @@ -28,13 +29,20 @@ type Runner struct { func NewRunner(technique *stratus.AttackTechnique, warmup bool, cleanup bool) Runner { stateManager := NewStateManager() - return Runner{ + runner := Runner{ Technique: technique, ShouldWarmUp: warmup, ShouldCleanup: cleanup, TerraformManager: NewTerraformManager(path.Join(stateManager.GetRootDirectory(), "terraform")), StateManager: stateManager, } + runner.initialize() + + return runner +} + +func (m *Runner) initialize() { + m.ValidatePlatformRequirements() } // Utility function to extract the Terraform file of a technique @@ -136,3 +144,12 @@ func (m *Runner) CleanUp() error { return prerequisitesCleanupErr } } + +func (m *Runner) ValidatePlatformRequirements() { + switch m.Technique.Platform { + case stratus.AWS: + if !providers.AWS().IsAuthenticatedAgainstAWS() { + log.Fatal("You are not authenticated against AWS, or you have not set your region.") + } + } +} diff --git a/internal/runner/terraform.go b/internal/runner/terraform.go index 1b61ee34..08d2a25c 100644 --- a/internal/runner/terraform.go +++ b/internal/runner/terraform.go @@ -3,7 +3,6 @@ package runner import ( "context" "errors" - "fmt" "github.com/datadog/stratus-red-team/internal/utils" "github.com/hashicorp/go-version" "github.com/hashicorp/hc-install/product" @@ -22,7 +21,6 @@ type TerraformManager struct { } func NewTerraformManager(terraformBinaryPath string) *TerraformManager { - fmt.Println(terraformBinaryPath) manager := TerraformManager{ terraformVersion: TerraformVersion, terraformBinaryPath: terraformBinaryPath,