A Deep Dive into Exploiting SaaS-Based Company Partnership Management Dashboards through a Chain of Vulnerabilities

From User Registration Bypass to Vertical Privilege Escalation

Fahad Alamrei
HakTrak Cybersecurity Squad
11 min readJan 9, 2024

--

بسم الله الرحمن الرحيم

This write-up is a part of HakTrak Cybersecurity Squad’s research activity.

In this write-up, we’ll present two different approaches:

  • For those seeking only the main points of this finding (InshaAllah it can saves tons of minutes if readers understanding every flow already) — please kindly see the TL;DR section, and
  • For those who need to understand the flow of execution or journey about this finding. InshaAllah, it can tell the readers about some mindsets and hopefully can help people to enrich their insights.

Please kindly enjoy the write-up.

TL;DR

Here are the simple points about this issue:

  • The target utilizes a SaaS for partnership management.
  • The platform comprises two different login pages, namely the partner login (a customer — partner.company.tld) and the organization login (an owner — portal.saas-platform.tld).
  • Bypassing the registration process on the organization’s page was achieved using an endpoint identified on the partner.company.tld.
  • We created a new user within our own entity. Entity ID Hash and Account ID Hash were discovered in the header as a part of access control protection.
  • Search and find the Entity ID Hash and Account ID Hash values on the target’s main partner.company.tld page.
  • We created an administrator account within our entity using the entity ID and account ID hash obtained from partner.company.tld, expecting to find a broken access control issue that would allow us to create an administrator account in that target.
  • Successfully creating an administrator user on the target’s end facilitated effective takeover of the target administrator dashboard.
  • Similarly, potential exists to take over all clients using this SaaS.

0. Introduction

During one of my bug hunting activities at HakTrak with YoKo Kho, we encountered a rather unique entity - a company that using SaaS that specifically focuses in the partnership management sector.

As an overview, this application provides two separate login pages for customer (https://partner.company.tld which redirects to the “https://org-entity-name.saas-platform.tld” endpoint in an HTTP Request) and workers within organizations offering partnership opportunities (https://portal.saas-platform.tld).

1. Application Types and General Login Flow on Partner Pages

As for the initial stage in conducting testing, we start the test from the page provided for partner.

Figure 1 Simple Login Form on partner.company.tld

Like login forms in general, we encountered an interface featuring a login form and an account creation link. In such scenarios, there are several initial steps that a tester can consider, namely:

  • Conducting a file/directory crawling in the partner area.
  • Trying to find login credentials within collaboration tools (such as GitHub, Gitlab, Atlassian products) and similar platforms.
  • Trying to guess potential usage of default credentials (username and password).
  • Performing general tests such as observing responses during random login attempts, executing simple injections, and similar activities.
  • Attempting registration to gain deeper insights into the target’s features, aiding in the identification of possible vulnerabilities.
  • Or other things that can at least help testers in understanding the system better.
Figure 2 Simple MindMap

So what’s the result? Unfortunately, none of the methods we attempted seemed to yield positive results. Even the registration feature doesn’t seem to work.

Why is that? When we tried to register on partner.company.tld (which redirects to “https://org-entityname.saas-platform.tld/api/register” endpoint), the application showed that the registration was successful (because a successful registration message appeared and the registrant was asked to see the email), but apparently there was no confirmation link for us in email.

Note: initially we suspected that there might be certain blocks on free email services (such as Google, Yahoo, Microsoft, etc.), but when we tried to use personal email, the same thing happened, namely no activation link came through.

Starting from here, we tried logging in with the newly created credentials, hoping that the application might not necessitate account activation. Unfortunately, the application notified us that the account remained inactivated. We also attempted a password reset, hoping it might indirectly validate our account, but this approach also didn’t work.

So, at this point, our steps stopped. After that, we temporarily shifted our testing focus to another page, namely the login page designated for employee access (organizations).

2. General Flow on the Employee Page (Organizations)

2.1. Examining the Login Flow at portal.saas-platform.tld

As a reminder, the organization’s employee login page directs users to the https://portal.saas-platform.tld subdomain.

Figure 3 Organization / Employee Login Page

To simplify and shorten the terminology, we’ll refer to the employee login page for the organization as the “organization” page.

On the organization login page, things don’t look any better as the page comes with a captcha and there isn’t even a link to register. Even though in the end we succeeded in bypassing the captcha protection, we first focused on the flow that we had tested first.

Just like on the partner page, we do the exact same test here too.

During an attempt at brute-forcing (which of course starts with submitting a username), we found a very interesting process, namely the application initially verifies the submitted username’s registration status with the host through the following endpoint:

Figure 4 Username Check Feature

If the username is correct, then the application will continue by sending the password. But if not, the app will still ask to enter a valid username value.

Note: technically a flow like this would make the application flow problematic regarding username enumeration issues. However, this problem itself is quite difficult to be exploited if we do not know the list of users registered in it (especially if the user uses a username value that is considered very unique). Whatever the situation, risk is still risk.

2.2. Registration Tests via URL Manipulation

2.2.1. Overview of the Organization Page

There is one qoidah that is quite important for us to hold on to, namely: when a feature is not available on the front-end, it does not mean that the feature is “not available”. The meaning is, it is highly possible that the endpoint is “accessible,” but the feature is not visibly displayed.

By adhering to this qoidah, of course it would be a very wise step if we try to make changes to the URL (let’s say: URL manipulation) to be able to achieve the features we want.

In this situation, we aimed to test the registration feature on the organization page, despite its unavailability. How did we approach this? The simplest way is by “emulating” the flow elsewhere that is also built by the same developer. Why is that? Because there’s a likelihood that developers or companies maintain consistency in their development style across different products. For instance, if product A employs /api/register for registration, it is not impossible that a similar approach is used in product B.

So in this situation, we also add /register/ to user-portal.saas-platform.tld, regardless of whether it is started from the /api/ path or not. Example:

Figure 5 Sample Test I

or

Figure 6 Sample Test II

If you’re wondering, aren’t the login processing endpoints different between organizations and partners? The answer is yes, they are different - evidenced by distinct subdomains. Hence, we attempted to ‘replicate’ the signup endpoint observed in the partner endpoint (which redirects to https://org-entity-name.saas-platform.tld/api/register - refer to chapter 1) on the organization page (a recap URL will be included in the next section).

So what’s the result? Unfortunately, once again, this did not produce positive results. We get the information “resource not found”.

2.2.2. Password Reset Request — “The Key” to Obtaining Different Endpoint

Figure 7 Reset Password Page

Considering that we didn’t find many clues on the login page, we moved on to the next feature, namely the password reset feature. Without access to credentials or knowledge of the registered username, why delve into the password reset feature? Yes, this is where something interesting happens.

In this feature, we found that the endpoint that processes password reset requests is located in a different location, namely https://admin-portal.saas-platform.tld.

Figure 8 Found Different Subdomain

From here, we once more added a path similar to what we did with https://user-portal.saas-platform.tld, namely adding the “register” path. Surprisingly, the response was highly affirmative, prompting us to provide various details including first name, last name, email, and company name.

Figure 9 URL Manipulation

Note: To recap, here are some of the URLs that have been successfully obtained:

2.2.3. Register our Own Account in Organization Page
In the previous result, it can be seen that the application requires JSON data in the form of first name, last name, email, and company. So all we need to do is add these four parameters to the request.

When we have entered all the parameters, we immediately send it to the host. Long story short, our signup attempt succeeded. (despite the application’s refusal to accept registration with email services like Gmail, we utilized free email providers such as fakemailgenerator).

Once all the requisite data is provided and transmitted to the host, it appears that the host acknowledged our request. Surprisingly, an activation link was included in the HTTP Response, prompting concerns about potential exploitation wherein an attacker could appear legitimate by leveraging the company’s domain — although this matter is not the focus of this write-up.

Regardless of whether we use the activation link obtained via email or HTTP Response, we are instantly redirected to the password creation page that can be used to log into the saas-platform.tld service.

3. Login to Organization Dashboard

So, After we fill in the password, it turns out that we are also asked to fill in the name of the subdomain which partner page will later use to carry out activities on the related entity, for example: https://newentity.saas-platform.tld.

Long story short, once all the required details are provided, we’re directed to the employee dashboard page within our own entity. Remember one simple thing, even though this is just our own entity, one of the best is, InshaAllah we will have an overview of each process in this employee’s dashboard.

4. Looking for User Creation Feature

Now that we can access the employee dashboard (within the company we’ve established), InshaAllah, we will have an insight into the application’s functionality. So, what actions should we take next?

Considering our objective to identify potential entry points for taking control of the published company pages via the saas-platform.tld, we are actively exploring user-related feature.

So maybe there is another question, why “user-related” features? Considering that any organization using the saas-platform.tld service primarily logs in at http://portal.saas-platform.tld subdomain (which redirects to http://user-portal.saas-platform.tld/api/login endpoint), identifying potential issues associated with broken access control could potentially allow us to generate users in a different entity.

After looking at the flow of the application a bit, we finally found a feature to create users which is located in the “Settings” -> “User Management” menu.

Note: to make this article more comfortable to read, we have included several sketches in it.

Figure 10 Admin Creation Feature

In this menu, we encounter a functionality allowing the creation of an administrator-level account, limited to managing content within our own registered entity. On the other hand, there’s an option to generate an employee-level account, whose access requirements can be adjusted to existing needs.

Long story short, we instantly created a random administrator user, and we found there are some unique parameters that are difficult to predict, namely the hash (for account and entity). Here is the sample of the request:

Here, we assume that if we succeed in obtaining the two hashes (namely the entity’s ID hash and account ID hash), it might potentially allow us to create an account in another entity. Remember, just a possibility. However, this testing is certainly good to be conducted.

From here, we came back to the home page of the entity we are testing, namely https://partner.company.tld.

5. Looking for Entity ID Hash and Account ID Hash

The initial step upon revisiting the partner-entity page involves inspecting the front-end source using the browser’s ‘view source’ feature. Following this, we search for keywords like ‘-ID’ or ‘account-ID’ (based on the obtained data from the previous request). Surprisingly, we discovered the two things we were looking for, namely the account ID Hash and the entity ID hash.

Figure 11 Found both of HashID

However, we cannot simply celebrate, as there’s no guarantee that this execution will certainly occur.

6. Put the Entity and Account Hash ID into Request on https://admin-portal.saas-platform.tld/api/user

At this stage, having obtained the two Hash IDs, we revisit the request detailed in point 4 of this report.

In summary, we attempt to resend the user creation request, altering specific parameters, namely:

  • Replacing the Account-ID value in the header with the ‘account_id’ value.
  • Substituting the Entity-ID value in the header with the ‘entity_id’ value.

So what’s the result? It turns out that The host accepted this modified request as a valid.

Figure 12 Host Accept the Request

We then checked our email, and we got a valid invitation from the entity that we test. After that, we generated a password using the provided activation link.

Figure 13 Valid Invitation
Figure 14 Create a Password

And after we created our password, we successfully gained control of the partner dashboard of our target. Essentially, using the same method, we could potentially take control of all registered dashboards of other entities.

7. Lesson Learned

As we near the conclusion of this article, we aim to provide a brief recap in this section. This recap aims to summarize a few key lessons from this journey, making it more accessible and comprehensible for readers:

  • When a feature isn’t available on the front-end, it doesn’t necessarily mean that the feature isn’t available. In this case, we found the registration feature within the organization’s subdomain, although it wasn’t readily apparent.
  • There’s a likelihood that developers or companies maintain consistency in their development style across different products. In this case, it’s evident that the developers used the same endpoint for two different application functions.
  • Even though applications might seem to use hashed values or UUIDs that appear difficult to guess, it’s important to remember that there’s a possibility of obtaining this information from one of the publicly accessible pages within the application.

--

--