Learning about Insecure Direct Object Reference (IDOR)


What is an Insecure Direct Object Reference? Imagine the URL https://api.example.com/api/user/139349 - in which you supply the endpoint with a userid/guid, or some sort of identification and it'll execute & respond. In this case, it's looking for userid 139349. An application that is not vulnerable will not let you change 139349 to another users ID, but if it is vulnerable, the IDOR bug would enable a malicious user to enumerate https://api.example.com/api/user/x & leak users information. So the simple version is, being able to modify/view other users' info from simply changing one value, typically integer value, is an IDOR.

IDOR's exist because of a lack of access control. The developer is not validating you are that USERID and they are happy to allow for any ID supplied. This can result in editing, viewing and destroying information you do not own. Your goal when looking for IDORs is to achieve either of the three.

Over my time as a bug bounty hunter i've reported countless idors resulting in ~250,000,000 details being leaked. IDORs can exist throughout the entire application so it is always suggested that if you see IDs then to always test, even if they are guids or some type of "encrypted id". Look for potential leaks of this ID such as public profile, posts, or look for patterns and see if you can generate your own & run it it through a tool such as Burp Suite's intruder. I once had a case where a certain set of a-z characters were used and I was able to mass-generate valid IDs from a simple script.

Finding IDOR's

IDOR bugs exist in more places than you think, especially on mobile apps! Mobile apps will typically query an API with a users ID and this ID can be manipulated to view any other users' information. An API is designed to take user input such as the users ID, https://api.example.com/user/123456), and process & return information. The endpoint should ensure that the user ID being supplied is actually you but in a lot of cases you will find there is no validation.

Be mindful that one IDOR on an API will more than likely lead to lots more!

Below you can find some common areas you may discover an IDOR vulnerability

  • Look for integer values and test!

    Look at the feature you're testing and what it does. Imagine you are querying for sensitive order information and the request is https://www.example.com/order?order_id=1337. Changing the ID to 1338 will reveal another users order! A great report and finding on this can be found here from our Hackevent: [IDOR] Modifying anyone's Appointment information

    Anytime you see a request and the postdata is JSON, {"userid":"1", "password":"oops"}, always try modifying the userID. In a lot of cases you will discover it is vulnerable. As well as this, you can simply injecting a new parameter name if the userID isn't provided! Before: {password":"oops"}, and after: {"password":"oops","userid":"1"}.

  • However..

    However with that said, don't just look for integer values. Perhaps when updating your profile your username is used instead to validate which profile to update, so simply trying another username you control will let you test for IDOR.

  • Opt out links

    These sometimes just contain a userid arguement to opt out and which can be found in emails they send you, so make sure to signup to all newsletters and test. Being able to just opt out is usually low impact/informative, so make sure to see if you can cause impact from something such as an email leak. Sometimes they will confim the email that has been subscribed/unsubscribed and changing a userID value may reveal another users' email.

  • Updating account settings

    Sometimes when updating your account settings, they'll send your userid as a parameter. Manipulating this can sometimes result in another users profile being edited. Don't forget that if one feature is vulnerable to IDOR then it may be a site-wide issue (and don't forget to check mobile site!). Even if you do not see your ID in the post data, just simply try adding it. id=, uid=, userid=, especially if it is a GraphQL query or JSON post data (if it's PUT).

  • Querying for your information

    The same as above when updating, but imagine you are navigating the web application in a check out process. Seperate requests are made to query for both your delivery address, payment address and saved payment information. When retrieving your information the web application needs to know which information to retrieve and a lot of the time this is controlled via a parameter. Even if you don't see a parameter, try inserting one anyway!

  • Reset password

    Mongobug was able to do this on Uber but instead of a userID, he had to supply the users number. Not hard to obtain though right and earned himself a nice $10k, check it out here: https://hackerone.com/reports/143717. This is what we mean by being able to control input that affects another user via their identifier.

  • Anytime you see some sort of identifier

    This can mean a simple ID (1), or a guid (425d1126-4139-4067-ac68-d9caafdf2b46), or some other value, think about username, email, mobile number, etc. The key is to look for values which identifies you when interacting with the site/API, then to check if you can provide another users ID (your second testing account), and if yes, you have a vulnerability!.

    When faced with GUID-like values sometimes you can discover these from public areas such as posts, avatar URLs. For example imagine you have an IDOR for deleting any photo which you confirmed with two accounts you own, but the ID of the images look like: ID:ac68-d9caafdf2b46. Sometimes when displaying the image this value may be used in the URL, https://cdn-images.example.com/avatar/ac68-d9caafdf2b46/0.jpg. Pay attention to values like this and make a note on where you see it being used.

Another simple test, -1 !

This is mentioned on the SQL injection page but is also revelant here. Simply trying -1 can sometimes uncover a vulnerability. Imagine the request is:

	
POST /updateUser
Host: example.com

user_id=1338&name=test
	

If you were to provide user_id=1338-1 and it was vulnerable, then the code would execute against user_id=1337. The code

$sql = "UPDATE users SET name='test' WHERE id='1338-1'"; will be executed as being user id 1337


Test your knowledge with BugBountyHunter Challenges


Resources

A list of useful websites, blog posts, reports tools to help you.