From Accessing Restricted Functionality via URL Found in .js File, to Vertical Privilege Escalation through Modification of the ‘accessLevel’ Value in HTTP Responses on the API

A Story About How We Achieved Super Admin Access Through a Chain of Vulnerabilities, Alhamdulillah

YoKo Kho
HakTrak Cybersecurity Squad
9 min readMar 13, 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 readers interested in a brief summary of this finding (InshaAllah it can saves significant time for readers understanding every flow already) — please kindly see the TL;DR section, and
  • For those who want to learn the execution flow or journey regarding this finding. InshaAllah, it can provide 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 does not have a freely accessible registration feature, in other words, each user (employee) may have to go through several stages to gain access rights.
  • Through searching using the Data Leaks Monitoring Platform, one active credential that can be used was found.
  • Logging in, and only a fairly minimalist menu was found — limited to maintaining personal data.
  • Examining the app.bundle.min.js file obtained after logging in, more than 30 endpoint information were found in the dashboardroutes variable.
  • Accessing each endpoint via URL, and found one endpoint that can be directly accessed (/invite-user), which contains tens of thousands of user data.
  • Creating a new user from the invite user feature and changing the accessLevel value to 99 in the request (this value was also found in the app.bundle.min.js file).
  • Successfully gaining access as a super admin.

1. Accessing https://url_1.xyz-company.com/

While conducting bug hunting activities with Fahad Alamri and Meshari Almalki, we once again encountered a target that only had a login form. In addition to following some initial steps as described in our previous post, we also tried to find other information regarding the possibility of credentials on the Data Leaks Monitoring Platform that could potentially be used to log into the target. Long story short, we found one valid account to use, allowing us to gain a better understanding of the situation within the application.

Figure 1 Login into the Account

When we first logged in, we immediately assumed that this was a regular user account (because the menu was very minimalistic). If we face this situation, we should remember one of the fundamental principles, which is: “where there is a user in an app, there is usually a higher-privileged user tasked with managing all users”. However, the issue arises from our lack of information about this high-privileged user and the menu (including its endpoints) since we only have one regular account.

2. Analyzing .js File — app.bundle.min.js

So, what can we do when facing a limited situation like this — considering we only have 1 account with limited privileges? Technically, there are many things that can be done, some of which are as follows:

  • Try to check for possible broken access control by changing the ID value or by adjusting certain values that are “seemingly” easy to guess (for example, email addresses with common names like admin@target.tld, support@target.tld, and the like).
  • When changing the ID value or those previous values does not work well, then we can try to re-execute with a different HTTP method (for example, if previously executed with POST, try executing with GET). This also applies vice versa.
  • Try to observe and analyze how user sessions are created (whether the created sessions are predictable or not).
  • Attempt some injection testing (for example: SQL Injection, XSS, and the like).
  • Try accessing the protected URL directly from a “low-level” account (but if the endpoint naming is unique, then knowledge of this endpoint information is certainly mandatory).
  • And of course, there are many more things that can be tried. We suggest to readers to visit the Pentester Land portal. They collect many amazing resources.

So, from several testing attempts, it was the access to protected URLs that yielded positive results.

Perhaps there’s one question that arises: “Don’t we need information about the endpoint names, either by viewing them from an admin account or by guessing when developers use easy-to-guess naming conventions?”

Generally, that’s correct. However, we also cannot overlook the situation where developers “may” place all endpoint information in JavaScript, which can be viewed from the client-side — and that’s what happened. So when we logged out, we found a .js file whose size was relatively large, namely 9.354.560 bytes (around 8.91 MB).

Figure 2 Found JS File after Logout
Figure 3 Found JS File after Logout II

While reviewing these .js files, we discovered more than 30 endpoint information in the dashboardroutes variable. Without wait to long, we attempted to log in again and immediately try to access several existing endpoints via URL. And finaly, we found one endpoint that that could be directly accessed (/invite-user), containing tens of thousands of user data.

Figure 4 Some of Endpoints

3. /invite-user Endpoint — Endpoint with over Tens of Thousands User Data

When we visited the /invite-user endpoint, the application immediately displayed a fairly large list of users. This certainly ensures that there is a broken access control issue on the endpoint in question.

Figure 5 Broken Access Control on /invite-user Endpoint

In general, even we only look at the name and email address, it turns out that the information the attacker gets is more than that. Basically when we click on any of the usernames, we will find the phone number, branch, and so on.

Figure 6 User Detail

Departing from this situation, we rushed to try to create new users. The reason is none other than to see whether there is a possibility that the privileges of the user we just created can be increased or not.

4. Create a New User and Attempt to Escalate its Privileges

When we tried to create a user, basically the application sends a request to /api/users with a lot of json data in it.

POST /api/users HTTP/2
Host: api.url_1.xyz-company.com
Content-Length: 340
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Authorization: Bearer <bearer_data_here>
Content-Type: application/json
Accept: application/json, text/javascript, */*; q=0.01
Fngprt: <Fngprt_data_here>
Sec-Ch-Ua-Platform: “macOS”
Origin: https://url_1.xyz-company.com
Referer: https://url_1.xyz-company.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

{“name”:”Test Account”,”email”:”haktrak_test_account@haktrak-xyz.tld”,”userCountryCode”:”966",”contact”:”13374444",”designation”:””,”department”:””,”branch”:””,”country”:”Saudi Arabia”,”accessLevel”:”2",”userLimit”:””,”domains”:””,”organisationId”:”5f**********************”,”orgAdmin”:false,”twoFactor”:false}

If we tried to see the flow that occurred during user creation, we will see the “accessLevel” parameter. To be more certain, we tried to look again at the contents of the .js file that we found previously (in the hope that there would be real information so it wasn’t just speculation).

Figure 7 Super User Admin accessLevel

In short, we find certainty that accessLevel 99 is the access level that represents Super Admin. From here. We also try to create users and study existing demand.

So, here is the sample of modified request:

{“name”:”Test Account”,”email”:”haktrak_test_account@haktrak-xyz.tld”,”userCountryCode”:”966",”contact”:”13374444",”designation”:””,”department”:””,”branch”:””,”country”:”Saudi Arabia”,”accessLevel”:”99",”userLimit”:””,”domains”:””,”organisationId”:”5f**********************”,”orgAdmin”:false,”twoFactor”:false}

Please note that even though there are quite a lot of parameters, our attention is focused on the email and accessLevel parameters only. The reason is quite simple, namely because an email is required to receive the password from the application, and the accessLevel is changed to increase our privileges.

In this situation, we need to change the accessLevel value from 2 to 99 (i.e. Super Admin), and then proceed with sending to the server.

When we try to find the status of the account we have created, we will find that the account already has “Super Admin” status (which should only be able to create manager / maintainer accounts status).

Figure 8 Super Admin Account

Please note: at one point, we discovered that changing accessLevel to 99 didn’t work properly when the user was first created (in other words, the role was reverted to the manager).

If this happens, then we only need to edit the user that has been created, intercept the request, click save (POST Request), and change the accessLevel again to 99. In this way we have succeeded in increasing the privileges of that user to Super Admin.

After the user was successfully created, we rushed to look at the email (because we couldn’t find the form to create a password).

Figure 9 Credentials has been Sent via Email

5. Login with Super Admin Account

After getting the password, we immediately log in. After logging in, the portal asks us to change the password that we created previously (it is of course a very good practice to change the password after first use).

If the password has been changed then we have successfully logged in as Super Admin and have access to all the data contained therein.

Figure 10 Super Admin Dashboard

6. Lesson Learned

As we approach the end of this article, we aim to provide a brief summary in this section. This summary intends to condense several key lessons from this journey, making it more accessible and comprehensible for readers:

  • Sometimes, we may encounter difficulty in finding a way to access the application even after executing several initial steps as outlined in the previous article. When faced with this situation, it is crucial for us to adopt a broader approach, such as trying to find possible credentials that can be used through the Data Leaks Monitoring Platform.
    In this situation, we can utilize related tools (such as ThreatsTracker — our own Intellectual Platform) to assist us in gaining access to the application.
Figure 11 One of ThreatsTracker Dashboard
Figure 12 One of ThreatsTracker Dashboard
  • Remember that “Recon shouldn’t just be limited to finding assets and outdated stuff. It’s also understanding the app and finding functionality that’s not easily accessible. There needs to be a balance between recon and good ol hacking on the application in order to be successful” said @NahamSec while responding to one of @Mongobug’s tweets.
  • It is important for testers to note that they also need to communicate that the discovery of credential leaks is a “finding that also needs to be addressed” by the owner (for example, where the credentials leaked from and how to mitigate them). Simply changing credentials is not a comprehensive solution for a case where user credentials are stolen by malware.
  • It is crucial for testers to analyze .js files processed by the application, both during login, after login, and during logout. In this context, we found a .js file containing detailed information about the application’s endpoints (and access levels), which led to the discovery of an endpoint with access control issues. And in other contexts, there is a possibility that we may find hardcoded sensitive information (such as key) that can be used for further attacks scenario.
  • This write-up also highlights the importance of having credentials to conduct comprehensive testing within a system. An application may seem fine from the outside, but it can be entirely different once logged in with various privileges.

--

--