#!/bin/bash # ============================================================================= # Modular AWS Permission Checker # Description: Check specific AWS permissions for current session # Usage: ./aws-perm-check.sh [module] [options] # ============================================================================= # Global variables SCRIPT_NAME="$(basename "$0")" QUIET_MODE=false VERBOSE_MODE=false OUTPUT_FORMAT="text" # text, json, csv # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # ============================================================================= # Core Functions # ============================================================================= log_info() { [[ "$QUIET_MODE" == true ]] && return echo -e "${BLUE}[INFO]${NC} $1" } log_success() { [[ "$QUIET_MODE" == true ]] && return echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" >&2 } log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } show_usage() { cat << EOF Usage: $SCRIPT_NAME [MODULE] [OPTIONS] MODULES: core - Basic AWS identity and core permissions ec2 - EC2 service permissions s3 - S3 service permissions iam - IAM service permissions ssm - Systems Manager permissions rds - RDS service permissions ecr - Elastic Container Registry permissions cloudwatch - CloudWatch permissions jenkins - Jenkins-specific privilege escalation checks all - Run all modules OPTIONS: -q, --quiet Quiet mode (minimal output) -v, --verbose Verbose mode (detailed output) -f, --format Output format: text|json|csv (default: text) -h, --help Show this help message EXAMPLES: $SCRIPT_NAME core # Check core permissions $SCRIPT_NAME ec2 -v # Check EC2 with verbose output $SCRIPT_NAME all -f json # All checks in JSON format $SCRIPT_NAME iam --quiet # IAM checks with minimal output EOF } # Verify AWS credentials verify_aws_credentials() { log_info "Verifying AWS credentials..." if ! aws sts get-caller-identity &>/dev/null; then log_error "AWS credentials not configured or invalid" log_error "Please ensure you have configured:" log_error " - AWS Access Key ID" log_error " - AWS Secret Access Key" log_error " - AWS Session Token (if using temporary credentials)" exit 1 fi log_success "AWS credentials verified" } # Get caller identity information get_caller_info() { local caller_arn=$(aws sts get-caller-identity --query 'Arn' --output text) local caller_type=$(echo "$caller_arn" | cut -d':' -f6 | cut -d'/' -f1) local caller_name=$(echo "$caller_arn" | cut -d'/' -f2) local account_id=$(aws sts get-caller-identity --query 'Account' --output text) echo "$caller_type|$caller_name|$account_id|$caller_arn" } # Test a specific permission test_permission() { local service="$1" local action="$2" local test_command="$3" local description="${4:-}" local full_action="${service}:${action}" [[ -n "$description" ]] && full_action="$full_action ($description)" if [[ "$VERBOSE_MODE" == true ]]; then log_info "Testing $full_action..." log_info "Command: $test_command" elif [[ "$QUIET_MODE" == false ]]; then echo -n "Testing $full_action... " fi if eval "$test_command &>/dev/null"; then [[ "$QUIET_MODE" == false ]] && echo -e "${GREEN}✅ Allowed${NC}" [[ "$VERBOSE_MODE" == true ]] && log_success "Permission allowed" return 0 else [[ "$QUIET_MODE" == false ]] && echo -e "${RED}❌ Denied${NC}" [[ "$VERBOSE_MODE" == true ]] && log_warning "Permission denied" return 1 fi } # ============================================================================= # Module Functions # ============================================================================= module_core() { log_info "Running core permissions check..." local caller_info=$(get_caller_info) local caller_type=$(echo "$caller_info" | cut -d'|' -f1) local caller_name=$(echo "$caller_info" | cut -d'|' -f2) local account_id=$(echo "$caller_info" | cut -d'|' -f3) local caller_arn=$(echo "$caller_info" | cut -d'|' -f4) echo "=== AWS Identity Information ===" echo "Identity Type: $caller_type" echo "Identity Name: $caller_name" echo "Account ID: $account_id" echo "Full ARN: $caller_arn" echo echo "=== Core Permissions ===" test_permission "STS" "GetCallerIdentity" "aws sts get-caller-identity" "Current identity" } module_ec2() { log_info "Running EC2 permissions check..." echo "=== EC2 Permissions ===" test_permission "EC2" "DescribeInstances" "aws ec2 describe-instances --max-items 1" test_permission "EC2" "DescribeSecurityGroups" "aws ec2 describe-security-groups --max-items 1" test_permission "EC2" "DescribeVpcs" "aws ec2 describe-vpcs --max-items 1" test_permission "EC2" "DescribeInstanceTypes" "aws ec2 describe-instance-types --max-items 1" test_permission "EC2" "DescribeImages" "aws ec2 describe-images --owners self --max-items 1" test_permission "EC2" "DescribeKeyPairs" "aws ec2 describe-key-pairs --max-items 1" } module_s3() { log_info "Running S3 permissions check..." echo "=== S3 Permissions ===" test_permission "S3" "ListAllMyBuckets" "aws s3 ls" # Test S3 GetObject only if ListBuckets succeeded if aws s3 ls &>/dev/null; then local first_bucket=$(aws s3 ls | head -n 1 | awk '{print $3}' 2>/dev/null) if [[ -n "$first_bucket" ]]; then test_permission "S3" "ListBucket" "aws s3api list-objects --bucket $first_bucket --max-items 1" "List objects in $first_bucket" test_permission "S3" "GetBucketLocation" "aws s3api get-bucket-location --bucket $first_bucket" "Get $first_bucket location" else log_warning "No S3 buckets found to test object-level permissions" fi fi } module_iam() { log_info "Running IAM permissions check..." echo "=== IAM Permissions ===" test_permission "IAM" "ListRoles" "aws iam list-roles --max-items 1" test_permission "IAM" "ListPolicies" "aws iam list-policies --max-items 1" test_permission "IAM" "ListUsers" "aws iam list-users --max-items 1" test_permission "IAM" "GetAccountSummary" "aws iam get-account-summary" test_permission "IAM" "ListAccountAliases" "aws iam list-account-aliases" # Get current identity policies if possible local caller_info=$(get_caller_info) local caller_type=$(echo "$caller_info" | cut -d'|' -f1) local caller_name=$(echo "$caller_info" | cut -d'|' -f2) echo echo "=== Current Identity Policy Information ===" if [[ "$caller_type" == "role" || "$caller_type" == "assumed-role" ]]; then test_permission "IAM" "ListAttachedRolePolicies" "aws iam list-attached-role-policies --role-name $caller_name" "List policies for current role" test_permission "IAM" "ListRolePolicies" "aws iam list-role-policies --role-name $caller_name" "List inline policies for current role" elif [[ "$caller_type" == "user" ]]; then test_permission "IAM" "ListAttachedUserPolicies" "aws iam list-attached-user-policies --user-name $caller_name" "List policies for current user" test_permission "IAM" "ListUserPolicies" "aws iam list-user-policies --user-name $caller_name" "List inline policies for current user" fi } module_ssm() { log_info "Running SSM permissions check..." echo "=== Systems Manager Permissions ===" test_permission "SSM" "DescribeInstanceInformation" "aws ssm describe-instance-information --max-items 1" test_permission "SSM" "ListCommands" "aws ssm list-commands --max-items 1" test_permission "SSM" "DescribeParameters" "aws ssm describe-parameters --max-items 1" test_permission "SSM" "GetParameters" "aws ssm get-parameters --names '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' || true" } module_rds() { log_info "Running RDS permissions check..." echo "=== RDS Permissions ===" test_permission "RDS" "DescribeDBInstances" "aws rds describe-db-instances --max-items 1" test_permission "RDS" "DescribeDBClusters" "aws rds describe-db-clusters --max-items 1" test_permission "RDS" "DescribeDBSubnetGroups" "aws rds describe-db-subnet-groups --max-items 1" } module_ecr() { log_info "Running ECR permissions check..." echo "=== ECR Permissions ===" test_permission "ECR" "DescribeRepositories" "aws ecr describe-repositories --max-items 1" test_permission "ECR" "GetAuthorizationToken" "aws ecr get-authorization-token" } module_cloudwatch() { log_info "Running CloudWatch permissions check..." echo "=== CloudWatch Permissions ===" test_permission "CloudWatch" "ListMetrics" "aws cloudwatch list-metrics --max-items 1" test_permission "CloudWatch" "DescribeAlarms" "aws cloudwatch describe-alarms --max-items 1" test_permission "Logs" "DescribeLogGroups" "aws logs describe-log-groups --max-items 1" } module_jenkins() { log_info "Running Jenkins privilege escalation check..." # Get current caller information local caller_info=$(get_caller_info) local caller_type=$(echo "$caller_info" | cut -d'|' -f1) local caller_name=$(echo "$caller_info" | cut -d'|' -f2) local caller_arn=$(echo "$caller_info" | cut -d'|' -f4) # Check if current session is using a role (required for Jenkins escalation) if [[ "$caller_type" != "role" && "$caller_type" != "assumed-role" ]]; then log_warning "Current session is not using a role (type: $caller_type)" log_warning "Jenkins privilege escalation typically requires role-based access" echo "Current identity: $caller_arn" return 1 fi # Extract the role name from current session local current_role="$caller_name" local admin_policy_arn="arn:aws:iam::aws:policy/AdministratorAccess" echo "=== Jenkins Privilege Escalation Permissions ===" echo "Current Role: $current_role" echo "Full ARN: $caller_arn" echo # Check if this looks like a Jenkins role if [[ "$current_role" =~ jenkins|Jenkins ]]; then log_info "Detected Jenkins-related role name" else log_warning "Current role doesn't appear to be Jenkins-related" log_info "Proceeding with privilege escalation checks anyway..." fi echo echo "=== Current Role Analysis ===" test_permission "IAM" "GetRole" "aws iam get-role --role-name $current_role" "Get current role details" test_permission "IAM" "ListAttachedRolePolicies" "aws iam list-attached-role-policies --role-name $current_role" "List current role policies" test_permission "IAM" "ListRolePolicies" "aws iam list-role-policies --role-name $current_role" "List inline policies for current role" # Test privilege escalation capabilities echo echo "=== Privilege Escalation Tests ===" local can_attach=false local can_put_policy=false local can_create_role=false # Test AttachRolePolicy permission (most critical) echo "Testing IAM:AttachRolePolicy... " if aws iam attach-role-policy --role-name "$current_role" --policy-arn "$admin_policy_arn" &>/dev/null; then echo -e "${GREEN}✅ Allowed - CRITICAL VULNERABILITY!${NC}" can_attach=true # Immediately detach to clean up aws iam detach-role-policy --role-name "$current_role" --policy-arn "$admin_policy_arn" &>/dev/null echo " → Automatically detached policy for safety" else echo -e "${RED}❌ Denied${NC}" fi # Test DetachRolePolicy permission test_permission "IAM" "DetachRolePolicy" "aws iam detach-role-policy --role-name $current_role --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess --dry-run" "Detach policies from current role" # Test PutRolePolicy permission (inline policy creation) echo "Testing IAM:PutRolePolicy... " if aws iam put-role-policy --role-name "$current_role" --policy-name "test-escalation-policy" --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}' &>/dev/null; then echo -e "${GREEN}✅ Allowed - CRITICAL VULNERABILITY!${NC}" can_put_policy=true # Immediately delete the policy aws iam delete-role-policy --role-name "$current_role" --policy-name "test-escalation-policy" &>/dev/null echo " → Automatically deleted test policy for safety" else echo -e "${RED}❌ Denied${NC}" fi # Test CreateRole permission echo "Testing IAM:CreateRole... " if aws iam create-role --role-name "test-escalation-role-$" --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}' &>/dev/null; then echo -e "${YELLOW}✅ Allowed - Potential escalation path${NC}" can_create_role=true # Clean up the test role aws iam delete-role --role-name "test-escalation-role-$" &>/dev/null echo " → Automatically deleted test role for safety" else echo -e "${RED}❌ Denied${NC}" fi # Additional privilege escalation tests test_permission "IAM" "UpdateAssumeRolePolicy" "aws iam update-assume-role-policy --role-name $current_role --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}' --dry-run" "Modify role trust policy" test_permission "IAM" "CreatePolicy" "aws iam create-policy --policy-name test-policy-$ --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"s3:ListBucket\",\"Resource\":\"*\"}]}' --dry-run" "Create new policies" test_permission "IAM" "PassRole" "aws iam get-role --role-name $current_role" "Pass role to services" # Test if we can modify other Jenkins roles (if any exist) echo echo "=== Other Jenkins Roles Check ===" log_info "Searching for other Jenkins-related roles..." if aws iam list-roles --query 'Roles[?contains(RoleName, `jenkins`) || contains(RoleName, `Jenkins`)].RoleName' --output text 2>/dev/null | grep -v "^$" | while read -r jenkins_role; do if [[ "$jenkins_role" != "$current_role" && -n "$jenkins_role" ]]; then echo "Found Jenkins role: $jenkins_role" test_permission "IAM" "AttachRolePolicy" "aws iam attach-role-policy --role-name $jenkins_role --policy-arn $admin_policy_arn --dry-run 2>/dev/null" "Attach policy to $jenkins_role" fi done; then log_info "Completed search for other Jenkins roles" else log_warning "Could not search for other Jenkins roles (insufficient ListRoles permission)" fi echo echo "=== Privilege Escalation Summary ===" if [[ "$can_attach" == true ]]; then log_warning "🚨 CRITICAL PRIVILEGE ESCALATION POSSIBLE! 🚨" echo echo "Critical findings:" echo "- Can attach AdministratorAccess policy to current role" echo "- Current role: $current_role" echo echo "Escalation commands:" echo "1. aws iam attach-role-policy --role-name '$current_role' --policy-arn '$admin_policy_arn'" echo "2. aws sts get-caller-identity # Verify new permissions" echo "3. # You now have full AWS admin access!" echo echo "Cleanup command (to remove escalation):" echo "aws iam detach-role-policy --role-name '$current_role' --policy-arn '$admin_policy_arn'" elif [[ "$can_put_policy" == true ]]; then log_warning "🚨 PRIVILEGE ESCALATION POSSIBLE VIA INLINE POLICY! 🚨" echo echo "Critical findings:" echo "- Can create admin inline policies on current role" echo "- Current role: $current_role" echo echo "Escalation commands:" echo "1. aws iam put-role-policy --role-name '$current_role' --policy-name admin-policy --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}]}'" echo "2. aws sts get-caller-identity # Verify new permissions" echo "3. # You now have full AWS admin access!" echo echo "Cleanup command (to remove escalation):" echo "aws iam delete-role-policy --role-name '$current_role' --policy-name admin-policy" elif [[ "$can_create_role" == true ]]; then log_warning "⚠️ POTENTIAL PRIVILEGE ESCALATION VIA ROLE CREATION" echo echo "Findings:" echo "- Can create new roles (requires additional permissions to escalate)" echo "- Need iam:AttachRolePolicy or iam:PutRolePolicy on new roles to escalate" echo "- May be able to create roles with broader permissions" else log_info "✅ Direct privilege escalation not detected" echo "Current role appears to have limited IAM permissions" echo "Note: This doesn't guarantee safety - other escalation paths may exist" fi } # ============================================================================= # Main Script Logic # ============================================================================= main() { local module="" # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_usage exit 0 ;; -q|--quiet) QUIET_MODE=true shift ;; -v|--verbose) VERBOSE_MODE=true shift ;; -f|--format) OUTPUT_FORMAT="$2" shift 2 ;; core|ec2|s3|iam|ssm|rds|ecr|cloudwatch|jenkins|all) module="$1" shift ;; *) log_error "Unknown option: $1" show_usage exit 1 ;; esac done # If no module specified, show usage if [[ -z "$module" ]]; then show_usage exit 1 fi # Verify AWS credentials verify_aws_credentials echo # Run the specified module(s) case $module in core) module_core ;; ec2) module_ec2 ;; s3) module_s3 ;; iam) module_iam ;; ssm) module_ssm ;; rds) module_rds ;; ecr) module_ecr ;; cloudwatch) module_cloudwatch ;; jenkins) module_jenkins ;; all) module_core echo module_ec2 echo module_s3 echo module_iam echo module_ssm echo module_rds echo module_ecr echo module_cloudwatch echo module_jenkins ;; esac echo log_info "Permission check complete for module: $module" } # Run main function with all arguments main "$@"