I know where you had coffee last summer! In this blogpost we will explain an IDOR vulnerability that we found at Starbucks Singapore's website a few weeks ago. This vulnerability would have allowed an attacker to obtain or leak the information of six million Starbucks customers in Singapore. With one million of them including full marketing information such as name, gender, favorite drinks, favorite foods, frequent outlet, usual order time, join date and more. Of course, this information would allow people with bad intentions to carry out a complete profiling of Starbucks customers and even to identify which is a persons favourite Starbucks, potentially impacting physical security, not just virtual.
We have reported the vulnerability to Starbucks as soon as we found it and it has been fixed, preventing this information from leaking and/or being used with malicious intent.
Let's start, what is an IDOR?
Insecure Direct Object References
Insecure direct object references (IDOR) is a type of access control vulnerability that arises when an application uses user-supplied input to access objects directly. A direct object reference is likely to occur when a developer exposes a reference to an internal implementation object, such as a file, directory, or database entry belonging to a specific user, without any validation mechanism, which allows attackers to manipulate these references to access unauthorized data. The term IDOR was popularized by its appearance in the OWASP 2007 Top Ten. However, it is just one example of many access control implementation mistakes that can lead to access controls being circumvented.
Impact of IDOR vulnerabilities
It is not easy to predict the potential impact of an IDOR, since it varies greatly depending on what type of data or files the attacker can access to, but here are some examples of possible impacts:
- Authentication Bypass
- Alteration of Data
- Account Takeover
- Exposure of Confidential/Sensitive Information
How we found an IDOR on Starbucks Singapore's website
Together with HackerOne and Starbucks, we organized a live hacking meetup [https://twitter.com/ylevalle/status/1221190570661511168?s=20] in Buenos Aires, on January 25, 2020. The night before, I was analyzing one of the Starbucks Singapore's websites: campaign.starbucks.com.sg.
It looks like a marketing campaign and it was not particularly interesting, but upon analyzing it, I noticed a bunch of very descriptive error messages that made me wonder if the website might contain a vulnerability:
After realizing that the website was using Node.js I started testing for Node.js bugs, however, those tests were unsuccessful. Then, I logged in with one of the test users I had created for the website and started to analyze the application data flow using Burp Suite.
The site campaign.starbucks.com.sg makes two API calls to authenticate users, the first one to /api/users/login:
Then the application makes another API call, but this time to /api/users/info, supposedly to retrieve user information. The "mid" parameter is not in plaintext this time, it is encoded or encrypted in some way, the response is also encoded or encrypted:
My first idea was to fuzz the parameter "mid" of the second request with invalid values, I did it with Burp Intruder and to my surprise, in most cases the application threw an "AES decryption error". Interesting! So the "mid" value and user information were not encoded, they were encrypted with AES. Then, I decided to test for IDORs using my second test account on the site. After logging into the website with user1, I changed the original "mid" encrypted value of user1 to the corresponding "mid" of user2, as a result, the application successfully responded with the corresponding information from user2, encrypted with AES. That was cool! However, it was not a real attack scenario because... how would I know the encrypted "mid" values of other users? How would I decrypt the user information returned? What could this blob of encrypted data contain?
My approach to solving these problems was to intercept the response from the first POST request and change the plaintext member ID to any other member ID I choose, the step-by-step was as follows:
- Turn on Burp intercept.
- Go to campaign.starbucks.com and log in with my own credentials.
- In the POST request to /api/users/login change the member ID (parameter "mid") of the response for another one, it could be any number between 1 and 6085045 (six million) because member IDs are sequential.
- Forward the POST request to /api/users/info in Burp and grab the value of the variable "data" in the response, which is the variable that contains the encrypted user information.
- Get the returned information of the user decrypted in JSON format.
- Optionally, you can use a JSON beautifier to view the information of the user in a better way.
- Repeat the process with any other user of your choosing.
Performing these tests with my second user account, I realized that the application only returned the name of the corresponding user and all the other fields were empty, but there was really no point in a marketing campaign that only uses the customer name. Remembering that the website was intended as a celebration for reaching one million users, I got the idea of trying member IDs below a million. In this way, I was finally able to get all the complete marketing information of the users: name, gender, favorite drinks, top foods, frequent outlet, join date, usual order time and more.
In addition, I realized that for users whose ID was less than a million, not only I could obtain their information but impersonate them in the application:
Causes of the vulnerability
Analyzing this bug in detail, there are three causes or problems to solve:
The first one is an IDOR in the /api/users/info endpoint call: this call could be made by unauthenticated users to obtain information of any other user on the platform (you can make the API call and obtain the response without being logged in).
The second problem is that, you can also impersonate any user of the platform, just login in with your own credentials but changing the member ID in the response.
Besides, the entropy of the member ID parameter is fairly low because "mid" is a parameter with sequential values, all values between 1 and 6085045 corresponds to users, so using this bug we can obtain information from all users in the Starbucks Singapore database. There is sensitive information for users with "mid" below one million because the information returned includes personal data like name, gender, favorite drinks, favorite foods, frequent outlet where the person usually goes and more.
Impact and Severity of the vulnerability
In terms of impact, through this bug, a malicious attacker could sequentially test Starbucks Singapore member IDs from 6085043 until number 1 to obtain and leak the name of more than six million Starbucks customers in Singapore, one million of them including also full marketing information. After our report, this bug was fixed by Starbucks so it cannot be abused by attackers anymore.
Regarding severity, allowing an information leak of six million Starbucks customers in total, and one million including complete marketing information that allowed people with bad intentions to know even which Starbucks a certain person usually goes to, should be considered high or critical.
Insecure Direct Object References allow attackers to bypass authorization and access resources directly by modifying the value of a parameter used to direct an object. Such resources can be database entries belonging to other users, files in the system and more. This is caused by the fact that the application takes user-supplied input and uses it to retrieve an object without performing sufficient authorization checks. IDORs could appear everywhere, in web applications there are many variables or parameters with a unique value for a unique user. If you change the values of these parameters and you get directed to another user’s data or, changing the parameters change the behavior of the application, then an IDOR bug is present. Therefore it can be exploited and used against the web application.
To prevent this type of vulnerability, the application should verify that the current user has permission to access an object every time access is attempted, to avoid it being accessed by unauthorized users. Moreover, applications should never use client-side encryption.
Security Researcher at Dreamlab Technologies