Payment bypass on Twitch and Roblox
tl;dr: I discovered a vulnerability in the payment service provider Xsolla - used by Twitch, Roblox, and many others - that allowed for nearly free subscriptions/payments. This flaw was reported and fixed through Roblox and Xsolla’s bug programs.
Introduction
I was watching someone do a CTF live on Twitch and after watching a couple of ads I noticed the “Twitch Turbo” feature where for X dollars a month you can skip all ads. There’s also a monthly streamer subscription where for X amount of $ a month you support the streamer and gain emotes/recognition/loneliness/etc.
For mere curiosity - and because I love looking at payment flows and payment logic bypasses - I decided to look at the payment processing system being used.
Novel Payment Bypasses
Generally speaking, payment logic bypasses happen in some of the following instances:
- Attacker can change the payment value of the current purchase state - throughout the payment flow - and perform a successful transaction marking the state as completed:
To avoid data tampering, most modern payment flows perform cryptographic signatures of the payment data. When a POST request gets made toward the payment provider, a signature of these values is also sent - along with the payment values and IDs. Ideally, this signature would be previously calculated server-side after all the parameters have been properly validated, and the server has deemed the payment state valid and untampered with.
There are however instances where that’s not the case - and this signature gets generated client-side, which can be easily intercepted and tampered with by an attacker through javascript breakpoints 1.
- Attacker completes the purchase of a cheaper item and uses its transaction ID to confirm a much more expensive purchase state. This can happen when there are no purchase-state <-> transaction-state correction checks in the backend.
When the user gets redirected to the payment gateway, a payment token 1 is sent. If the gateway does not correlate this token to the payment purchase values, then the user can change the payment value and the Merchant app will only validate if a successful transaction occurred 2.
This can also be performed by establishing two payment states in parallel, one with a cheaper item and the other with a more expensive item. The attacker completes the purchase of a cheaper item and uses the callback payment_token
on the more expensive item - marking that purchase as complete.
- Attacker manipulates parameter (i.e. shipping price) quantities to subtract values from the total amount.
In this case, the attacker takes advantage of the server-side total calculation that is performed given a certain input that has not been properly validated (i.e. shipping price 1).
Payment Gateway
Nowadays most websites outsource payment processing through Payment Gateways (i.e. Stripe, Paypal, etc). This was also the case with Twitch - where the payment processing platform Xsolla was found to be in use.
I clicked on the “Twitch Turbo” (the subscription feature that allows you to skip ads) and multiple payment options showed up in the Xsolla’s iframe.
The following payment flow was analyzed when observing the HTTP requests belonging to the credit card option.
I noticed that the very first requests after clicking on the Credit Card payment method were initializing the payment session through /paystation2/api/directpayment?pid=2449
- where the payment session ID was sent in user_session_id
- and returning a huge piece of JSON response:
Some of these JSON values included the subscription price of 11.99 in fix_projectAmount
, fix_projectAmount_stored
, sum
- as well as other payment information such as receipt email 1 in fix_email
.
The usage of the fixed
wording made me interested in these parameters since it usually represents immutable values associated to the current payment session. Ideally, these values would already be in an immutable state since the payment provider has already assimilated item ID’s (i.e. Twitch Turbo) to the current purchase session ID.
The following interesting parameters were also found in this JSON response:
These values seemingly represent the immutable variables across the payment state. Most of these variables were also found to be existent - and already assigned - within the JSON blob.
Change the state
In an attempt to change the current email address, the parameter [email protected]
was appended to the POST request, but no change in the payment state occurred.
After some enumeration - and taking into account the list of fixed
variables enumerated previously - the [email protected]
parameter effectively changed the fix_email
value:
This showcased the ability to change the values of the current payment state. Especially seemingly fixed values such as email
.
I then attempted to modify all the variables containing the value ”11.99”. After going through all the variable changes, I found that the projectAmount
variable was the only one that would allow a price change without triggering any errors in the payment form.
After filling in the Credit Card information and performing the 1€ purchase, a receipt was generated and a Twitch callback redirect triggered the Twitch Turbo activation (!)
After further analysis of the associated API requests, I figured out that this behavior only occurs in the subscription model payments. This is because Xsolla uses another payment flow for instant purchases with far less variables.
More free stuff
While still trying to figure out if this bug only occurs in the Twitch Xsolla project, I figured I’d try other services that use Xsolla with subscription-based plans.
After some research, the game Roblox was found to be one of them. Apparently, there’s a thing called “Roblox Premium” that allows parents to give their kids a monthly Robux (the Roblox currency) allowance by setting up a subscription-based service:
As it turns out this product was also vulnerable to this type of bug, making it then possible to purchase “Roblox Premium 450” for 0.37€:
Disclosure
Date of Metric | — | |
---|---|---|
Jan 21st, 2024 | Developed payment bypass proof-of-concept on twitch.tv and Roblox ; | |
Jan 21st, 2024 | Reported bug through Roblox ’s bug bounty program; | |
Jan 21st, 2024 | Roblox diverted reporting to Xsolla s bug bounty program; | |
Jan 21st, 2024 | Reported bug to Xsolla using their bug bounty web form; | |
Jan 27th, 2024 | I verify that the vulnerability has been mitigated; | |
Jan 28th, 2024 | Still no response from Xsolla - I email them a support ticket asking for an update; | |
Jan 30th, 2024 | Xsolla responds and apologizes for the delay - indicating issues with a high throughput of tickets; | |
Jan 30th, 2024 | Xsolla rewards me with their max bounty: USD 2k; | |
Feb 7th, 2024 | Roblox thanks me for my submission and confirms the vulnerability has been mitigated - rewards me USD 2.5k; | |
Sep 25th, 2024 | I release this blog post. |