> For the complete documentation index, see [llms.txt](https://blog.pepperclipp.com/pepperclipp-public/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.pepperclipp.com/pepperclipp-public/aws/how-using-deprecated-policies-creates-overprivileged-permissions-amazonec2roleforssm-vs-amazonssmm.md).

# How Using Deprecated Policies Creates Overprivileged Permissions - AmazonEC2RoleforSSM vs AmazonSSMM

## Intro

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.

<figure><img src="/files/frRDRy4RVpJPo4aLlEmQ" alt=""><figcaption></figcaption></figure>

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.

### **Diff-ing 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:

<figure><img src="/files/ZVG8DKHaSE3kbXwoV8Ls" alt=""><figcaption></figcaption></figure>

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": "*"
        }
    ]
}
```

**AmazonEC2RoleforSSM S3 Privileges**

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`

**How Attackers Leverage These Permissions**

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.

## Case Study #1: SSRF on Instances with Meta-Data v1 to All Buckets compromise

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.

<figure><img src="/files/UAOTsbpwZ0AOxnD1imDj" alt=""><figcaption></figcaption></figure>

We get access as the IP with a name that looks like an SSM related IP:

<figure><img src="/files/zfU6H2Dsubi1yvIHZBi6" alt=""><figcaption></figcaption></figure>

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:

<figure><img src="/files/7jrH515WoD3PmJhJiNJ5" alt=""><figcaption></figcaption></figure>

Let’s try to check if the bucket is encrypted:

<figure><img src="/files/kmi0nM09PMFLCBltUrp3" alt=""><figcaption></figcaption></figure>

No encryption found. Let’s grab one of the files using `GetObject` (using both s3 and s3api as services):

<figure><img src="/files/Z6CN7zal23oKAyTbDftw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/pWoBz7bMy9ahBVTqi7I1" alt=""><figcaption></figcaption></figure>

This way we can get sensitive information from S3 Buckets like configuration files, databases, logs or other sensitive information:

<figure><img src="/files/WYSpSSK5GL4Tr5PL1uvE" alt=""><figcaption></figcaption></figure>

### AmazonEC2RoleforSSM Directory Services Privileges

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.

## Case Study #2: Domain Joined EC2 Instance on AWS Directory Service with IMDSv1

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.

<figure><img src="/files/LiLwY3Psn6dbU2izM84V" alt=""><figcaption></figcaption></figure>

After getting the credentials we start testing Directory Service. We start with Enumerating Directories using `DescribeDirectories`:

<figure><img src="/files/maVK7ChDrapCGOqOLJCW" alt=""><figcaption></figcaption></figure>

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.

<figure><img src="/files/c59tslhI8iLR2y2xd1xJ" alt=""><figcaption></figcaption></figure>

And on the Directory:

<figure><img src="/files/1KCQWiJdMz8YufIuchFa" alt=""><figcaption></figcaption></figure>

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.

**Instance and Status Enumeration**

## Case Study Nr.3: Enumerating Instance State using DescribeInstanceStatus

`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.

<figure><img src="/files/GNkZvM7WL2AtwidX3HiB" alt=""><figcaption></figcaption></figure>

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.

### **Service Enumeration through CloudWatch Log Groups**

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.

<figure><img src="/files/DjoYIYCuEKQ3nANViGPZ" alt=""><figcaption></figcaption></figure>

And for each Group we can check its streams:

<figure><img src="/files/i7dOSdAeIuaFBPn7rrgW" alt=""><figcaption></figcaption></figure>

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

## **Conclusion**

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.
