Betting Free, Winning More Free
In one of our engagements at Bulletproof we discovered in a betting platform an interesting business logic vulnerability that allowed us to place bets without providing actual money and with a small profit lost. This bug could be repeated continuously to make this small account bigger and would allow a third-party actor to generate infinite money for free.
The bug consisted on 2 security misconfiguration chained together:
- Client-side validation
- Rounding algorithm
Exploitation Process
Client- Side Validation
When auditing a betting platform, the betting functionallity is the core of the business and the place where the impact could be bigger. When playing with the functionallity one step caught our attention. After trying to place a very small amount of money (0.001€) the server replied with the following error at the client-side:
Minimum bet is 0.10€
Perfect, normal behaviour. Intercepting the request with burp we can further analyze the HTTP request:
...
"deposits" : {
"single" : [0.1]
}
...
In the response, we can observe the value Gain that is generated by multiplying the betting quantity * betting odds. In this case 0.10€ * 1.28 = 0.128€.
...
"Gain" : 0.128
...
After trying to place again this small quantity (0.001€), no error is thrown from the server-side, and the response body shows:
...
"Gain" : 0
...
With this, we can confirm that the minimum quantity check is performed only client-side, however, there is no impact on the application right now.
Rounding algorithm
When playing around with small amounts on the betting process we observe that the Gain value is changing. To better understand the behavior, the following table reflects the association betting amount/gain value:
Manual Calculation | Betting Amount | Gain Response | Output in the application |
---|---|---|---|
0.001 * 1.28 = 0.00128 | 0.001 | 0 | Betting amount:0.00€ Gain: N/A |
0.003 * 1.28 = 0.00384 | 0.003 | 0 | Betting amount:0.00€ Gain: N/A |
0.004 * 1.28 = 0.00512 | 0.004 | 0.01 | Betting amount:0.00€ Gain: 0.01€ |
0.007 * 1.28 = 0.00896 | 0.007 | 0.01 | Betting amount:0.01€ Gain: 0.01€ |
The conclusion to be drawn here:
- A betting amount less than 0.005 will reflect on the application
Betting amount:0.00€
. Therefore a rounding algorithm exists on the betting amount. - An odd less than 0.005 will reflect on the application
Gain: N/A
, however an odd equal or greater than 0.005 will reflectGain: 0.01€
. Therefore a rounding algorithm exists on the gain amount.
Therefore, a betting amount less than 0.005 with a Gain greater than 0.00499 will allow betting free with a possibility of winning 0.01€.
However, is this really working? Or this behavior is observed but in the end, our wallet is being decreased accordingly?
If we place 3 bets of 0.004€ = 0.012€, we will see a 0.01€ decrease from our wallet if the application is doing it right.
However, after placing 3 bets, our wallet is not decreased.
Having this scenario, the next step that came to our mind was to place 600 bets to confirm the vulnerability.
200 first team win + 200 drawn + 200 second team win, covering with this all the possible scenarios.
After placing the 600 bets, our wallet was not decreased :)
When the match finished…
We won 2€ as a proof of concept and reported to the client.
I know what you are thinking and yes… we reported to the client…
Greetings from Bahamas.