AWS Penetration Testing Notes: S3, IAM, and Lambda Misconfigurations

Common AWS findings: exposed S3 buckets, IAM misconfigurations, and Lambda weaknesses, grouped by service.

10 min read
ibrahimsql
1,970 words

AWS Penetration Testing Notes: S3, IAM, and Lambda Misconfigurations#

Why this topic matters: most cloud findings are configuration findings. The services themselves hold up; the way teams connect them is where the audits start.

Ethics and scope: every check here assumes a written scope that names the AWS account, the regions, and the services under test. Do not probe accounts you do not own, and do not extract data beyond a proof of read access. For the web-side equivalents, see OWASP Top 10 notes.

S3: The Classic Exposure#

S3 shows up in almost every cloud audit. The patterns are stable.

Public access#

  • Bucket policy grants public read.
  • ACL grants READ_ACP to everyone.
  • Static website hosting exposes directory listings.
  • A CDN fronts a bucket and preserves the public policy.

Dangling buckets#

A CNAME that points at a deleted bucket is the same class of problem as a dangling subdomain, with the bucket name as the claimable resource.

cdn.example.com CNAME old-assets.s3.amazonaws.com

If old-assets.s3.amazonaws.com is gone, the name is claimable. That claim under your domain is a finding.

Triage questions#

  1. Does the bucket allow public reads?
  2. Does it allow public writes or listing?
  3. Is it referenced from DNS or docs?
  4. Is encryption on by default?
  5. Are access logs enabled?

IAM: The Perimeter#

IAM decides who can do what. The findings cluster around trust and policy breadth.

Over-broad policies#

  • Action: "*", Resource: "*" on a role used by a workload.
  • AdministratorAccess attached to a human role.
  • Managed policies copied from tutorials without review.

Trust misconfigurations#

  • A role assumable from a broad set of principals.
  • sts:AssumeRole trusting a third-party account that changed hands.
  • Cross-account trusts that were never re-reviewed.

PassRole patterns#

PassRole lets one principal hand a role to another service. It is powerful and common, which is why it appears in escalation notes: a principal that can both pass a powerful role and create the service gets the service's powers.

What to enumerate#

AssetQuestionTool shape
RolesWho can assume them?iam list-roles plus trust docs
PoliciesAny * actions on * resources?Policy simulator
UsersMFA on console users?Credential report
GroupsDirect policies vs inheritedConsole or API listing
Access keysRotation and ageLast-used report

Lambda: Serverless Attack Surface#

Lambda findings are code and configuration findings, in serverless clothes.

Handler input#

The event JSON is user input. Treat it like any other untrusted body:

  • No validation of expected fields.
  • Template injection in log lines or SQL built from event fields.
  • Path traversal when events carry file names.

Permissions#

  • Execution role with s3:GetObject on every bucket.
  • Environment variables holding long-lived secrets.
  • VPC placement that grants unexpected network reach.

Supply chain#

  • Dependencies pinned loosely.
  • Layers from unverified sources.
  • Build steps that do not record provenance.

Event shapes to probe#

# API Gateway event to a function {"pathParameters": {"id": "../../etc/passwd"}, "queryStringParameters": {...}} # S3 event to a function {"Records": [{"s3": {"object": {"key": "../../../tmp/x"}}}]}

Common Findings by Service#

ServiceFrequent findingFix direction
S3Public read/write bucketBlock public access, audit policies
IAMAdministratorAccess on a roleNarrow to task actions
LambdaOver-broad execution roleLeast privilege per function
EC2Security group open to 0.0.0.0/0Restrict ingress, use SSM
RDSPublic endpoint enabledPrivate subnets, no public IP
CloudTrailLogging gap in a regionEnable in all regions
KMSOver-broad key policiesScope key use to one principal

Tooling Notes#

  • ScoutSuite: multi-cloud audit with a scored report.
  • Pacu: exploitation framework for scoped AWS tests.
  • Prowler: CIS benchmark style checks.
  • CloudSploit: rule-based misconfiguration scan.

Each tool produces a list. The tester's job is to verify the list, remove false positives, and write what is actually exploitable in the scoped account.

A Scoped Test Flow#

  1. List the account's resources by region.
  2. Run the passive audit tool inside the authorized account.
  3. Verify each candidate with a minimal read, not a write.
  4. Record the exact resource ARN and the observed access.
  5. Write the fix, the owner, and the verification date.

Proof of Access, Not Theft#

For every bucket or key you believe is exposed, capture the minimum evidence:

  • A directory listing head, not the data.
  • A first record of a listing, not the listing.
  • A failed and a successful call for the same resource.

Evidence that proves access without copying the contents is what a good report needs.

Limits of These Notes#

  • AWS features change; the audit checklist ages.
  • Some findings depend on the tenant and region of the account.
  • A misconfiguration flagged by a scanner may be intentional.
  • This is an audit guide, not an exploitation handbook.

IAM Deep Dive: The Trust Policy#

A role's trust policy says who can assume it. The interesting cases are the broad ones:

{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::000000000000:root"}, "Action": "sts:AssumeRole" }] }

That document alone is not wrong. The finding is when the account ID, the external ID, or the condition is weaker than the role's power.

S3 Deep Dive: Block Public Access#

The four account-level settings that define the posture:

SettingWhat it blocks
Block public ACLsNew public ACLs on buckets and objects
Ignore public ACLsExisting public ACLs
Block public bucket policiesPublic bucket policies
Restrict public bucketsAccess to buckets with public policies

A finding note names which of the four is off and which bucket proves the exposure.

Lambda Deep Dive: Handler Shape#

def handler(event, context): name = event.get("name", "") return {"statusCode": 200, "body": f"hello {name}"}

The vulnerable shape is the same code with the name concatenated into a system call or a SQL string. Every handler deserves the same question: what in this function touches the outside world because of the event?

Reporting Shape#

FieldExample
Resourcearn:aws:s3:::client-exports
ObservedPublic ACL granting READ
ScopeAccount 111122223333, region us-east-1
EvidenceDirectory listing head, trimmed
FixEnable Block Public Access, remove ACL
VerificationRe-run audit after change

Triage by Exploitability, Not Volume#

A scanner may return hundreds of findings. Sort them:

  1. Can an unauthenticated principal reach data?
  2. Can a low-privilege principal escalate?
  3. Can a role escape its intended account?
  4. Everything else is hygiene.

A Small Walkthrough#

Walkthrough 1: bucket audit#

  1. List buckets in the scoped account.
  2. For each, read the ACL and the policy.
  3. Note any public grants.
  4. Try one anonymous GET on a single object head.
  5. Record ARN, grant, and observed status.

Walkthrough 2: role audit#

  1. List roles and their trust documents.
  2. Flag wildcard trusts or missing external IDs.
  3. Check attached policies for *:*.
  4. Note which roles are assumed by which services.
  5. Record one line per risky pair.

Walkthrough 3: function audit#

  1. List functions and their execution roles.
  2. Check environment variables for long-lived secrets.
  3. Look at the handler for unvalidated event fields.
  4. Check dependency pins and layer sources.
  5. Record one line per function with a concern.

False Positive Friends#

  • A bucket that is intentionally public for a static site.
  • A role with a big policy used only in a sandbox account.
  • An environment variable that holds a rotated, short-lived token.
  • A security group rule that looks open but is limited by a NACL you did not read.

Each of these needs one verification before it becomes a report.

What a Good Cloud Report Contains#

  • The scoped account and region list.
  • The exact resource identifier for each finding.
  • One proof request or API call per finding.
  • A fix that names the console path or the Terraform resource.
  • A verification date and the re-run command.

Reading Order Around This Topic#

Triage Cadence#

Re-run the audit after every infrastructure change. The finding list is a living artifact; a check that passed in January tells you nothing about March.

Short Glossary#

  • ARN: the AWS resource name, a unique identifier per resource.
  • Trust policy: the document saying who may assume a role.
  • Execution role: the IAM role a Lambda function runs with.
  • Public access block: the four S3 account settings that gate public grants.
  • External ID: the extra condition many cross-account trusts require.

Final Notes#

Cloud findings are boring in the best way: they follow a checklist, they have a known fix, and they verify cleanly. The discipline is the same as web testing. Scope first, one minimal proof per finding, and a fix that names the exact setting.

A Note on Evidence#

A curl that lists a bucket head is a proof. A copied customer record is not evidence; it is an incident. Trim every artifact before it leaves the engagement machine. When in doubt, record the ARN and the failing call, and let the client re-run the proof.

Small Print for the Report#

  • Record the scanner version and rule set used.
  • Record the region list covered.
  • Mark findings that were verified manually.
  • Note the settings that were changed as a result.

Service Trust Boundary#

internet --> S3 / CDN --> IAM decision --> Lambda / app --> data | | | public policy role trust handler input

Each hop has a configuration check. The classic findings live where two hops disagree: a bucket policy that trusts a CDN, a role that trusts a changed account, a handler that trusts its input.

Detection#

  • iam AccessAnalyzer findings for public or cross-account access.
  • S3 access logs and Block Public Access state.
  • Lambda env vars containing secrets in plaintext.
  • CloudTrail for s3:GetBucketAcl, iam:PassRole, and AssumeRole patterns.

Limitations#

  • A finding in a scanner is configuration evidence, not impact; a public bucket on a test account is not a breach.
  • Rate limits and honeypots shape what a read-only probe will reveal; record the limit, do not fight it.
  • Rotating a key does not revoke sessions minted before rotation; track session TTLs.

Cikarilar#

  • Most cloud findings are configuration findings.
  • Public access is a posture, not an attribute of one bucket.
  • PassRole plus create-service equals escalation.
  • Record the ARN and the failing call, not customer data.
---
Share this post:

What do you think?

React to show your appreciation

Related Posts