Dish Network is the 4th largest mobile provider in the US, with around 8.5 million customers - the majority of those being under the companies "Boost Mobile" brand, which it acquired from Sprint in 2021.
A few weeks ago whilst playing with Boost Mobile's "BoostOne" app I stumbled across a security flaw that allowed access to the account information (including phone number, email, physical address and more), payment details/history, and bill information for any Boost Mobile user. More importantly, the flaw also allowed changing the users PIN, which would allow anyone to port out or "sim swap" the users account! All that is needed to access this information is either the users phone number or their email address!
This vulnerability also appears to have affected customers of Dish Network's new Project Genesis 5G network.
I reached out to Dish Network to report this issue, and whilst their response was far from stellar (that'll be the subject of a future blog post!), it does appear that they fixed the issue within about 10 days of me first reaching out to them. At this point they still haven't confirmed to me that it's been fixed, however the problem no longer exists so it appears that it has been.
Enough intro, lets dig into the vulnerability...
Dish/Boost Mobile use a standard OAUTH-style authentication mechanism, where a username and password are used to generate a long-expiry "Refresh Token", which in turn is used to generate a short-lived "Access Token". In this example we have an refresh token that corresponds to the user 'email@example.com', and we're using this to request an access token.
For simplicity, I've saved this access token in a variable, and the same access token is then used for all future requests. Remember, this access token corresponds to the 'firstname.lastname@example.org' account, so we would only expect it to have access to data for that account.
Using this token, we can make a request for account information. This returns numerous details for the account, including the owners name, address, phone number, email address, etc. Of course as these details are for my own account there's no security issue here - this is information that I would expect to have access to.
What is interesting about this request is the actual request URL itself - it includes the username that the information is being requested for. As the only information returned should be for the user that is logged in it doesn't seem that there should be a need for that parameter to be passed.
If we try the same call without the username parameter, we get an error :
So seemingly the username is being used for the query, it's not just extraneous information in the request.
So what happens if we tried and request information for a different user? Obviously the correct action would be to deny that request. Unfortunately, that's not at all what happened!
In this case we've request account details for a different username (email@example.com), whilst still using the authentication credentials for the initial account. This request should have been denied, but it was NOT! Instead we are given full account details for the other user! This data includes name, email address, physical address, phone number, phone details/IMEI and more.
(Note that in this case both of the accounts being used here are my accounts, however they are completely separate/unrelated accounts. They have separate email address, physical addresses, phone numbers, and even a slightly different surname between the two. Boost Mobile has no way of knowing that these two accounts belong to the same person - for all due purpose these accounts belong to completely separate people)
This type of issue is known as a "Broken Object Level Authorization" (BOLA) vulnerability. The website is correctly enforcing authentication (you require a valid token to access it), however it is not enforcing authorization at the object-level so data for all users can be accessed, not just the user that is authenticated. BOLA is listed at #1 on the OWASP API Security list.
The attack above would require us to first know the email address for the user whos account we were trying to gain information on, but it turns out we don't even need that, as the username parameter can also be passed a phone number.
Once again, this was using a phone number that does not correspond to the authentication token that we're using to make the request.
In addition to the data returned by the 'account' request, we can also request additional details around billing, payments, etc. These use a URL that includes the account ID for the account - which is included in the output above. ("id":"223xxxxxx066").
"Bill" contains details of the users upcoming bill.
"Payment Method" shows the details for the credit card setup to make this next payment - although thankfully only the last 4 digits plus the expiry and not the full number, although the "token" field could also be of interest.
"Payment History" shows details of prior payments, including URLs pointing to further details of those payments including the card used to make them (again, only the last 4 digits/expiry).
To this point we have only been querying information from the API, however there are also multiple fields that can be updated - including the users address, their password (which requires the current password so seemingly can't be abused), and their PIN code! This PIN code is what is used when authenticating to a Boost agent via website chat, social media or the phone, as well as being what is used to port a phone number out of Boost.
Note that while this response says the PIN has been "set up" successfully, it works the same even if a PIN has already been set on the account. Unlike the password, no additional authentication is required to set/change the PIN.
The impact of this flaw is significant. Starting with only an email address or a phone number we are able to reset the PIN number and then port out the phone number - what is commonly known as a SIM Swap Attack, and is commonly used by criminals to bypass 2 factor authentication mechanisms.
Only Boost Mobile?
Dish Network, the parent company behind Boost Mobile, actually owns/runs multiple phone providers in the US, including their new 5G network "Project Genesis"
All of the API URLs above included a "tenant" parameter which was set to "BOOST". Changing this to something else gives an Invalid tenant error, implying that this field is indeed being used to set the provider.
Changing the tenant to "GENESIS" did NOT give this invalid tenant error, but instead simply returned an empty set of results - implying that this issue existed not just for Boost Mobile customers, but also for Project Genesis customers. Unfortunately I don't have access to a Project Genesis phone number/email which would allow me to confirm this, but it does appear that these customers are affected as well.
The empty response is the same as the response that is returned when querying the "Boost" tenant with a phone number (username) that is not a Boost customer - so it's an indication that there is no account for that phone number in the tenant being queried.
Although I have not tested enough to be sure, it does not appear that there is any rate-limiting on this query, meaning it would be feasible to brute-force/enumerate phone numbers using this query looking for valid Boost Mobile customers.
Other Issues with the Boost Mobile website/API
Although the issue described above is by far the most critical issue I've found, there are a number of other issues with the Boost website/API. I'll keep those for another day...
- OWAWP API Top 10 list, with Broken Object Level Authorization at #1 on the list.
- "T-Mobile customer data plundered thanks to bad API" - ARS Technica
- "A Deep Dive On The Most Critical API Vulnerability — BOLA" - Inon Shkedy