IDOR - Broken Authentication
IDOR - Background Info
In our first example, what's stopping someone from checking another user's ID and getting all their information?
This code example demonstrates how this can occur.
The server is taking in the user's id and directly displays that information.
To fix this the server shouldn't believe the user, but rather extract the session ID and check on the backend.
In the case of Serverless checks, the application must have a mechanism to check a signature (JWT)
Forced Browsing
Similar to IDOR, forced browsing can occur if the application exposes a direct reference to a file location
Here an attacker can visit the link and retrieve the image even though it is a private image
UUID - Safe? Think not...
Consider the server accepts arbitrary UUIDs from the user, yet the UUID is too long and random to guess. What can an attacker perform?
When you come across a UUID, it can make it difficult to exploit a potential IDOR situation. To better understand how the UUID is created, try creating a few different users and see what their UUIDs look like. If there doesn't seem to be a specific pattern, you'll need to try enumerating the UUID. Keep an eye out for any faults in the API or CORS misconfigurations that may reveal the UUID, and try different methods to enumerate it and perform IDOR.
One option is to try and find a location the UUID gets leaked.
Other places to look for leaked UUIDs are:
Credit: https://rez0.blog/hacking/cybersecurity/2022/08/18/unpredictable-idors.html
Wayback machine: Archives URLs and pages. Unpredictable IDs are often in the parameters or inside the URL path.
Alien vault OTX: Threat intel that inadvertently archives urls as a part of its feature set. Unpredictable IDs are often in the parameters or inside the URL path.
URLScan: A website scanner for suspicious and malicious URLs. Companies submit data to it. This often contains unpredictable IDs in the parameters or paths.
Common Crawl: Archives URLs and pages. Unpredictable IDs are often in the parameters or inside the URL path.
Google search: Google indexes links that might have IDs in the path or parameters, cache pages that might have IDs on them, and indexes websites (like forums) where people often post URLs or full requests which include IDs.
Github search: Github public repos often include users posting their requests for debugging purposes in the Issues section, hardcoding unpredictable IDs into scripts, etc.
Insider threat - previous employee: A previous employee who used the application on their laptop can look at the logs or local storage of their PC to get the IDs or they could have simply written them down before quitting or after getting fired but before access revocation.
Insider threat - RO user can view ID: A current employee with read-only access in an app can often see unpredictable IDs. If there’s an IDOR via unpredictable IDs, it’s often a form of privilege escalation because the IDOR represents a breach of trust already.
Referrer header: Referrer headers with the ID in the path or GET parameters would leak the ID to other servers
Browser history: Getting access to browser history via physical access or corporate handling of it would leak any IDs in the GET parameters or path
Web logs: Anyone with HTTP (s) logs would have access to any unpredictable IDs in GET parameters or paths. This includes company IT, VPN providers, ISPs, etc.
Unknown or future bug ID leak: Just because the report submitter does not have a current way to leak unpredictable IDs, it doesn’t mean there’s no way. Or that there won’t be a bug in the future that leaks those IDs.
It might not be unpredictable: Any cryptography expert will tell you “random” with computers is very hard. It’s one reason why Cloudflare uses lava lamps. Many “unpredictable” IDs may have a design flaw that leads to predictability.
Clickjacking to steal the ID: Clickjacking can leak unpredictable IDs.
Org-IDs in OAuth buttons: OAuth “Sign in with” buttons can leak the org UUID in the generated URL
Accidental screen share: If you are streaming a video game or sharing your video on Zoom and you alt-tab into an app with unfixed UUID IDORs, the UUID of your org or account would be in the URL and is now fully vulnerable.
Hard-coded IDs: There are sometimes pre-existing hardcoded UUIDs or a dev might add one at a later time directly to the database. For example 00000000-00…
if you face an encoded value, you can test the IDOR vulnerability by decoding the encoded value. if you face a hashed value, you should test whether the hash value is accessible or predictable.
The user id "8f14e45fceea167a5a36dedd4bea2543" may seem like a random and unguessable number, but that may not be the case. It's a common practice to use a hashing function to encrypt user ids before storing them in a database, so this may be the situation here.
As you can see above this is an MD5 hash of the number 7. If an attacker were to take an MD5 Hash of the number “11” they would be able to craft a user id for that user.
Now that we generated an MD5 hash for the integer 11 we can use this to retrieve information from that person's user account.
(source: bugbounty playbook 2)
Another tip to keep in mind is to never assume that the format you see is the only one available. For example, if you come across a UUID, a hash, or an encrypted string, try experimenting with sending an easily guessable number or username instead. This approach worked for John H4X00R, who in an article described how he discovered an encrypted string representing a username. He attempted to send his clear-text username, and to his surprise, it worked. This earned him a $5k reward from Twitter.
Bypassing Validation
https://blog.mert.ninja/idor/
How To Think
When trying to hack an application, it's important to understand how the business works. Don't just blindly change numbers in the API calls without understanding what you're looking for. There are tools that can help you with this, but it's important to think for yourself too.
Whenever you see a new API endpoint that takes an object ID from the user, ask yourself these questions:
- Is this ID connected to a private resource? For example, if the API endpoint is "/api/articles/555", it's likely that the articles are public and accessible to everyone.
It's also important to understand the relationships between resources. For example, understand that "trips" and "receipts" are related and that each trip is connected to a specific user.
Get to know the different roles and groups in the API, such as "user", "driver", "supervisor" and "manager".
Another tip is to use the predictable nature of REST APIs to find more endpoints.
If you come across an endpoint that accesses a resource through a RESTful method, like GET /api/chats/<chat_id>/message/<message_id>, don't be afraid to try experimenting with different HTTP methods, like POST or DELETE.
If you receive an error, try changing the "Content-type" header and see if that makes a difference.
Overall, remember to think critically and not just rely on tools.
How To Test:
The basic way to test for BOLA is to guess the random ID of the object, but this doesn’t always work. The more efficient way would be to perform “Session Label Swapping”:
Identify the session label:
A session label is a generic term to describe every string that is used by the API to identify the logged-in user. The reason I call it a session label and not a session ID or authentication token is that, for BOLA exploitation, it doesn’t matter!Log two session labels from different users:
Create two different users and document their session labels.
For example:
User 1, Hugo=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMTEiLCJuYW1lIjoiSHVnbyIsImlhdCI6MTUxNjIzOTAyMn0.JaTvHH5TbKzgRMa5reRDMiPjHEmPKY8axsu5dFMu5Ao
User 2, Bugo=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMjIiLCJuYW1lIjoiQnVnbyIsImlhdCI6MTUxNjIzOTAyMn0.uXTOzhX1mnYI3TZUSyjWS7qQXfYNn6qw-MehVGAgvpc
Keep them in a .txt file.
Login as user #1, sniff the traffic and find an API call to an endpoint that receives an object ID from the client. For example: /api/trips/e6d84adc-b1c7–4adf-a392–35e5b71f068a/details
Repeat and intercept the suspicious API call.
Change the session label of user #1 to the session label of user #2 — to make a call on behalf of user #2x.
Absorb the result. If you received an authorization error, the endpoint is probably not vulnerable.
If the endpoint returns details of the object, compare the two results and check if they are the same. If they are the same — the endpoint is vulnerable.
- Some endpoints don’t return data. For example, the endpoint “ DELETE /api/users/<user_id>” would only return a status code without data.
It might be a bit more complicated to understand if they are vulnerable or not, but don’t ignore them.
Tips & Tricks:
Object IDs in URLs tend to be less vulnerable. Try to put more effort into IDs in HTTP headers/bodies.
UUID instead of numeric values? Don’t give up!
Use the “session label swapping” technique or find endpoints that return IDs of objects that belong to other users.Always try numeric IDs. If you found that an endpoint receives a non-numeric object ID, like a GUID or an email address, give it a shot and try to replace it with a numeric value (e.g.: replace “inon@traceable.ai“ with the number “100”)
Received 403/401 once? Don’t give up!
It’s not extremely common, but some weird authorization mechanisms only work partially. Try many different IDs. For example: if the endpoint “/api/v1/trips/666” returned 403, run a script to enumerate 50 random IDs from 0001 to 9999.Find the most niche features in the application
Let’s say you found a weird feature to create a customized picture for your profile only during mustache awareness month (it’s June btw), and it performs an API call to
/api/mustache_awarness_month/profile_pics/<avocado_emoji_id>
There’s a very good chance that the developers haven’t thought about authorization there.
How To Bypass Object-Level Authorization:
Wrap the ID with an array.
Instead of {“id”:111} send {“id”:[111]}Wrap the ID with a JSON object
Instead of {“id”:111} send {“id”:{“id”:111}}Try to perform HTTP parameter pollution:
/api/get_profile?user_id=<legit_id>&user_id=<victim’s_id>
OR
/api/get_profile?user_id=<victim’s_id>&user_id=<user_id>
This can work in situations where the component that performs the authorization check and the endpoint itself use different libraries to parse query parameters. In some cases, library #1 would take the first occurrence of “user_id” while library #2 would take the second.
- Try to perform JSON parameter pollution
POST api/get_profile
{“user_id”:<legit_id>,”user_id”:<victim’s_id>}_
OR
POST api/get_profile
{“user_id”:<victim’s_id>,”user_id”:<legit_id>}_
It’s pretty similar to HTTP parameter pollution.
- Find API hosts where the authorization mechanism isn’t enabled. Sometimes, in different environments, the authorization mechanism might be disabled, for various reasons. For example, QA would be vulnerable but production would not.
Autorize
First, to avoid being polluted by resources or URLs that are not inside your scope, we recommend starting by adding new Interception Filters. Go on Interception Filters > Select “Scope items only: (Content is not required) and click on Add filter (be sure to have a scope set in Target > Scope).
Once this is done, open your web browser and create two accounts on your target scope ([attacker] and [victim]). Log on to your [attacker] account and in the Intercept or proxy tab, copy the cookie of your [attacker] session (this may also be a header string like JWT token) and paste the value to the configuration inside the Autorize tab.
You’re now ready to test for IDORs from your [victim] account. On Autorize, click on Authorize is off to start. Autorize can do many things for you, but you also need to work for him 🙂
From your current [victim] account session, try as many things you can on your target: add new data, tamper with your data, delete them, and test all the features, the goal here is to accumulate the maximum number of queries inside the Autorize tab.
Whats going on:
To identify potential IDORs, Autorize uses color highlighting in Authz Status and Unauth Status columns:
Red “bypassed!”: endpoint could be vulnerable to IDOR,
Orange “Is enforced!”: endpoint seems to be protected but look anyway,
Green “Enforced!”: endpoint is clearly protected against IDOR.
Be careful, Autorize displaying many red highlight requests does not mean that all endpoints are systematically vulnerable. There may be false positives, it’s up to you to double-check the output.
Now compare the size of the responses between each query: if it’s the same, go deeper!:
Orig. Len: is the size of the response from our original session (our [victim] account)
Modif. Len: is the response from the same request replayed by Autorize using the [attacker] cookies (automatically replayed by Autorize)
Unauth. Len: this is also the same request as our victim account but without cookies session (to test if the endpoint is vulnerable to Improper Access Control)
Click on the interesting request and check the Request/Response Viewers tab (right):
Modified Response corresponds to the server response to our [victim] request but with our [attacker] cookies. As we can see, much information is displayed and a vulnerability of the IDOR type seems to exist.
The Original Response corresponds to the server response to our original [victim] request. It’s useful to compare the response between our two accounts and to detect false positives.
An unauthenticated Response is the server's response to the request but without any auth cookie.
By using this plugin, you should have a better chance of finding IDOR and Improper Access Control vulnerabilities. Moreover, it allows you to automate some queries and focus on interesting ones.
Resources
Subscribe to my newsletter
Read articles from Shay Rand directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Shay Rand
Shay Rand
I am a Web Application Security Consultant and Pen Tester. I'm currently part of the AppSec team at Maglan - Accenture Security. All Views are my Own.