[하루한줄] CVE-2025-5277: AWS MCP Server의 검증 부족으로 인한 Command Injection 취약점
URL
https://github.com/advisories/GHSA-m4qw-j7mx-qv6h
Target
- AWS MCP server
Explain
AI가 AWS CLI 명령어를 실행할 수 있도록 지원하는 AWS MCP 서버 프로젝트에서 발견된 Command Injection 취약점의 세부 정보가 공개되었습니다.
취약점은 클라이언트의 프롬프트를 통해 전달 혹은 생성되는 명령어가 execute_aws_command()
, execute_pipe_command()
등의 함수를 통해 실행되기 전 검증을 수행하는 validate_aws_command()
함수에 존재합니다.
def validate_aws_command(command: str) -> None:
"""Validate that the command is a proper AWS CLI command.
Args:
command: The AWS CLI command to validate
Raises:
CommandValidationError: If the command is invalid
"""
cmd_parts = shlex.split(command)
if not cmd_parts or cmd_parts[0].lower() != "aws":
raise CommandValidationError("Commands must start with 'aws'")
if len(cmd_parts) < 2:
raise CommandValidationError("Command must include an AWS service (e.g., aws s3)")
# Optional: Add a deny list for potentially dangerous commands
dangerous_commands = ["aws iam create-user", "aws iam create-access-key", "aws ec2 terminate-instances", "aws rds delete-db-instance"]
if any(command.startswith(dangerous_cmd) for dangerous_cmd in dangerous_commands):
raise CommandValidationError("This command is restricted for security reasons")
해당 함수는 다음 검증을 수행합니다.
cmd_parts[0].lower() != "aws"
: aws로 시작하는지 확인len(cmd_parts) < 2
: 두 번째 인자가 있는지 확인command.startswith(dangerous_cmd)
: 특정 위험한 명령어에 대한 deny list 검증
그러나 해당 함수에는 Command Injection에 악용될 수 있는 쉘 메타문자나, root, admin과 관련된 민감한 명령어가 포함되어 있는지 검사하지 않습니다.
async def execute_aws_command(command: str, timeout: int | None = None) -> CommandResult:
"""Execute an AWS CLI command and return the result.
...
"""
# ...
# Validate the command
validate_aws_command(command)
# ...
try:
# Split command safely for exec
cmd_parts = shlex.split(command)
# Create subprocess using exec (safer than shell=True)
process = await asyncio.create_subprocess_exec(*cmd_parts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
# ...
validate_aws_command
를 통해 명령어를 검증한 이후에는 shlex.split
을 통해 공백을 기준으로 명령어를 분리한 후 create_subprocess_exec
로 명령어를 실행하는데, shell=True
를 사용하지 않고 *cmd_parts
를 직접 전달하는 방식으로 인해 쉘 메타 문자가 포함된 명령어를 쉘이 해석하는 과정에서 임의의 명령어 삽입이 발생합니다. 이를 악용하는 공격자는 root, admin 등 민감한 유저에 대한 정보 유출, 시스템 설정 파일 유출 등이 가능합니다.
def validate_aws_command(command: str) -> None:
"""Validate that the command is a proper AWS CLI command.
...
"""
#...
# Check regex rules first (these apply regardless of service)
error_message = check_regex_rules(command, service)
if error_message:
raise ValueError(error_message)
# Check against dangerous commands for this service
if service in SECURITY_CONFIG.dangerous_commands:
# Check each dangerous command pattern
for dangerous_cmd in SECURITY_CONFIG.dangerous_commands[service]:
if command.startswith(dangerous_cmd):
# If it's a dangerous command, check if it's also in safe patterns
if is_service_command_safe(command, service):
return # Command is safe despite matching dangerous pattern
# Command is dangerous, raise an error
raise ValueError(
f"This command ({dangerous_cmd}) is restricted for security reasons. "
f"Please use a more specific, read-only command or add 'help' or '--help' to see available options."
)
logger.debug(f"Command validation successful: {command}")
#...
def check_regex_rules(command: str, service: Optional[str] = None) -> Optional[str]:More actions
"""Check command against regex rules.
Args:
command: The command to check
service: The AWS service being used, if known
Returns:
Error message if command matches a regex rule, None otherwise
"""
# Check general rules that apply to all commands
if "general" in SECURITY_CONFIG.regex_rules:
for rule in SECURITY_CONFIG.regex_rules["general"]:
pattern = re.compile(rule.pattern)
if pattern.search(command):
logger.warning(f"Command matches regex rule: {rule.description}")
return rule.error_message
# Check service-specific rules if service is provided
if service and service in SECURITY_CONFIG.regex_rules:
for rule in SECURITY_CONFIG.regex_rules[service]:
pattern = re.compile(rule.pattern)
if pattern.search(command):
logger.warning(f"Command matches service-specific regex rule for {service}: {rule.description}")
return rule.error_message
return None
패치는 기존에 validate_aws_command()
함수 내부에서 쓰였던 dangerous_command
리스트를 config로 분리함해 확장 가능하도록 변경한 동시에 검증할 명령어를 추가하였으며, 정규식을 사용한 검증을 수행하는 check_regex_rules
함수 또한 추가해 검증을 강화하였습니다. 아래는 정규식 검증과 dangerous_command
리스트를 포함하는 config 파일입니다.
- SECURITY_CONFIG (example)
#...
# Commands considered dangerous by security category
# Keys are AWS service names, values are lists of command prefixes to block
dangerous_commands:
# Identity and Access Management - core of security
iam:
# User management (potential backdoor accounts)
- "aws iam create-user" # Creates new IAM users that could persist after compromise
- "aws iam update-user" # Updates existing user properties
# Credential management (theft risk)
- "aws iam create-access-key" # Creates long-term credentials that can be exfiltrated
- "aws iam update-access-key" # Changes status of access keys (enabling/disabling)
- "aws iam create-login-profile" # Creates console passwords for existing users
- "aws iam update-login-profile" # Updates console passwords
# Authentication controls
- "aws iam create-virtual-mfa-device" # Creates new MFA devices
- "aws iam deactivate-mfa-device" # Removes MFA protection from accounts
- "aws iam delete-virtual-mfa-device" # Deletes MFA devices
- "aws iam enable-mfa-device" # Enables/associates MFA devices
# Privilege escalation via policy manipulation
- "aws iam attach-user-policy" # Attaches managed policies to users
- "aws iam attach-role-policy" # Attaches managed policies to roles
- "aws iam attach-group-policy" # Attaches managed policies to groups
- "aws iam create-policy" # Creates new managed policies
- "aws iam create-policy-version" # Creates new versions of managed policies
- "aws iam set-default-policy-version" # Changes active policy version
# Inline policy manipulation (harder to detect)
- "aws iam put-user-policy" # Creates/updates inline policies for users
- "aws iam put-role-policy" # Creates/updates inline policies for roles
- "aws iam put-group-policy" # Creates/updates inline policies for groups
# Trust relationship manipulation
- "aws iam update-assume-role-policy" # Changes who can assume a role
- "aws iam update-role" # Updates role properties
# Security Token Service - temporary credentials
sts:
- "aws sts assume-role" # Assumes roles with potentially higher privileges
- "aws sts get-federation-token" # Gets federated access tokens
# AWS Organizations - multi-account management
organizations:
- "aws organizations create-account" # Creates new AWS accounts
- "aws organizations invite-account-to-organization" # Brings accounts under org control
- "aws organizations leave-organization" # Removes accounts from organization
- "aws organizations remove-account-from-organization" # Removes accounts from organization
- "aws organizations disable-policy-type" # Disables policy enforcement
- "aws organizations create-policy" # Creates organization policies
- "aws organizations attach-policy" # Attaches organization policies
# ---------------------------------------------------------------------------------
# 🔍 Audit and Logging Security Rules
# ---------------------------------------------------------------------------------
# These rules prevent attackers from covering their tracks by:
# - Disabling or deleting audit logs (CloudTrail)
# - Turning off compliance monitoring (Config)
# - Disabling threat detection (GuardDuty)
# - Removing alarm systems (CloudWatch)
# ---------------------------------------------------------------------------------
# CloudTrail - AWS activity logging
cloudtrail:
- "aws cloudtrail delete-trail" # Removes audit trail completely
- "aws cloudtrail stop-logging" # Stops collecting audit logs
- "aws cloudtrail update-trail" # Modifies logging settings (e.g., disabling logging)
- "aws cloudtrail put-event-selectors" # Changes what events are logged
- "aws cloudtrail delete-event-data-store" # Deletes storage for CloudTrail events
# AWS Config - configuration monitoring
config:
- "aws configservice delete-configuration-recorder" # Removes configuration tracking
- "aws configservice stop-configuration-recorder" # Stops recording configuration changes
- "aws configservice delete-delivery-channel" # Stops delivering configuration snapshots
- "aws configservice delete-remediation-configuration" # Removes auto-remediation
# GuardDuty - threat detection
guardduty:
- "aws guardduty delete-detector" # Disables threat detection completely
- "aws guardduty disable-organization-admin-account" # Disables central security
- "aws guardduty update-detector" # Modifies threat detection settings
# CloudWatch - monitoring and alerting
cloudwatch:
- "aws cloudwatch delete-alarms" # Removes security alarm configurations
- "aws cloudwatch disable-alarm-actions" # Disables alarm action triggers
- "aws cloudwatch delete-dashboards" # Removes monitoring dashboards
# Complex pattern matching using regular expressions
regex_rules:
# Global security patterns (apply to all services)
general:
# Identity and authentication risks
- pattern: "aws .* --profile\\s+(root|admin|administrator)"
description: "Prevent use of sensitive profiles"
error_message: "Using sensitive profiles (root, admin) is restricted for security reasons."
# Protocol security risks
- pattern: "aws .* --no-verify-ssl"
description: "Prevent disabling SSL verification"
error_message: "Disabling SSL verification is not allowed for security reasons."
# Data exposure risks
- pattern: "aws .* --output\\s+text\\s+.*--query\\s+.*Password"
description: "Prevent password exposure in text output"
error_message: "Outputting sensitive data like passwords in text format is restricted."
# Debug mode risks
- pattern: "aws .* --debug"
description: "Prevent debug mode which shows sensitive info"
error_message: "Debug mode is restricted as it may expose sensitive information."
# IAM-specific security patterns
iam:
# Privileged user creation
- pattern: "aws iam create-user.*--user-name\\s+(root|admin|administrator|backup|security|finance|billing)"
description: "Prevent creation of privileged-sounding users"
error_message: "Creating users with sensitive names is restricted for security reasons."
# Privilege escalation via policies
- pattern: "aws iam attach-user-policy.*--policy-arn\\s+.*Administrator"
description: "Prevent attaching Administrator policies"
error_message: "Attaching Administrator policies is restricted for security reasons."
- pattern: "aws iam attach-user-policy.*--policy-arn\\s+.*FullAccess"
description: "Prevent attaching FullAccess policies to users"
error_message: "Attaching FullAccess policies directly to users is restricted (use roles instead)."
# Unrestricted permissions in policies
- pattern: "aws iam create-policy.*\"Effect\":\\s*\"Allow\".*\"Action\":\\s*\"\*\".*\"Resource\":\\s*\"\*\""
description: "Prevent creation of policies with * permissions"
error_message: "Creating policies with unrestricted (*) permissions is not allowed."
# Password policy weakening
- pattern: "aws iam create-login-profile.*--password-reset-required\\s+false"
description: "Enforce password reset for new profiles"
error_message: "Creating login profiles without requiring password reset is restricted."
- pattern: "aws iam update-account-password-policy.*--require-uppercase-characters\\s+false"
description: "Prevent weakening password policies"
error_message: "Weakening account password policies is restricted."
# S3 security patterns
s3:
# Public bucket exposure
- pattern: "aws s3api put-bucket-policy.*\"Effect\":\\s*\"Allow\".*\"Principal\":\\s*\"\*\""
description: "Prevent public bucket policies"
error_message: "Creating public bucket policies is restricted for security reasons."
# Disabling public access blocks
- pattern: "aws s3api put-public-access-block.*--public-access-block-configuration\\s+.*\"BlockPublicAcls\":\\s*false"
description: "Prevent disabling public access blocks"
error_message: "Disabling S3 public access blocks is restricted for security reasons."
# Public bucket creation outside approved regions
- pattern: "aws s3api create-bucket.*--region\\s+(?!eu|us-east-1).*--acl\\s+public"
description: "Prevent public buckets outside of allowed regions"
error_message: "Creating public buckets outside allowed regions is restricted."
# EC2 network security patterns
ec2:
# Open security groups for sensitive ports
- pattern: "aws ec2 authorize-security-group-ingress.*--cidr\\s+0\\.0\\.0\\.0/0.*--port\\s+(?!80|443)[0-9]+"
description: "Prevent open security groups for non-web ports"
error_message: "Opening non-web ports to the entire internet (0.0.0.0/0) is restricted."
# Unsafe user-data scripts
- pattern: "aws ec2 run-instances.*--user-data\\s+.*curl.*\\|.*sh"
description: "Detect potentially unsafe user-data scripts"
error_message: "Running scripts from remote sources in user-data presents security risks."
# CloudTrail integrity patterns
cloudtrail:
# Disabling global event logging
- pattern: "aws cloudtrail update-trail.*--no-include-global-service-events"
description: "Prevent disabling global event logging"
error_message: "Disabling CloudTrail logging for global service events is restricted."
# Making trails single-region
- pattern: "aws cloudtrail update-trail.*--no-multi-region"
description: "Prevent making trails single-region"
error_message: "Changing CloudTrail trails from multi-region to single-region is restricted."
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.