With my invitation to renniepak's HackerHideout, I got the chance to re-live the bug bounty/hunting thrill that I hadn't felt for some time. I haven't bug hunted for quite a while, so I decided to write a small post about two recent findings that could lead to an account takeover (ATO) and one bonus informative finding that I was so close to escalating to a high, but yet so far.
In this application, organization owners submit information about their company such as legal documents, financial details, and other information for the application owner to review and accept (or decline). An organization owner creates an account with a username and an email address, and then they can further explore the app, and submit the above-mentioned details and documents.
The first way to takeover an account in this application is through a simple IDOR. A user can change their email address without password verification. When submitting an email change, one can see their account's ID being sent along with the email address. Changing this ID to another user's ID will change that other user's email address. The only problem? No one knows another user's ID.
Here comes into play the disregard of security best practices. According to security best practices, user IDs should not be sequential. Rather, they should be randomly generated, UUIDv4 ideally. In our case, the application generates IDs sequentially. This, along with the fact that the email address modification endpoint is susceptible to brute forcing attacks, allows an attacker to change the email address of ALL of the accounts in the application (~1700 accounts). The attacker needs to only fuzz IDs up until their ID. Since the victim's account exists already it has a lower ID.
After changing the email address of the victim to one an attacker owns, they can request a password reset using the victim's username and the new email address.
Is it elegant? No. Is it quiet and under the hood? No. Is it successful? Yes.
This vulnerability is a bug chain that can lead to an account takeover. The bug chain takes advantage of two vulnerabilities that can lead to unauthorized access to the victim's account.
As mentioned, a user can upload any document. This document can either be assigned to one of the user's organizations or just be an uploaded document waiting to be assigned to an organization.
The documents are allowed to have HTML content that gets rendered. Although the application is filtering obvious payloads such as <script>
tags and elements such as onerror
etc. it was failing to catch slightly obfuscated payloads such as <img src="x"/onerror="alert(1)">
. With this, we have achieved a (self-)XSS. But how can we deliver this to another user?
Since there was already an IDOR existing (ATO #1), this is an indication that there might be other authorization issues around the application. It turns out that an attacker can upload an unassigned document to another user's account by modifying the user ID. Then the document is assigned a document ID, which an attacker can view in the request's response.
The only hindrance in this is that an attacker cannot know the user ID of the victim. This severely lowers the severity of the vulnerability, since the attack complexity is set to high. If an attacker knows the victim's user ID, they can then deliver the document URL to the victim, triggering the XSS, once the victim clicks the URL.