By Joseph Thacker, Principal AI Engineer, AppOmni
NOTE: This SSO compromise was achievable due to a custom code vulnerability introduced by the service provider. It’s not a vulnerability in Okta as it’s well regarded as a heavily tested and secure product. It is unrelated to the Dec. 2022 Okta breach, the PassBleed risks, or the 0ktapus phishing scam.
As a part of AppOmni Labs research, I achieved a full SSO compromise on a leading service provider’s Okta instance. This compromise effectively achieved read/write access of over 200,000 users and staff, as well as access to 23 applications. This was accomplished by chaining a path traversal vulnerability in an API endpoint with an insecure direct object reference (IDOR) in order to achieve admin account takeover due to a hard-coded service account.
Like all AO Labs exercises, this takeover involved no unauthorized access of other users’ data. We informed the service provider’s team and disclosed the vulnerability immediately. The service provider had a fix in place within a few days.
The API Call That Raised My Suspicions
As a part of routine research, I was proxying normal usage of the application when I noticed a unique API call in burp.
` ` `
POST /content/app/en-us/signin/jcr:content/path/vuln_endpoint HTTP/2
{
“action”: “update”,
“id”: “11qh3i3lrd34kiCIz0x6”,
“account”: {
“email”: “joseph@appomni.com”
}
}
` ` `
Fig.1: Unusual API request
This is interesting for multiple reasons:
- I knew the application was based on Okta, and Okta uses an API scheme that looks completely different for updating users (`/api/v1/users/:id`).
- The request uses an ID to update an object, so it stands out as a time to test for an IDOR.
- There’s potential for mass assignment by adding more account attributes or changing “phone” to something the user shouldn’t be able to change.
- The `jcr:content` part of the path meant this was living on a content server (that is not a part of Okta’s stack).
- The response was returning my user object as json, so if I were to modify or access another user, I would be able to tell.
I immediately wanted to check for an IDOR first. Even though the user ID is hard to obtain, I recently wrote about unpredictable IDORs and how they’re still vulnerabilities.
How I Compromised a Service Provider’s Okta Instance
After asking a coworker to share their user ID so I could validate the vulnerability, I checked if I was able to modify their account details via IDOR, and it worked! The two caveats are that it required knowing their user ID, as mentioned before, and they couldn’t be an account with SMS 2FA enabled. I mentioned it to the AO Labs team and planned to disclose the Okta instance issue to the service provider the next morning.
However, I have been a bug hunter for some time. I know that Okta’s products are heavily tested and secure. Cross-user IDORs are the first thing many hackers check, so I was confident cross-user IDORs weren’t possible in a normal Okta instance. I had a hunch that the call was being made with an admin account — most likely a service account specifically for this use.
I also knew the API calls in Okta usually use the user ID in the path such as: `/api/v1/users/:id`. Since this unusual API endpoint was insecure and likely created ad-hoc for convenience, I thought it might have used the ID parameter as a part of the path. Hence I used a request like this:
` ` `
POST /content/app/en-us/signin/jcr:content/path/vuln_endpoint HTTP/2
{
“action”: “update”,
“id”: “11qh3i3lrd34kiCIz0x6/../00jh3gbn452kb3hja”,
“account”: {
“email”: “joseph@appomni.com”
}
}
` ` `
Fig.2: Path traversal to edit another user’s email
And, once more, it worked! I was traversing up and back down into the path required to update the other user. This didn’t give me any more impact than that of the IDOR I had already found, but it made me realize I should look for other endpoints and SSRF (server-side request forgery).
In playing with the path traversal, I was trying words and paths I’d seen in Okta’s API, such as /sessions, /factors, /authn, etc. I then tried `/../me` and was greeted with a response like this:
“account”: {
“email”: “joseph@appomni.com”,
“login”: “service_account@product.com”,
“username”: “SERVICEACCOUNT”,
“phone”: “555-555-5555”
}
Fig. 3: Changing the service account’s email
The /me endpoint returns the data of the current user. This endpoint had hard-coded credentials of the service account above. And it was an admin because it needed to be able to modify all users.
As you can see, I’d inadvertently changed the email address of the service account. I could have stopped and reported at this point, but if there was MFA on the account, the impact was near zero. If I could log into it, the impact would be Critical.
Since we had a good relationship with the service provider, I decided to also change the login and see if I could login to the account. I wanted to make it clear I was a researcher, so I appended the email address with “+researcher” and went back to login.
How The Service Provider Addressed My Okta Compromise
After logging in, I saw the beautiful blue Okta Admin button. I clicked it, and here’s what I saw:
![Full SSO Compromise - AppOmni Labs Research](https://appomni.com/wp-content/uploads/2024/03/image-full-sso-compromise-1024x567.webp)
Fig. 4: Screenshot of Admin access to the unnamed customer’s Okta instance
I took this screenshot for proof, immediately logged out, and changed the login and email fields back to the service account’s original values.
Methods for Preventing Similar Compromises
Configuring and managing SaaS is difficult. In this case, a major service provider (unnamed) used another SaaS application (Okta) in a unique way by hosting some ad-hoc code on yet another SaaS application (for serving the content). These SaaS-to-Saas connections led to a critical vulnerability.
Your organization likely doesn’t use this exact combination of apps, especially since one is undisclosed. But this type of vulnerability or a similar one can crop up in any SaaS stack. Do you know …
- How many service accounts does your organization use?
- How many of them have full Admin privileges to every user, group, and application in your organization?
- If your organization happened to add custom functionality that a malicious actor could use, would you be able to detect it?
- If a service account has the email address changed, does your organization have a rule to detect that behavior?
These are the types of questions AppOmni can answer for you. We believe in an all-encompassing SaaS security approach – one that validates settings, user permissions, misconfigurations, third party access, and detects threats. Reach out for a demo.
Related Resources
-
The Hidden Security Gaps in Your SaaS Apps: Are You Doing Due Diligence?
Learn about the hidden security gaps in your SaaS apps and what you can do to ensure you’re conducting the due diligence to mitigate these risks and protect the data in your organization.
-
Potential Widespread Data Exposure Analysis: Oracle NetSuite
Read the blog for an analysis on the potential data exposure of Oracle NetSuite with a thorough understanding of NetSuite access control model, basic SuiteCommerce concepts and more.
-
SaaS-Aware Identity Threat Detection and Response (ITDR): Bringing SaaS Awareness to ITDR Solutions
Learn how our SaaS-Aware Identity Threat Detection and Response complements ITDR solutions by putting identity at the forefront of SaaS Security.