Secondary Context Leads To Company Takeover.

Berserker
9 min readJan 28, 2025

--

How me and Omar found a secondary context that allowed us to take over the whole company. I will list down what we found within our approach in the target. This research with all the vulnerabilities took us about 3 weeks.

1- Accessed The Admin Dashboard that led us to takeover over 3,000 companies listed down for our target.

2- All The Employees Real Finger Prints, Classified Employees Documents With Their PII.

3- Bypassed The KYC Check Allowed Us To Takeover Phone Numbers.

4- Bypassed Previous Vulnerabilities via Secondary Context.

At first, we are going to explain how we found the vulnerability.

While hunting the target we found an endpoint that returned a weird response when manipulating the request. This error was caused when we added special characters after the path.

Full path.

As you could see In the response it returned a path that seemed interesting. When you observe the path in the request and response it seems somehow similar to each other, but the path in the response seemed longer which at first we indicated that the path in the response is the Backend API. This is an Image to explain it well.

Explaination of Frontend And Backend Paths.

The first thing we thought, and you might be thinking the same, is can we access the backend API somehow?

We instantly tried to access it via path traversal to access the backend API.

As usual, when we tried to path traversal a WAF is blocking us.

However, we didn't stop there. Checked the JS files and found a production domain that doesn’t use a WAF. This domain was a lifesaver for us.

The JS File with the production API.

After we checked, luckily enough it holds the same API and DB of the main domain we were testing.

As soon as we realised it had the same API we tried path traversal to achieve secondary context on the target but we stumbled upon a 404 request that was interesting.

The production domain that holds the same API without WAF.

You will probably ask why is it interesting it's just a 404 Error response, but if we check a 404 request in our target without the path traversal.

Different type of 404 error than the we did path traversal on

This clearly means that we achieved the backend API when the 404 Error was different from the Frontend API.

Now, we made sure that we got what we wanted, but there is something else it feels like we are lost at this point because there is a 404 Response and we don’t know how to access the internal endpoints.

Of course, we tried fuzzing and funny enough it worked!

We found an application.wadl endpoint internally that holds all the internal endpoints for this microservice, which is responsible for the payment system documentation in the Backend API.

An important detail is that these microservices operate on different internal domains, and their mappings are determined by the Frontend API. For example, the path in the frontend API /b2cSRV_NewSim/ maps to the backend API path /company/new/sim. However, the internal domain for this microservice is different, which is an internal domain [http://uat-satellite.redacted.com/]. Keep in mind that this is still in the production domain we found.

The diagrams show how the Frontend API routes requests to internal Backend APIs, revealing internal domains and endpoint structures.
The diagrams show how the Frontend API routes requests to internal Backend APIs, revealing internal domains and endpoint structures.

I explained this because of the application.wadl we found has only been found on one microservice which is one that is responsible for the payment system.

The API endpoints file we found that hold all the endpoints for the microservice.

There is an interesting endpoint which is /extractOrderDocument/{id]/.

We obviously tried requesting the PDF file and it returned a huge file.

The Backend responds with a PDF file from an ID we requested.

Let’s look at what the PDF file holds?

Fingerprints of employees
PII of employees

As you could see we reached documents of internal employees leaking PII and real fingerprints.

While digging into the application.wadl there is a path we found that retrieves all the customers invoices via mobile number through the backend API.

The request retrieves a link via a mobile number. The response is an encrypted link that holds the invoice.
The customer invoice via the link from above.

It retrieves PII for customers via their mobile numbers.

How we get accessed to over 3000 companies that are under the company’s control?

The second week of our research we tried to reach more endpoints but found nothing, and as I explained above the front end path of /soa_b2b_billGen/v1 that only had the listing of all the endpoints of the microservices.

We were completely lost at this, but we kept on digging and fuzzing more!

Tried to take notes of everything we found and it came in handy

These resources helped us to find out a super admin panel.

But we had a problem the response responded back with 405 Method Not Allowed. We changed it to the POST method but the frontend responds with 405 method not allowed either.

Meaning the frontend API only aceepts it as a GET method to be processed through the backend API. It also means that superadmin login will only accept the POST method through the backend.

Explaination of the request method and how it is proccessed to achieve our attack.

So, we need to find a POST request that is vulnerable to secondary context path traversal.

After a long search for a vulnerable POST request, we found it!

Internal superadmin login page

We reached the internal admin login page. It was a moment of both joy and frustration because it required an account.

However, in the response, there was a JavaScript file that we checked, and it contained internal endpoints.

But there was validation in place, meaning we needed to obtain the login credentials; otherwise, we couldn’t do anything.

We thought, why not try some default credentials? Maybe we’d get lucky? Unfortunately, it didn’t work.

Later, we realised that we could perform username enumeration because the error message revealed whether the username was incorrect or if it was just the password.

Username enumeration worked and the error message responds if the username is correct.

When we reached this, we were hoping to get access somehow. Tried brute-forcing with a regular password wordlist and it didn't work.

We started losing hope and were about to give up and move on to something else. But then, we decided to give it one last try.

We thought, why not create a custom wordlist? That’s when we went back to our shared notion, continued working on it, and tried to gather any words related to the company that could help us. We used the GAP extension in Burp Suite to help us gather all the words/parameters.

With the help of ChatGPT, we gathered around 70,000 costume password lists and deduplicated words.

We tried brute forcing again with the costume list we made and it worked!

At that moment we were super excited we obtained the access token of the superAdmin.

Login of superAdmin worked with our costume wordlist.

Now we have full control of the company’s super admin panel meaning we control more than 3,000 companies. Including all of the company’s branches

Super admin dashboard controling over 3000 companies

We can change passwords, National IDs, and any sensitive information.

Ability to change passwords for any company.

Bypassing KYC Checks For Number Transfer Leading To Account And Number Takeover

This is a telecom company meaning if we take over the number it means the user has no longer access to the number.

It involves verifying a customer’s identity to ensure the legitimacy of their request to prevent fraudulent activities such as unauthorized SIM swaps or identity theft.

A key aspect of this process is document verification, where the customer is required to provide official identification to prove their identity.

This may include government-issued IDs such as a passport, national ID card, or driver’s license.

During our testing, when we attempted the original request without interacting with the backend, the system responded with a 417 Expectation Failed error.

This indicates that the request did not meet the system’s KYC check, preventing us from transferring the victim’s number to our document and another telecom operator.

The original request.

After trying to request it via the backend API, it went through and transferred the number with my document to another operator!

Bypassed KYC

We were able to bypass the KYC verification process and successfully transfer any phone number to an attacker’s document and telecom operator of choice.

This is a diagram to explain it perfectly

How were we able to access all user and company data and bypass all previous vulnerabilities?

When we were testing the company we reported a lot of Broken Access Control vulnerabilities and it has been fixed.

Fix for our previous vulnerabilities.

However, We thought why not try to reach the backend API and bypass our previous reports?

Bypassed via the backend API

We requested it via the backend API, and It worked!

With this technique, we bypassed over 20 reports we submitted previously, for anyone wondering the path of the Backend API was obtained by generating an error in the path.

Let’s get into depth why this is happening.

Authentication and authorization checks were only enforced in the Frontend API, allowing us to bypass them entirely by making direct requests to the Backend API.

Explaination of the fix
Diagram of how it was bypassed

Instead of sending a normal request, we used path traversal [../../] to break out of the expected request flow and directly access a sensitive backend endpoint.

The Frontend API saw a normal request and forwarded it without blocking it. However, the Backend API interpreted it differently and returned user data without requiring authentication.

This worked because the Frontend API didn’t perform proper request sanitization, while the Backend API normalized paths differently, leading to a mismatch in how the request was interpreted.

Why this works?

The request we sent looked normal to the Frontend API, so it didn’t block it. But once it reached the Backend API, it got resolved differently.

That’s a wrap! I hope you enjoyed and learned something new. Don’t miss out on what’s coming next follow us on Twitter/X for more exciting updates!

https://x.com/stuipds | https://x.com/Omarzzu

--

--

Responses (3)