Role Abuse: SSM
This page describes how a compromised machine with the default AmazonSSMRoleForInstancesQuickSetup role can allow an attacker to move laterally to all other machines holding this role in the VPC.
Last updated
This page describes how a compromised machine with the default AmazonSSMRoleForInstancesQuickSetup role can allow an attacker to move laterally to all other machines holding this role in the VPC.
Last updated
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.
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's BOF collection to send an HTTP request to the internal metadata API in AWS.
This results in an HTTP response, indicating that this machine holds the AmazonSSMRoleForInstancesQuickSetup role.
Next, we request AWS credentials for this role.
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.
The newly obtained credentials can be used to interact with the AWS APIs programatically, or we can use Rhinosecuritylabs' pacu tool to generate a console link for our convenience. The first step is to create a ~/.aws/credentials file with the credentials:
Next, pacu can be launched via docker, while mounting the AWS credentials in the container.
Next, we can import the AWS credentials and validate our role through the AWS console CLI.
Finally, pacu can generate the console login link to authenticate via a web browser via the following command:
Browsing the URL automagically authenticates as the compromised instance with the AmazonSSMRoleForInstancesQuickSetup role.
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.
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.
Since we already compromised ACTIVEMQ, we will start a session on the only other available machine, DOTNETNUKE.
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) and then download and execute a stageless PowerShell beacon in-memory.
This results in an active Cobalt Strike C2 connection on DOTNETNUKE as the ssm-user from powershell.exe.
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:
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:
For Windows (with some quoted-string-kung-fu)
Finally, list the output for the executed command via the following command (replace the COMMANID with the output of the previous command)
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.
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.
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.