Wizer CTF #30: Tell me who your friends are!
Link to challenge: CTF #30
Goal
In this challenge, we went back to the basics again to uncover and investigate an IDOR (Insecure Direct Object Reference). Did you manage to spot the vulnerability?
Description of code
The code in this challenge is based on a typical friends network within a game. The first endpoint, `api/player`, retrieves a player's record using a numeric ID. The second endpoint, `api/friends`, returns the friends of a specified player based on their ID.
What’s wrong with that approach?
In reviewing the code, we can identify a potential IDOR since there's no authorization mechanism in place.
What would a successful IDOR attack look like in this case?
A successful IDOR attack to retrieve Nikki Hartman's friends could start by sequentially guessing nearby IDs based on one we already know. For example, if our ID is 25010, we could use the `api/player` endpoint to try IDs such as 25009, 25008, 25007, and so on, or 25011, 25012, 25013, and so forth, in an attempt to discover Nikki Hartman's ID. A simple script could be written to automate this brute-force guessing process, speeding up the attack. Once Nikki's ID is found, we can use the `api/friends` endpoint to retrieve her friends list. Too easy, right?
So what?
The example code is missing a crucial element: authorization. Whenever an application accesses, modifies, or deletes data, it must verify that the user making the request is authorized to perform those actions. IDOR vulnerabilities exploit the absence or improper implementation of authorization checks, allowing authenticated users to access data they shouldn't have access to.
Main Takeaways:
-
Always make sure that the user is authorized to access information on the backend:
It is not enough to have a strong authentication on the API level, and it is always required to limit the access of authenticated users to only what they are authorized to access. You might have some UI which blocks it, but always remember that attackers go straight to the backend, putting the client's traffic through a proxy to analyze it directly, hence can easily bypass any frontend protection.
-
Unique IDs aren't a type of security:
In this case the IDs are allocated sequentially, so the guesswork is easy and straightforward. However, even if IDs are harder to guess, i.e. UUID or any other more complex ID structure, always remember that obscurity isn't security, and can never replace a solid authorization. In other words, even if IDs are very complex to guess, there might be other endpoints or data-leaks which will allow an attacker to gain access to other, unauthorized IDs.
-
Secure code starts in good design process:
When designing your application, always consider the security implications of your design. It’s essential to account for not only what should happen in the ideal scenario (the "happy path") but also what should be prevented. For example, in this case, the design should have explicitly stated that the friends function must only return friends of the authenticated user, rather than any user. This would have guided both developers and the QA process to ensure that IDOR (Insecure Direct Object References) vulnerabilities are not possible.
Code Wizer!