
문제에서 제공받은 Access Key와 Secret Key를 통해 Profile을 생성하고, sts get-caller-identity 명령을 사용하여 User에 대한 정보를 확인한다.
profile의 이름을 GuardDuty로 설정한 이유는, 해당 시나리오를 풀며 GuardDuty가 위협 탐지를 어디까지 진행할 수 있을지에 대한 테스트를 해보기 위함이였으며 이에 대한 결과는 '공격자가 숨기려는 흔적, GuardDuty는 어디까지 잡을까?' 라는 이름으로 글을 작성해두었다.

solo라는 이름의 User임을 확인할 수 있었으며 시나리오의 목표인 RDS 데이터베이스의 Secret 값 탈취를 위해 해당 User의 Group, Policy, Role 등을 조회하여 동작할 수 있는 권한을 확인해 보기로 했다.
list-groups-for-user, list-attached-user-policies, list-user-policies, list-roles 명령을 통해 Group, Policy, Role 등을 조회해보았지만 모두 권한이 존재하지 않아 User의 정확한 권한을 확인할 수 없었다.




AWS CLI를 통해서 정확히 어떤 서비스가 있는지 확인하기 어렵기 때문에 pacu라는 도구를 사용해보기로 했다.
Pacu 설치 및 세팅
아래 명령을 통해 pacu를 설치한다.
pip3 install -U pacu
설치가 완료되면 pacu 명령을 통해 실행할 수 있다.
실행하면 새로운 세션을 만들거나 기존 세션을 이용할 수 있다. 0을 눌러 새로운 세션의 이름을 지정해주면 세션 생성이 끝난다.

그럼 위와 같이 No Keys Set 이라는 문구가 명령줄에 뜨게되는데, 해당 세션에 현재 설정된 키가 없다는 뜻이다.
키 설정은 set_keys 명령을 통해 진행 가능하다.

등록하는 키의 별칭, Access Key, Secret Key, Session token을 입력하면 키 저장이 끝난다. (Session token은 없으면 None 상태로 엔터를 눌러 넘어가주면 된다.)
아래와 같이 pacu의 iam__bruteforce_permissions 모듈을 이용하여 solo User의 권한을 확인할 수 있었다.

여러 권한이 존재했고, dynamodb와 S3에 대한 권한으로 각각 엔드포인트와 버킷을 조회해보았지만 DynamoDB 공식 리전 엔드포인트와 개인이 직접 생성했던 버킷만 존재하는 것으로 보아 공격에 사용되는 권한은 아닌 것 같았다.


이번에는 list-projects 명령을 통해 Codebuild 프로젝트를 조회해보았고, 하나의 프로젝트가 존재함을 확인하였다.

batch-get-projects 명령으로 해당 프로젝트의 세부 정보를 조회해보았고, 환경 변수 값으로 Access Key와 Secret Key가 노출되어 있는 것을 확인할 수 있었다.

해당 자격 증명을 codebuild라는 이름으로 profile 등록을 하고, sts get-caller-identity 명령을 사용하여 User에 대한 정보를 확인했다.

calrissian 이라는 User의 자격증명임을 알 수 있었으며, 이번에도 list-groups-for-user, list-attached-user-policies, list-user-policies, list-roles 명령을 통해 User의 Group, Policy, Role을 조회해보았다.




하지만 해당 User에게도 IAM 권한이 없어 정보 조회가 불가능했고, 이번에도 pacu의 iam__bruteforce_permissions 모듈을 이용하여 권한을 확인해보았다.

이번에는 RDS에 접근할 수 있는 권한이 존재하는 것을 확인하였고, describe-db-instances 명령을 통해 인스턴스를 조회해보았다.

RDS 인스턴스 조회 전체 출력
~ aws --profile codebuild rds describe-db-instances
{
"DBInstances": [
{
"DBInstanceIdentifier": "cg-rds-instance-cgidxmalpknpde",
"DBInstanceClass": "db.m5.large",
"Engine": "postgres",
"DBInstanceStatus": "available",
"MasterUsername": "cgadmin",
"DBName": "securedb",
"Endpoint": {
"Address": "cg-rds-instance-cgidxmalpknpde.copko4e0q8s4.us-east-1.rds.amazonaws.com",
"Port": 5432,
"HostedZoneId": "Z2R2ITUGPM61AM"
},
"AllocatedStorage": 20,
"InstanceCreateTime": "2025-11-16T04:20:40.311000+00:00",
"PreferredBackupWindow": "10:20-10:50",
"BackupRetentionPeriod": 0,
"DBSecurityGroups": [],
"VpcSecurityGroups": [
{
"VpcSecurityGroupId": "sg-05287e7e4802a61b0",
"Status": "active"
}
],
"DBParameterGroups": [
{
"DBParameterGroupName": "default.postgres17",
"ParameterApplyStatus": "in-sync"
}
],
"AvailabilityZone": "us-east-1a",
"DBSubnetGroup": {
"DBSubnetGroupName": "cloud-goat-rds-subnet-group-cgidxmalpknpde",
"DBSubnetGroupDescription": "CloudGoat cgidxmalpknpde Subnet Group",
"VpcId": "vpc-08c14e6dc94faa02a",
"SubnetGroupStatus": "Complete",
"Subnets": [
{
"SubnetIdentifier": "subnet-0c12025dae85558bc",
"SubnetAvailabilityZone": {
"Name": "us-east-1b"
},
"SubnetOutpost": {},
"SubnetStatus": "Active"
},
{
"SubnetIdentifier": "subnet-09ed27c1056325f38",
"SubnetAvailabilityZone": {
"Name": "us-east-1a"
},
"SubnetOutpost": {},
"SubnetStatus": "Active"
}
]
},
"PreferredMaintenanceWindow": "fri:09:50-fri:10:20",
"PendingModifiedValues": {},
"MultiAZ": false,
"EngineVersion": "17.4",
"AutoMinorVersionUpgrade": true,
"ReadReplicaDBInstanceIdentifiers": [],
"LicenseModel": "postgresql-license",
"OptionGroupMemberships": [
{
"OptionGroupName": "default:postgres-17",
"Status": "in-sync"
}
],
"PubliclyAccessible": false,
"StorageType": "gp2",
"DbInstancePort": 0,
"StorageEncrypted": false,
"DbiResourceId": "db-YJKT2H7LS6NNKJSGGSS57N6CIA",
"CACertificateIdentifier": "rds-ca-rsa2048-g1",
"DomainMemberships": [],
"CopyTagsToSnapshot": false,
"MonitoringInterval": 0,
"DBInstanceArn": "arn:aws:rds:us-east-1:account_id:db:cg-rds-instance-cgidxmalpknpde",
"IAMDatabaseAuthenticationEnabled": false,
"DatabaseInsightsMode": "standard",
"PerformanceInsightsEnabled": false,
"DeletionProtection": false,
"AssociatedRoles": [],
"TagList": [
{
"Key": "Name",
"Value": "cg-rds-instance-cgidxmalpknpde"
},
{
"Key": "Scenario",
"Value": "codebuild-secrets"
},
{
"Key": "Stack",
"Value": "CloudGoat"
}
],
"CustomerOwnedIpEnabled": false,
"ActivityStreamStatus": "stopped",
"BackupTarget": "region",
"NetworkType": "IPV4",
"StorageThroughput": 0,
"CertificateDetails": {
"CAIdentifier": "rds-ca-rsa2048-g1",
"ValidTill": "2026-11-16T04:19:20+00:00"
},
"DedicatedLogVolume": false,
"IsStorageConfigUpgradeAvailable": false,
"EngineLifecycleSupport": "open-source-rds-extended-support"
}
]
}
조회에 성공했지만, PubliclyAccessible 옵션이 false로 설정되어 있기에 외부에서 접근이 불가능 하다는 것을 알게되었다.
아까 solo User의 권한에 EC2 인스턴스 조회, 인스턴스가 위치한 VPC, Subnet 등을 조회할 수 있는 것과 calrissian User의 권한에 RDS 인스턴스 조회, 인스턴스가 위치한 VPC, Subnet 등을 조회할 수 있다는 것에서 두 인스턴스가 같은 VPC에 존재한다면 EC2 인스턴스에서 RDS 데이터베이스에 접근할 수 있을 것이라 예상하였다.
우선 RDS 인스턴스의 VPC는 vpc-08c14e6dc94faa02a라는 것을 확인하였고, 다시 solo User의 권한으로 돌아가 describe-instances 명령을 통해 존재하는 인스턴스를 조회해보았다.

EC2 인스턴스 조회 전체 출력
~ aws --profile guardduty ec2 describe-instances
{
"Reservations": [
{
"ReservationId": "r-080ee46aec2ab327d",
"OwnerId": "account_id",
"Groups": [],
"Instances": [
{
"Architecture": "x86_64",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"AttachTime": "2025-11-16T04:22:20+00:00",
"DeleteOnTermination": true,
"Status": "attached",
"VolumeId": "vol-01b9ec6e058fa6975"
}
}
],
"ClientToken": "terraform-20251116042218869700000005",
"EbsOptimized": false,
"EnaSupport": true,
"Hypervisor": "xen",
"IamInstanceProfile": {
"Arn": "arn:aws:iam::account_id:instance-profile/cg-ec2-instance-profile-cgidxmalpknpde",
"Id": "AIPA6IY35ZX43QZMQVFE2"
},
"NetworkInterfaces": [
{
"Association": {
"IpOwnerId": "amazon",
"PublicDnsName": "ec2-3-80-191-65.compute-1.amazonaws.com",
"PublicIp": "3.80.191.65"
},
"Attachment": {
"AttachTime": "2025-11-16T04:22:19+00:00",
"AttachmentId": "eni-attach-08617fa3e8e0b8d46",
"DeleteOnTermination": true,
"DeviceIndex": 0,
"Status": "attached",
"NetworkCardIndex": 0
},
"Description": "",
"Groups": [
{
"GroupId": "sg-075c01bf89684afb7",
"GroupName": "cg-ec2-ssh-cgidxmalpknpde"
}
],
"Ipv6Addresses": [],
"MacAddress": "0e:74:99:2d:fd:f9",
"NetworkInterfaceId": "eni-0b9471e94d112b0a6",
"OwnerId": "account_id",
"PrivateDnsName": "ip-10-10-10-167.ec2.internal",
"PrivateIpAddress": "10.10.10.167",
"PrivateIpAddresses": [
{
"Association": {
"IpOwnerId": "amazon",
"PublicDnsName": "ec2-3-80-191-65.compute-1.amazonaws.com",
"PublicIp": "3.80.191.65"
},
"Primary": true,
"PrivateDnsName": "ip-10-10-10-167.ec2.internal",
"PrivateIpAddress": "10.10.10.167"
}
],
"SourceDestCheck": true,
"Status": "in-use",
"SubnetId": "subnet-0616001f322a36669",
"VpcId": "vpc-08c14e6dc94faa02a",
"InterfaceType": "interface",
"Operator": {
"Managed": false
}
}
],
"RootDeviceName": "/dev/sda1",
"RootDeviceType": "ebs",
"SecurityGroups": [
{
"GroupId": "sg-075c01bf89684afb7",
"GroupName": "cg-ec2-ssh-cgidxmalpknpde"
}
],
"SourceDestCheck": true,
"Tags": [
{
"Key": "Name",
"Value": "cg-ubuntu-ec2-cgidxmalpknpde"
},
{
"Key": "Stack",
"Value": "CloudGoat"
},
{
"Key": "Scenario",
"Value": "codebuild-secrets"
}
],
"VirtualizationType": "hvm",
"CpuOptions": {
"CoreCount": 1,
"ThreadsPerCore": 1
},
"CapacityReservationSpecification": {
"CapacityReservationPreference": "open"
},
"HibernationOptions": {
"Configured": false
},
"MetadataOptions": {
"State": "applied",
"HttpTokens": "optional",
"HttpPutResponseHopLimit": 1,
"HttpEndpoint": "enabled",
"HttpProtocolIpv6": "disabled",
"InstanceMetadataTags": "disabled"
},
"EnclaveOptions": {
"Enabled": false
},
"PlatformDetails": "Linux/UNIX",
"UsageOperation": "RunInstances",
"UsageOperationUpdateTime": "2025-11-16T04:22:19+00:00",
"PrivateDnsNameOptions": {
"HostnameType": "ip-name",
"EnableResourceNameDnsARecord": false,
"EnableResourceNameDnsAAAARecord": false
},
"MaintenanceOptions": {
"AutoRecovery": "default"
},
"CurrentInstanceBootMode": "legacy-bios",
"NetworkPerformanceOptions": {
"BandwidthWeighting": "default"
},
"Operator": {
"Managed": false
},
"InstanceId": "i-00bb4f5e104c2753b",
"ImageId": "ami-0a313d6098716f372",
"State": {
"Code": 16,
"Name": "running"
},
"PrivateDnsName": "ip-10-10-10-167.ec2.internal",
"PublicDnsName": "ec2-3-80-191-65.compute-1.amazonaws.com",
"StateTransitionReason": "",
"KeyName": "cg-ec2-key-pair-cgidxmalpknpde",
"AmiLaunchIndex": 0,
"ProductCodes": [],
"InstanceType": "t2.micro",
"LaunchTime": "2025-11-16T04:22:19+00:00",
"Placement": {
"GroupName": "",
"Tenancy": "default",
"AvailabilityZone": "us-east-1a"
},
"Monitoring": {
"State": "disabled"
},
"SubnetId": "subnet-0616001f322a36669",
"VpcId": "vpc-08c14e6dc94faa02a",
"PrivateIpAddress": "10.10.10.167",
"PublicIpAddress": "3.80.191.65"
}
]
}
]
}
출력된 결과를 통해 EC2 인스턴스도 RDS 인스턴스와 같은 vpc-08c14e6dc94faa02a에 위치한 것을 확인할 수 있었다. 또한, Public IP가 존재하는 것으로 보아 외부에서 접근할 수 있다는 것도 알게되었다.
이제 외부에서 어떻게 접근이 가능한지 Security Group을 확인해보았고, describe-security-groups 명령을 통해 Security Group의 인바운드 및 아웃바운드 규칙을 확인할 수 있었다.


이를 통해 해당 인스턴스에 SSH 접근이 가능하다는 것을 알게되었다.
그런데 문제가 있다면, EC2에 SSH 접근을 위해서는 Key pair 파일이 필요하다. 하지만 문제에서 따로 제공된 파일도 없고, solo User나 calrissian User에게 EC2 인스턴스를 새로 생성할 권한도 없기 때문에 다른 접근 방법을 찾아야 했다.
그렇게 찾아낸 방법은 AWS Systems Manager를 활용하는 방법이다. Systems Manager는 AWS, 온프레미스, 멀티 클라우드 환경에서의 노드를 중앙에서 확인하고 관리 및 운영할 수 있도록 지원해주는 서비스이다.
AWS Systems Manager이란 무엇인가요? - AWS Systems Manager
Windows Server 인스턴스에서 특정 SSM 문서(예: 레거시 AWS-ApplyPatchBaseline 문서)를 실행하려면 Windows PowerShell 3.0 이상이 필요합니다. Windows Server 인스턴스가 Windows Management Framework 3.0 이상을 실행 중인
docs.aws.amazon.com
해당 서비스는 ssm agent가 설치된 AWS EC2 인스턴스에 접근할 수 있는 Session Manager와 서버와 데이터베이스에 환경 변수나 Secret 값을 관리해주는 Parameter Store 등의 기능을 제공한다.
하지만 처음 이 서비스를 통한 방법을 찾아보았을 때 기존 solo와 calrissian User에게는 관련 권한이 없다는 것이 의심되었다. 그럼에도 해당 방법을 선택한 이유는 pacu가 모든 권한을 확인할 수 있는 것이 아니기 때문이다. Session Start만 해도 target 인스턴스를 지정하여 호출해야 하는 작업이고, Parameter Store 리스트를 호출하는 작업은 아예 pacu 기능에 포함되어 있지 않았다. (github에 업로드된 pacu 코드를 통해 이를 확인하였다.)
이러한 이유로 Systems Manager에 대한 권한은 확인되지 않았기에 직접 CLI에서 실행해보기로 했다.
우선 start-session 명령을 통해 EC2 인스턴스에 접근을 시도해보았고, 해당 동작은 권한이 존재하지 않아 실패하였다.

이번에는 describe-parameters 명령을 통해 존재하는 파라미터 데이터를 조회하였고, 권한이 존재하여 2개의 값을 조회할 수 있었다.

cg-ec2-public-key-cgidxmalpknpde, cg-ec2-private-key-cgidxmalpknpde 총 2개의 파라미터에 대하여 get-parameter 명령으로 값을 읽어보았고


출력값을 통해 SSH 접근에 이용되는 Key pair 파일임을 확인할 수 있었다. 둘 중 cg-ec2-private-key-cgidxmalpknpde의 값을 이용해 key pair 파일을 생성해주었고, 해당 파일을 이용해 EC2 인스턴스에 SSH 접근을 시도했다.

성공적으로 EC2 인스턴스 내부에 접근하였고, RDS에 접근할 수 있지만 접근에 필요한 비밀번호를 모르는 상태이다. 해당 EC2 내부에서 aws 명령을 이용해 EC2 인스턴스의 권한을 확인해보고 싶었지만 solo, calrissian와 마찬가지로 IAM 조회 권한이 존재하지 않아 이번에도 pacu를 활용하게 되었다.
외부에서 사용할 수 있도록 EC2 인스턴스 내부에서 curl http://169.254.169.254/latest/meta-data/iam/security-credentials/cg-ec2-role-cgidqg69sgwxa9 명령을 통해 메타데이터를 호출하였고, 출력받은 STS를 이용해 이전과 같이 iam__bruteforce_permissions 모듈을 이용한 권한 조회를 진행하였다.

Lambda에 대한 권한이 존재하기에 list-functions 명령을 통해 Lambda 함수를 조회하였다.

Lambda 함수가 하나 반환되었으며, 환경 변수에 DB 접속 정보가 노출된 것을 확인하였다.
해당 정보를 이용해 EC2 인스턴스 내부에서 RDS 인스턴스에 접근할 수 있었고, postgreSQL에 저장된 값을 읽어올 수 있었다.

'CloudGoat' 카테고리의 다른 글
| vulnerable_lambda(Medium) Write up (0) | 2025.10.31 |
|---|---|
| iam_privesc_by_attachment(Medium) Write up (0) | 2025.10.30 |
| RDS_snapshot(Medium) Write up (0) | 2025.05.01 |
| iam_privesc_by_rollback(Easy) Write Up (0) | 2025.04.27 |
| SQS_FLAG_Shop(Easy) Write-up (0) | 2025.04.23 |