# [Bug Bounty] Race Condition: Redeeming Single-Use Coupon Multiple Times

Pada kesempatan kali ini saya akan membahas kerentanan yang seringkali terlewat oleh mata telanjang tapi punya impact yang sangat fatal, yaitu **Race Condition**. Kerentanan ini saya temukan pada fitur Redeem Voucher di sebuah platform E-Commerce (mari kita sebut saja [`target.com`](http://target.com)).

Konsep dasarnya sederhana: Satu kode voucher seharusnya cuma bisa dipakai satu kali. Tapi, apa jadinya kalau kita kirim request pemakaian voucher tersebut secara bersamaan dalam hitungan milidetik? Apakah server sempat mencatat bahwa vouchernya "sudah terpakai" sebelum request kedua masuk?

> Seketika saya langsung berpikir, "Kayaknya bisa deh kalau kita paksa server memproses banyak request sekaligus sebelum database sempat melakukan locking."

## The Naive Attempt

Awalnya saya coba cara manual menggunakan **Burp Suite Repeater**. Saya kirim satu request, lalu dengan cepat saya tekan `CTRL+R` dan `GO` lagi.

**Hasilnya? Gagal.** Server [`target.com`](http://target.com) cukup cepat. Request pertama sukses (`200 OK`), dan request kedua langsung ditolak (`400 Bad Request`) dengan pesan "Voucher already redeemed". Ternyata latensi jaringan dan kecepatan klik jari manusia tidak cukup cepat untuk mengalahkan logic check di backend.

Di sini banyak bug hunter menyerah. Tapi sebenarnya, kita hanya butuh alat yang lebih presisi.

## The Bypass: Turbo Intruder

Untuk melakukan bypass pada batasan kecepatan ini, kita tidak bisa mengandalkan Repeater biasa. Kita butuh **Turbo Intruder**, sebuah ekstensi di Burp Suite yang bisa menahan request di level jaringan, lalu melepaskannya secara serentak (paralel).

Strateginya adalah menggunakan teknik **Last-Byte Sync**. Kita akan menahan byte terakhir dari request, membuat koneksi terbuka dan siap ("gated"), lalu melepaskan semuanya dalam waktu bersamaan.

Berikut adalah script Python yang saya gunakan di Turbo Intruder:

```python
def queueRequests(target, wordlists):
    # Membuka 30 koneksi sekaligus
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=30,
                           requestsPerConnection=1,
                           pipeline=False
                           )
    
    # Antrikan 30 request ke dalam 'gate' bernama 'race1'
    for i in range(30):
        engine.queue(target.req, gate='race1')
    
    # Lepaskan semua request secara bersamaan (presisi milidetik)
    engine.openGate('race1')
    engine.complete(timeout=60)

def handleResponse(req, interesting):
    # Catat semua respon ke dalam tabel hasil
    table.add(req)
```

## The Result

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770115388860/8111febb-067a-49bc-8197-6fdbf1253f9c.png align="center")

Setelah script dijalankan, Turbo Intruder mengirimkan 30 request dalam jendela waktu kurang dari 5 milidetik. **Dan hasilnya mengejutkan!**

Alih-alih mendapatkan 1x status `200 OK` dan 29x `400 Bad Request`, saya mendapatkan **5x status 200 OK**. Ini berarti dari 30 request yang "balapan" masuk ke database:

1. Thread 1 cek voucher -&gt; Valid -&gt; Masuk proses potong saldo.
    
2. Thread 2 cek voucher -&gt; Valid (karena Thread 1 belum selesai update DB) -&gt; Masuk proses potong saldo.
    
3. Thread 3 cek voucher -&gt; Valid -&gt; Masuk proses potong saldo.
    
4. dst...
    

Voucher senilai **$10** yang seharusnya cuma bisa dipakai sekali, berhasil saya redeem sebanyak 5 kali, memberikan saya total kredit **$50**. Restriction pada backend berhasil terbypass total karena kegagalan atomisitas.

## Alternative Method: The "No-Code" Way (Burp Repeater)

Buat kalian yang malas buka Python atau tuning script, Burp Suite versi terbaru sebenarnya sudah punya fitur bawaan yang ga kalah sadis: **Parallel Request Grouping**.

Fitur ini memanfaatkan teknik *Last-byte Sync* secara otomatis via UI. Caranya gampang banget:

1. Kirim request voucher tadi ke **Repeater**.
    
2. Duplikasi request tersebut sebanyak 20 kali (`CTRL + R` spamming).
    
3. Klik icon `+` di baris tab, lalu pilih **"Create tab group"**.
    
4. Pilih semua tab yang sudah kita duplikasi tadi, beri nama grup (misal: *Race*), lalu **Create**.
    

**Nah, ini kuncinya:** Di bagian Send options (atas kiri), ubah dari *"Send group in sequence"* menjadi **"Send group in parallel (single connection)"**.

Kenapa harus *single connection*? Karena opsi ini yang paling efektif memicu *packet collision*. Burp akan membuka satu koneksi TCP dan menumpuk semua request di sana, lalu melepas byte terakhir secara serentak.

Tinggal klik **Send Group**, dan *boom!* Kalian akan melihat 20 kolom respon muncul bersamaan. Di kasus saya, teknik UI ini juga sukses memicu 3x redeem ganda tanpa perlu menyentuh satu baris kode pun.

## Remediation

Untuk remediasi, developer harus menerapkan **Pessimistic Locking** (misalnya `SELECT FOR UPDATE` pada database SQL) atau menggunakan operasi atomik. Ini akan memastikan bahwa ketika satu thread sedang membaca/mengubah status voucher, thread lain harus menunggu antrian dan tidak bisa membaca data yang sedang diproses.

Sistem yang sudah di-patch biasanya akan menangani antrian ini dengan benar sehingga hanya 1 request yang sukses, sisanya akan fail.

## Real-World Study Cases

Teori tanpa studi kasus nyata seringkali sulit dibayangkan. Berikut adalah daftar laporan asli (Public Disclosure) di HackerOne yang bisa kamu bedah untuk memahami pola serangan ini di berbagai tingkat keparahan:

**Low Severity (Logic & UI State):**

* [Report 1285538](https://hackerone.com/reports/1285538)
    
* [Report 454949](https://hackerone.com/reports/454949)
    
* [Report 927384](https://hackerone.com/reports/927384)
    

**Medium Severity:**

* [Report 429026](https://hackerone.com/reports/429026)
    

**High Severity (Financial & Integrity Impact):**

* [Report 759247](https://hackerone.com/reports/759247)
    

**Recommended Reading:**

* [Top 25 Race Condition Bug Bounty Reports](https://corneacristian.medium.com/top-25-racecondition-bug-bounty-reports-84f9073bf9e5)
    

*Bagi yang ingin belajar lebih dalam, teknik ini sangat efektif untuk target-target yang melibatkan saldo, kupon, atau limitasi jumlah penggunaan. Happy hacking!*
