Managed policies help AWS users simplify the way permissions are assigned. Periodically, AWS will add new permissions to active policies, which offer a new set of permissions to users. Because these are new permissions to an existing set of policies, users aren't impacted these changes and it doesn't remove any features or capabilities.
In the event that AWS would introduce a change to existing policies that could have adverse impacts on their users such as removing a certain set of permissions from a policy that IAM users, applications or services that leverage those policies, AWS will create a new policy, and deprecate the old legacy on in order to avoid service interruptions. These policies are also sometimes deprecated because they have overprivileged permissions that present security threats to their organization.
Once a policy is deprecated, it will continue to work for all existing users, groups and roles attached to it, but it cannot be attached to any NEW user, group or role. You would see warning informing you that the policy will soon be deprecated.
At Permiso, we often observe environments that leverage overprivileged, deprecated policies. These policies are initially used because they were recommended by tutorials, blogs, vlogs or other articles that are now as dated as the policies themselves. None the less, overprivileged policies can lead to over-privileged identities and they present a significant threat to your organization's security.
In this post, we will compare two policies - AmazonEC2RoleforSSM,
a deprecated version of the now recommended AmazonSSMManagedInstaceCore.
We'll break down why AWS likely deprecated the original policy and how organizations leave themselves vulnerable by continuing to use these deprecated policies.
If you compare both policies side by side, you will notice that the deprecated policy (AmazonEC2RoleforSSM
) has significantly more privileges attached to it than its counterpart. While AmazonSSMManagedInstanceCore
has an extra Permission in ssm:GetParameters, it also removes all the permissions from CloudWatch, EC2, DS, Logs, S3 with changes highlighted below:
The comparison above makes it apparent why the role has been deprecated. By default AmazonEC2RoleforSSM
affects a total of eight AWS services that include:
SSM
SSMMessages
EC2Messages
CloudWatch
EC2
DS
Logs
S3
What is more problematic is the fact that the resource is defined as “*”, meaning all resources on these services will be affected by the policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:DescribeAssociation",
"ssm:GetDeployablePatchSnapshotForInstance",
"ssm:GetDocument",
"ssm:DescribeDocument",
"ssm:GetManifest",
"ssm:GetParameters",
"ssm:ListAssociations",
"ssm:ListInstanceAssociations",
"ssm:PutInventory",
"ssm:PutComplianceItems",
"ssm:PutConfigurePackageResult",
"ssm:UpdateAssociationStatus",
"ssm:UpdateInstanceAssociationStatus",
"ssm:UpdateInstanceInformation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2messages:AcknowledgeMessage",
"ec2messages:DeleteMessage",
"ec2messages:FailMessage",
"ec2messages:GetEndpoint",
"ec2messages:GetMessages",
"ec2messages:SendReply"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cloudwatch:PutMetricData"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstanceStatus"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ds:CreateComputer",
"ds:DescribeDirectories"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:PutObject",
"s3:GetObject",
"s3:GetEncryptionConfiguration",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": "*"
}
]
}
While AmazonSSMManagedInstanceCore
only affects three AWS services, the impact on all resources within those services remains:
SSM
SSMMessages
EC2Messages
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:DescribeAssociation",
"ssm:GetDeployablePatchSnapshotForInstance",
"ssm:GetDocument",
"ssm:DescribeDocument",
"ssm:GetManifest",
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:ListAssociations",
"ssm:ListInstanceAssociations",
"ssm:PutInventory",
"ssm:PutComplianceItems",
"ssm:PutConfigurePackageResult",
"ssm:UpdateAssociationStatus",
"ssm:UpdateInstanceAssociationStatus",
"ssm:UpdateInstanceInformation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2messages:AcknowledgeMessage",
"ec2messages:DeleteMessage",
"ec2messages:FailMessage",
"ec2messages:GetEndpoint",
"ec2messages:GetMessages",
"ec2messages:SendReply"
],
"Resource": "*"
}
]
}
When we were testing some SSM related activities at Permiso, S3 Privileges on AmazonEC2RoleforSSM always troubled us. This policy gives a potential attacker almost all of the permissions and access needed to abuse S3 Buckets as they see fit, with the exception of listing bucket names (ListBuckets
), although any threat actors could utilize different techniques to find the bucket names.
Using this Policy, an Identity can:
List Objects using ListBucket
(not to be confused with ListBuckets
which lists bucket names)
Download or Upload Objects with GetObject
and PutObject
Get Bucket Encryption Configuration (using GetEncryptionConfiguration
)
Get Bucket Location using GetBucketLocation
(this can be easily found by fuzzing the bucket-name on any regions the bucket service is available on)
List/Abort Multipart Download Processes and each part of them using ListBucketMultipartUploads
, ListMultipartUploadParts
, AbortMultipartUpload
So what does all this mean for bad actors that are looking to make lateral moves across a network? Let's walk through some use cases where threat actors can leverage these outdated permissions to access sensitive data.
Assume that we found an SSRF (server-side request forgery) on an instance with IMDSv1, meaning a simple HTTP request can give us the credentials of an instance profile. Also, let's assume that during reconnaissance, we were able to find a bucket name “testbucketpermiso” on “eu-west-3”. This bucket is a private one.
We get access as the IP with a name that looks like an SSM related IP:
We assume this identity has AmazonEC2RoleforSSM
attached to it and start looking at the Bucket’s objects.
S3 has two versions of APIs that it it accesses. This is also apparent on awscli, where you use s3 or s3api as services. s3:ListBucket
is the permission that enables the usage of aws s3 ls:
aws s3 ls s3://bucketname
We’ll use this to list the bucket’s objects instead of s3:ListObjects
, which is the permission that allows bucket listing on the new API (adding —recursive will give all the objects, not just the primary directory objects). It should be noted that s3:ListObjects and s3:ListObjectsv2 also work:
Let’s try to check if the bucket is encrypted:
No encryption found. Let’s grab one of the files using GetObject
(using both s3 and s3api as services):
This way we can get sensitive information from S3 Buckets like configuration files, databases, logs or other sensitive information:
Directory Service is an AWS Managed AD Service. We can federate AD Environments using AD Connect-or.
The Permissions granted on Directory Service include:
List and gather information from Directory Services (AWS Managed and Federated ones from AD Connector) using DescribeDirectories
Create a Computer Account on a Directory using CreateComputer
Again, these permissions are granted for all resources within the service.
In this scenario, we have an EC2 Instance that is domain joined on AWS DS Service with IMDSv1 and AmazonEC2RoleforSSM Role Attached to the Instance Profile.
After getting the credentials we start testing Directory Service. We start with Enumerating Directories using DescribeDirectories
:
With this, we can get the DirectoryID (which we will need later), AD Domain (Name), AD DNS IPs, AD VPCs, Subnets and Regions covered, SSO, OS of Domain Controllers and whether it’s active or not.
Also, we can create machine accounts on AD using CreateComputer. This privilege is added so that the instance connected can automatically create the Machine Account in AD without requiring an administrator to do it. It's likely the reason those privileges were automatically added was so that Instances could be Domain Joined too.
And on the Directory:
This can help with RBCD too, without having to create a machine account from PowerShell. We didn't check to see if it worked when ms-ds-machineaccountquota was 0, because when you create a Directory, it gives you an OU and a user (Admin) that can manage only that OU. RBCD on Domain does not work since AccountNotDelegated
is True, meaning it cannot be delegated.
EC2:DescribeInstanceStatus
is a Privilege that allows an identity to get the state of one or all the instances running on a region. You can get all the instances that are pending, running, shutting-down, terminated, stopping, stopped. This provides insight on what Instance and instance turnover rate an account has.
This doesn't provide other info like OS, IP, Hostname, Domain Joined or not, but you get the idea. Additionally, this info can also be used when trying other enumeration techniques.
One interesting enumeration technique we've observed is using CloudWatch Log Groups to enumerate Services being used. You can choose to collect logs for a specific object like a single Instance or a single Lambda Function, then collect all of them into a Log Group. Log Group itself can be the service, as a form of grouping, but it can be anything. Since the most important services are the ones that are usually monitored, this can give an attacker a picture of the services being used.
AWSEC2RoleforSSM has both DescribeLogGroups
and DescribeLogStreams
, meaning you can list all Log Groups and the Streams inside them to understand what services are being used on an account.
And for each Group we can check its streams:
From this we see that there are at least 4 Services Being used:
Lambda
EC2
DS
Kube
And some service IDs:
Lambda Function Name: testDecryptionFunctionName
AWS DS IDs: d-8067298a1d and d-806729ebdd
EC2 Instance ID: i-02c1c36eaf8a15bd4
Kube Cluster: kubeCluster01
In these examples, we were able to:
List Instances and their status in an account
Get an idea on the services being used on an account
List Directory Services and almost pulled together a Resource Based Constrained Delegation
Got access to List, Download and Upload objects of any bucket in the account that we had the name for.
In conclusion, it’s a lot better to use AmazonSSMManagedInstanceCore
instead of AmazonEC2RoleforSSM
. It goes without saying that AmazonSSMManagedInstanceCore
has some potentially dangerous privileges too, which we'll cover in our next article in this series. For now, make sure to modify the Instance Profile’s Role Policy and break some stuff in the process.