Download as pdf
Download as pdf
You are on page 1of 17
51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) In Depth: Insecure Direct Object References (IDOR) [InDepth#11] Also known as hide-and-seek, and security through obscurity! STEPHEN REES.CARTER QO) 02)(6 Sy Share Greetings friends! | hope you enjoyed last week's Security Tip about Leaking Model Existence, and are thinking about areas in your apps that could benefit from adding another layer of security in that area. As promised, this week we're diving into Insecure Direct Object Reference (IDOR) vulnerabilities. | find this a fascinating topic because there are so many options to choose from when preventing IDORs, and many subtle tricks and pitfalls you need to avoid, We'll also be touching on a number of topics we've previously covered, such as Policy Objects, Signed URLs, and Timing Attacks. To help us learn about IDORs, we'll walk through the new challenges on our intentionally vulnerable demo site. (You're going to have a lot of fun with these ones!) In addition to LSID, I'm a Laravel Security Consultant, offering Laravel Security Audits and Penetration Tests. Reach out if you'd like me to hack your app and work with you to improve your security! Laravel Security In Depth is a reader- supported publication. To receive new posts, access our intentionally vulnerable demo site, and support my work, consider becoming a free or paid subscriber. hitps:arasec substack com/pin-depth-insecure-irect-objecteterences "7 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) In Depth: Insecure Direct Object References (IDOR) What is a Insecure Direct Object Reference (IDOR) vulnerability? OWASP defines IDOR as: Insecure Direct Object Reference (called IDOR from here) occurs when a application exposes a reference to an internal implementation object. Using this way, it reveals the real identifier and format/pattern used of the element in the storage backend side. The most common example of it (although is not limited to this one) is a record identifier in a storage system (database, filesystem and so on). IDOR is referenced in element A4 of the OWASP Top 10 in the 2013 edition. The term IDOR became common when OWASP included it in the 2007 Top 10 |. It stayed for the 2013 release, and was merged into Broken Access Control in the 2017 Top 10 This tells us something we should already have guessed: IDOR is an access or authorisation problem. Allowing someone to access something shouldn't have access to is an authorisation problem. You may have noticed I talk about this a lot, but it's so important to get authorisation right. The most common vulnerabilities | find when auditing my client's apps are authorisation problems. Usually they've done everything else right, and just missed one small line, which gives me an opening | need to break in! Maybe they've forgotten to add middleware, or they aren't checking if the user has access to the parent resource. Authorisation problems can manifest in many different ways, but when we're talking about IDORs we're referring specifically to accessing resources that we shouldn't have access to through some form of identifier. We're familiar with using IDs, Slugs, Hashids, and UUIDs, as different identifiers that we can use for requesting resources in our apps. hitps:arasec substack com/pin-depth-insecure-irect-objecteterences aur 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) Many of these can be easily guessed, or found, and when requests made for these identifies aren't properly authorised, we have an IDOR. Some IDORs may not expose anything beyond the existence of a record, while others could leak sensitive data or Personally Identifiable Information (PII), or even the leak entire database! | even had one that allowed me to login as any user 2. Do Try This At Home! In this post we're going to explore some different examples of IDORs, based off different examples I've seen in the wild, To aid with this exploration, I've built 5 new challenges into intentionally vulnerable demo site! You've got three options: 1. You can either stop reading the post and work through the challenges on your own first, and then come back when you've finished to read the post. 2. Alternatively, you can work through the challenges while reading the post. A guided tour, as such. @ 3. Or you can just read the post and skip the challenges. I'll include screenshots and solutions, so you'll know what's going on with each challenge. Demo site: https://larasec.evilhacker.dev/ Username: idor Password: nytuo-ev2qc-@vpzy-y2qea Ifyou have any trouble getting access, reach out and I'll give you a hand. Please be aware of other users to the demo site and limit any brute-force attempts and run them slowly. Thanks! Challenge #1 - Basic IDOR hitps:arasec substack com/pin-depth-insecure-irect-objecteterences a7 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) A developer has built a list of Hobbits within the database. Each logged-in user is automatically assigned two Hobbits, and they are only allowed to view the email addresses of the two Hobbits they are assigned To solve this problem, our friendly developer has implemented a link for each Hobbit which displays their email address when clicked. They've set the app to only display the link for the user's assigned Hobbits, to prevent users clicking links they should not have access to. Challenge #1: View the email addresses of all four Hobbits within the database. We're presented with the following list of Hobbits: The Hobbits *° Frodo * sem © Merry * Pippin e viewed 0 of 4 hobbits. ( As per the brief, we have Sam and Pippin underlined to indicate they are links. Frodo and Merry are not underlined and are not links. When clicking on the Sam link, we are shown Sam’s email address: hitps:arasec substack com/pin-depth-nsecure-irect-objecteterences an7 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) The Hobbits © Frodo © Sam (sam@evilhacker.dev) © Mery + Pippin You've viewed 1 of 4 hobbits. We can also see the URL of the page has been updated to be: https: //larasec.evilhacker.dev/idor?email=Sam The name in the URL should be a massive hint for what we need to do. Clicking on the Pippin link confirms it: https: //larasec.evilhacker.dev/idor?email=Pippin So next up we'll change Pippin for Frodo and see what happens https: //larasec.evilhacker.dev/idor?email=Frodo hitps:arasec substack com/pin-depth-insecure-irect-objecteterences sar 573723, 408 PM (@) In Depth: Insecure Direct Object References (IDOR) The Hobbits * Frodo (frodo@evilhacker.dev) * sam © Mery © Pippin Youve viewed 3 of 4 hobbits. (reset) Updating the URL gives us the final Hobbit we need to collect: https://larasec.evilhacker.dev/idor?email=Merry rene ek lated Click here to proceed to the second challenge... The Hobbits * Frodo * Sam * Merry (merry@evilhacker.dev) * Pippin Youve viewed 4 of 4 hobbits. (reset) nps:/larasec,substack.com/pi-deptnsecure-direct-abject-eferences ear 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) The Fix Although using the names in the URL made it trivial to find the next record, it's not an inherently insecure design, rather it depends on the use case. If these links are only accessed within the context of a user who has been assigned to view 2 of the links, then keeping the names as URL keys and locking access upon request would work well. If we're talking about database models, | would reach for Policy Objects or Gates to add in the needed authorisation. Although even a simple abort_unless() ina controller action would work. There is clearly logic in the view toggling when links are displayed, and this logic should be implemented when the request comes in too 3. Challenge #2 - Numeric IDOR It was pointed out to our eager and well-meaning developer that the URL can be changed to view the email address of any Hobbit. So they've made a subtle change - using the User ID, instead of the Email address. Challenge #2: View the email addresses of all four Hobbits within the database. @ We're presented with the same list of Hobbits as the first challenge - only with Frodo and Sam linked instead. Since it was the key in the last challenge, let's take a look at the two URLs we've got for viewing Frodo and Sam: https://larasec.evilhacker.dev/idor/two?id=24 https: //larasec.evilhacker.dev/idor/two?id=35 The reference has been switched from the name to a number. Since they are both numbers and both close together, it suggests we're dealing with a numeric increment ID. hitps:arasec substack com/pin-depth-insecure-irect-objecteterences m7 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) Finding the other two links is just a case of trying all IDs between two reasonable upper and lower limits. Let's pick 1 and 50: https: //larasec.evilhacker.dev/idor/two?id=1 https: //larasec.evilhacker .dev/idor/two?id=2 https: //larasec.evilhacker.dev/idor/two?id=3 https: //larasec.evilhacker.dev/idor/two?id=11 https: //larasec.evilhacker.dev/idor/two?id=12 https: //larasec.evilhacker.dev/idor/two?id=13 -> Pippin https: //larasec.evilhacker.dev/idor/two?id=14 https://larasec.evilhacker.dev/idor/two?id=15 https: //larasec.evilhacker.dev/idor/two?id=24 -> Frodo https: //larasec.evilhacker.dev/idor/two?id=35 -> Sam https://larasec.evilhacker.dev/idor/two?id=45 https: //larasec.evilhacker.dev/idor/two?id=46 -> Merry https: //larasec.evilhacker.dev/idor/two?id=47 https: //larasec.evilhacker.dev/idor/two?id=48 https://larasec.evilhacker.dev/idor/two?id=49 https: //larasec.evilhacker.dev/idor/two?id=50 This is easily scripted and with a small range, in this case we were only checking 50, it wouldn't take long to do. Add in a half-second delay between each hit and it shouldn't cause excessive traffic either 4 As an easy way to figure this one out, you'll notice each ID is 11 numbers apart. 13, 24, 35, 46.@ Once you visit all four Hobbits, you'll be able to proceed to the next challenge. The Fix The fix here is the same as challenge #1, we've just swapped the string IDs for numerical IDs. hitps:arasec substack com/pin-depth-insecure-irect-objecteterences an7 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) Challenge #3 - Status Code Shenanigans Fortunately, the same person who reported the problem with using the names in the URLs came back to check and discovered the numerical IDs weren't an improvement, and reported that too. Our friendly developer realised their mistake and has added some HTTP status code responses to hide the email address, and called it a day. The email addresses are no longer visible. Challenge #3: Attempt to view the email addresses of all four Hobbits. (All you need to do is find and visit their valid IDs.) We can see from the two working URLs that we're dealing with another incremental numeric ID in this challenge: https://larasec.evilhacker.dev/idor/three?id=44 https://larasec.evilhacker.dev/idor/three?id=66 Along the same lines as Challenge #2, the crude method of solving this one is to check each number to see what status code we get back. There are dedicated hacking tools that do this sort of thing, but since we're just checking status code, we can do it really easily in Laravel 5 Artisan: :command(‘idor:three', function () { for ($i = 15 $i <= 100; $i++) { $url = "https: //larasec.evilhacker.dev/idor/three?id={$i}"; $status = Http: :get($url)->status(); $this->line("{$url}\t{$status}") ; usleep(5@0_20) ; + Ys And the output. hitps:arasec substack com/pin-depth-nsecure-irect-objecteterences snr 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) https: //larasec.evilhacker.dev/idor/three?i -> 404 https: //larasec.evilhacker.dev/idor/three? => 404 https://larasec.evilhacker.dev/idor/three?id=3 -> 404 https: //larasec.evilhacker.dev/idor/three?i > 404 https: //larasec.evilhacker.dev/idor/three?i => 208 // Frodo https://larasec.evilhacker.dev/idor/three?i -> 404 https: //larasec.evilhacker.dev/idor/three?i => 404 https://larasec.evilhacker.dev/idor/three? -> 403 // Hobbit ? https://larasec.evilhacker.dev/idor/three?i -> 404 https://larasec.evilhacker.dev/idor/three?i > 404 https://larasec.evilhacker.dev/idor/three?i -> 208 // Merry https: //larasec.evilhacker.dev/idor/three?i -> 404 https://larasec.evilhacker.dev/idor/three?i => 404 https://larasec.evilhacker.dev/idor/three?i -> 403 // Hobbit ? https: //larasec.evilhacker.dev/idor/three? -> 404 https://larasec.evilhacker.dev/idor/three? -> 404 https://larasec.evilhacker.dev/idor/three?id=99 -> 404 https: //larasec.evilhacker.dev/idor/three? => 404 Also, like last time, there is a 11 number gap between the valid IDs. Now, the interesting thing to note here is that we don’t get to see the contents of the two extra Hobbits. We know they exist and have the IDs of 55 and 77, but that's it. As a result, this is technically not an IDOR. There is working authorisation going on here, and that’s great. But it’s leaking information, and that could be a problem. In this trivial example, the fact there are 4 Hobbits is already known, so it's not a risk. But there are many cases where leaking this information is sensitive. Maybe it exposes how many users are in your database - which is commercially useful information, or the product name for an upcoming release you don't want anyone to figure out yet. If the app has file handling and rejects system files, a 404 vs 403 difference could reveal the existence of files on the system - allowing the attacker to map it out. hitps:arasec substack com/pin-depth-nsecure-irect-objecteterences 1017 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) The Fix If you read last week's security Tip, Leaking Model Existence, you'll remember it coves this exact scenario and introduces a solution in the form of specifying the status code from Policy objects - and anywhere else that uses the authorisation helpers. You can also do it manually using the abort_*() helpers. This is how | build the challenge: if ($selected) { abort_unless(isset($hobbits[$selected]), 404); abort_unless($hobbits[$selected]['link'], 403); Changing the second abort_unless() to return a 404 would mask this one. The Twist But that isn’t the whole picture, as we covered in last week's security tip. Timing Attacks are still definitely a problem. If you want to learn more about them, go back and read this section from last week. If you want to play around with timing attacks, | built a timing attack challenge into my Enumeration challenges. So go check that one out to see how timing attacks work https://larasec.evilhacker.dev/enumeration/three Challenge #4 - UUIDs Change of plans! Our friendly developer has been asked to make the links for the email addresses publicly available, but not guessable. They'd read about something called a UUID, and decided to give it a try. At the same time, they started building an interactive front end for their application, and started to lay the groundwork for future components. But nothing is visible on hitps:arasec substack com/pin-depth-insecure-irect-objecteterences wT 59/23, 409 PM {3)1n Dept: Insecure Direct Object References (DOR) the page for users as yet. Challenge #4: View the email addresses of all four Hobbits within the database. In this challenge, we're presented with URLs that look like this: https://larasec.evilhacker.dev/idor/four?id=028fcc7b-bfad-4fd3-9135- 1924939774c https://larasec.evilhacker.dev/idor/four?id=2431f9d6-c789-4326-982d- 6113849189bb ‘Anyone who is familiar with UUIDs should recognise them immediately. They aren't incremental and our chances of correctly guessing the two UUIDs we're looking for are, let's face it, impossible, So what are we to do here? When met with a problem like this, we want to keep looking around. | placed a big clue in the description, talking about the developer laying the groundwork for something front end related with "nothing is visible on the page". In other words, there is something hiding in the HTML. Viewing the source, we find this block: hitps:arasec substack com/pin-depth-nsecure-irect-objecteterences war 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) sh2 cle: block text-x1 font-semibold text-gray-760 pb-6">The Hobbits List-inside list-disc"> ‘+: Seer > vaul class Y
  • marker Veli xedat 2ea1fede-c789-4: o2d-61138a018ebh" }"> cless-"under line">Pippini/e> The developer has passed the Hobbit ID, in this case a UUID, into an attribute for use by the Javascript. This is a perfectly acceptable use case for an ID, but given the ID is also the key needed to view the Hobbit in the URL, it gives us everything we need to view the record It's not uncommon for the secret you need to access a record to be returned as part of ‘API responses, or sent to the browser in an SPA or interactive component. While the user receiving this data usually has access, they don’t always, and you need to be careful of what data is being passed around and who can receive it. Now you could argue this isn’t technically an IDOR, but rather sensitive information leakage. However this occurs because the primary ID is being using in the URL, and the primary ID isn’t treated as sensitive information. So I'd argue the sensitive information leakage leads to an |DOR. Ultimately it’s broken access control. \\(/)_- The The problem here is that the primary ID is used for both use cases. If you need a URL with a secret key, don’t use your primary ID. Generate a different token for it, something hitps:arasec substack com/pin-depth-insecure-irect-objecteterences 1317 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) that can be a hidden attribute on your model, so it's not accidently passed around and only retrieved when required. Another option is to use Signed URLs, which we'll deal with in the final challenge. Challenge #5 - Signed URLs Our friendly developer stumbled upon Signed URLs in the Laravel Documentation and thought they'd be perfect for use protecting their Hobbit URLs. So they added in support for checking signed URLs.. Challenge #4: View the email addresses of all four Hobbits within the database. We have arrived at my favourite challenge, and one that's based on an actual vulnerability I discovered. It may feel contrived, but this did actually happen, and my lips are sealed. So this challenge poses an interesting problem, The two URLs we're given are: Frodo: https: //larasec.evilhacker.dev/idor/five?id=126070d5-839a-43af-924e- 56db03b662Fb&si gnature=9a28c734F33F9970a@b8b85ed5a0191add3cF264700385cd dbbe1@53ed17bae3 and Pippin https: //larasec.evilhacker.dev/idor/five?id=de5f7e5e-5bf5-4afe-beé1- 520077 fad@898s ignature=6902aec81bc49ec5737276e4ca2de024418256dc6Fb6352b 3aea84acd61453bb But how do we find the other Hobbits URLs? Itis still using UUIDs, and they are still exposed in the HTML source of the page: hitps:arasec substack com/pin-depth-insecure-irect-objecteterences 147 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR)
  • Sam
  • Merry But the URL doesn't just have the ID, but it also has a signature. Swapping out the UUID in a signed URL with one of the others gives us an expected 403 Forbidden error, so how do we generate a valid signature? It's important to stop here and remember that we developers overlook things and make silly assumptions (well, | know | do!). Combine those two flaws a desire to not break things and we get a backwards compatibility checks. But backwards compatibility combined with security sometimes results in wonderful edge cases. Can you see where I'm going with this? In order to not break existing links, the developer did this. if ($request->has(‘signature')) { abort_unless($request->hasValidSignature(), 403); } Yep. If you remove the signature from the URL, it bypasses the check and lets you view the record, Thus these two links work: https: //larasec.evilhacker.dev/idor/five?id=@f11d291-d9e9-4e3c-a072- 1F40cccal tos https://larasec.evilhacker.dev/idor/five?id=e4bc827b-5864-4ca7-bed4- 23afa4ffaede hitps:arasec substack com/pin-depth-insecure-irect-objecteterences 1817 51323, 409 PM. (@) In Depth: Insecure Direct Object References (IDOR) And that's it. Super simple, but unless you think to remove the signature from the URL, you won't discover it. That whole silly assumptions thing works both ways. @ The Fix Be very careful trying to support backwards compatibility with security features. It may allow a creative attacker to bypass your security. Maybe use a different endpoint and plan a shutdown date for the legacy endpoint, or regenerate links and notify users? This is one of the reasons | like the signed middleware that comes with Laravel - it ensures you don't forget to check the signature by enforcing it at the route level. Well Done! Nice work for making it this far! This has been an epic email to write, and | had a lot of fun building those challenges. | hope you had fun and learned something. @ Please reach out if you need help with the challenges, or have any suggestions for other challenges | could build. If there is a specific vulnerability you'd love to try out, let me know! 1 _https://owasp.org/www- paf-archive/OWASP_Top_10_- 2013,pdf 2 You could argue this one wasn't a true IDOR, but all it took was changing a URL parameter and | was logged in as an the admin user. 3. This is a common theme in broken access control / IDOR vulnerabilities. One half of authorisation is implemented, but the other half is neglected and forgotten about. is Please do this if you're trying this method on my demo site! 5 To save my server from all of you smashing it, I've added in usleep() and I'll leave figuring out how to handle basic auth to you. (| cheated and tested it on my local version) hitps:arasec substack com/pin-depth-nsecure-irect-objecteterences 1617 573723, 408 PM (@) In Depth: Insecure Direct Object References (IDOR) 2 Comments @ | viicscormen spham Aug 1, 2022 Hi Have you some github repo for this post ? Que Oreriy 1 reply by Stephen Rees-Carter 1 more comment © 2023 Stephen Rees-Carter Privacy: Terms - Collection notice Substack is the home for great writing pss sec substack.comipir-depth nsecure-drect-abject-eferences wir
  • You might also like