Browse CTFs New CTF Sign in

AWS Service Control Policy Misconfiguration: Cross-Account Permission Escalation

log_analysis_siem Difficulté 1–5 30 min certifiable

Théorie

Why This Matters

In 2019, a Capital One contractor exploited an overly permissive IAM role attached to a WAF instance to call ec2:DescribeInstances and s3:GetObject across an entire AWS Organization. A correctly configured Service Control Policy denying broad metadata and S3 read actions at the organizational unit level would have contained the blast radius to a single account rather than exposing over 100 million customer records. SCP misconfigurations are a force-multiplier vulnerability: one permissive policy silently widens the permission boundary of every IAM user, role, and group in every child account simultaneously — no individual account audit will detect the gap unless the SCP layer itself is reviewed.

Core Concept

AWS Organizations is the multi-account management service that groups AWS accounts into a hierarchy of Organizational Units (OUs). Service Control Policies (SCPs) are JSON permission documents attached to the root, to OUs, or to individual accounts. They act as a permission boundary — they never grant permissions, they only constrain what the maximum effective permission can be. Even if an IAM policy in a child account allows s3:*, an SCP that denies s3:DeleteBucket on the parent OU makes that action impossible for every principal in every child account.

SCPs follow an implicit deny at root model: if no SCP explicitly allows an action, it is denied. AWS provides a default FullAWSAccess SCP that allows all actions; organizations that rely solely on this policy have no SCP-level guardrails at all. A deny-list strategy keeps FullAWSAccess and adds explicit Deny statements; an allow-list strategy removes FullAWSAccess and grants only the actions required — the latter is harder to maintain but provides stronger containment.

The effective permission for any principal is the intersection of: the SCP allow set, the identity-based IAM policy, any resource-based policy, and any permission boundary. Attackers who gain access to a child account first enumerate SCPs to understand what actions are blocked before attempting privilege escalation — understanding that an SCP blocks iam:CreateUser shifts the attack toward Lambda execution roles or EC2 instance profiles instead.

Technical Deep-Dive

# List all SCPs in the organization (requires Organizations master account or delegated admin)
aws organizations list-policies --filter SERVICE_CONTROL_POLICY 
  --query 'Policies[*].{Id:Id,Name:Name,Description:Description}' 
  --output table

# Retrieve the full JSON of a specific SCP
aws organizations describe-policy --policy-id p-EXAMPLEPOLICYID 
  --query 'Policy.Content' --output text | python3 -m json.tool

# List all SCPs attached to a specific OU
aws organizations list-policies-for-target 
  --target-id ou-EXAMPLE-OUID 
  --filter SERVICE_CONTROL_POLICY 
  --query 'Policies[*].{Id:Id,Name:Name}' 
  --output table

# List all targets (OUs/accounts) that a specific SCP is attached to
aws organizations list-targets-for-policy --policy-id p-EXAMPLEPOLICYID 
  --query 'Targets[*].{Name:Name,TargetId:TargetId,Type:Type}' 
  --output table

# Simulate effective permissions for a principal in a child account
# (run from the child account after assuming the principal's role)
aws iam simulate-principal-policy 
  --policy-source-arn arn:aws:iam::123456789012:role/ExampleRole 
  --action-names s3:GetObject ec2:DescribeInstances iam:CreateUser 
  --query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}' 
  --output table

# Use Checkov to statically audit SCP JSON files saved locally
checkov -d ./scps/ --framework json_policy 
  --check CKV_AWS_132,CKV_AWS_192
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyLeaveOrganization",
      "Effect": "Deny",
      "Action": "organizations:LeaveOrganization",
      "Resource": "*"
    },
    {
      "Sid": "DenyRootUserActions",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "aws:PrincipalArn": "arn:aws:iam::*:root"
        }
      }
    }
  ]
}

Security Assessment Methodology

  1. Enumerate the SCP hierarchy. From the management account, run aws organizations list-policies --filter SERVICE_CONTROL_POLICY to obtain all SCP IDs, then list-targets-for-policy for each. Build a map of which OUs and accounts are covered.
  2. Identify accounts with only FullAWSAccess attached. If the only SCP is the AWS-managed FullAWSAccess (policy ID p-FullAWSAccess), there are no organizational guardrails — every IAM permission in child accounts is fully effective. This is the highest-priority finding.
  3. Parse each SCP for overly broad Allow statements. A statement of "Effect": "Allow", "Action": "*", "Resource": "*" in a custom SCP is equivalent to FullAWSAccess — it adds nothing. Confirm that allow-list SCPs enumerate only required service namespaces.
  4. Test effective permissions from inside a child account. Assume a role with known IAM permissions in a child account, then call aws iam simulate-principal-policy against high-value actions (iam:CreateUser, sts:AssumeRole, s3:GetObject). Compare the decision to what the IAM policy alone would allow — any action the SCP should block that returns allowed is a misconfiguration.
  5. Audit for missing critical deny statements. Production SCPs should deny: organizations:LeaveOrganization, root user actions, disabling CloudTrail, disabling GuardDuty, changing account contact information, and creating IAM users without MFA enforcement.
  6. Remediate by adding targeted Deny statements to the OU-level SCP. Use aws organizations update-policy or update via Terraform aws_organizations_policy resource. Re-run simulation to confirm the deny takes effect. Use aws organizations update-policy-content carefully — a malformed SCP that denies all actions on the root will lock every account in the organization.

Common Assessment Errors

  • Assuming SCPs grant permissions. SCPs only constrain; they never grant. An SCP that allows s3:* does nothing unless the IAM policy in the account also allows those actions. Assessors who read an SCP Allow as confirmation that a principal can perform the action will misreport findings.
  • Ignoring OU inheritance. SCPs are cumulative down the hierarchy — a child OU is constrained by both its own SCPs and all parent OU SCPs. Auditing only the directly attached SCP misses inherited restrictions or inherited gaps.
  • Overlooking the management account exception. SCPs do not apply to the management (master) account itself. An attacker who escalates to the management account bypasses all SCP controls. This is a design constraint, not a misconfiguration, but assessors must document it clearly.
  • Conflating SCPs with IAM permission boundaries. Permission boundaries are per-principal IAM constructs; SCPs are organizational. They interact but are configured differently. A finding about a missing permission boundary is not the same as a missing SCP.
  • Modifying SCPs in production without simulation testing. An overly broad Deny SCP applied to the root OU can silently break workloads across hundreds of accounts. Always test with simulate-principal-policy in a non-production OU before applying to production.
  • Missing delegated admin accounts. AWS allows a delegated administrator account for Organizations access. Enumerate with aws organizations list-delegated-administrators — a compromised delegated admin account can read and potentially modify SCP configuration.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0053 Knowledge of security risk management processes Evaluating SCP coverage gaps as organizational risk: a missing guardrail is a risk that spans every child account simultaneously
K0167 Knowledge of system administration, network, and OS hardening techniques Applying hardening principles to cloud organization structures: deny-list SCPs, root user restrictions, and CloudTrail protection
S0073 Skill in conducting vulnerability scans and recognizing vulnerabilities Using simulate-principal-policy and Checkov to detect SCP misconfigurations that widen effective permissions beyond intended boundaries
T0144 Conduct penetration testing as required for new or updated applications Enumerating SCP hierarchies from a child account to determine which escalation paths are blocked and which remain viable during a cloud penetration test
T0395 Write code to address security vulnerabilities Authoring correct SCP JSON with targeted Deny statements and condition keys to remediate identified permission boundary gaps

Further Reading

  • AWS Security Best Practices — Amazon Web Services, Service Control Policies chapter (AWS Documentation)
  • Hacking the Cloud: AWS Organizations Attacks — Nick Frichette (hackingthe.cloud)
  • Cloud Security Handbook — Eyal Estrin, Chapter 9: Multi-Account Governance (Packt Publishing)

Challenge Lab

Renforcez votre apprentissage avec un défi généré basé sur la compétence de cette carte.