Hey folks! It’s me, Muhammad Julfikar Hyder(thejulfikar) back again with a new article. I’m writing about an IDOR I identified a few days ago. Let’s get to know what IDOR is first.
Insecure direct object references (IDOR) are a type of access control vulnerability that arises when an application uses user-supplied input to access objects directly. The term IDOR was popularized by its appearance in the OWASP 2007 Top Ten. However, it is just one example of many access control implementation mistakes that can lead to access controls being circumvented. IDOR vulnerabilities are most commonly associated with horizontal privilege escalation, but they can also arise in relation to vertical privilege escalation.
Let’s get to the exploits now. Consider the applications as a subscription and billing platform. The application has a feature to add different user roles to manage the created organization by sending invites to their email.
A confirmation email with a signup link is sent to the new user when an admin requests to add a new user.
The list of invited users is displayed as “pending invites” to an endpoint until the users accept invitations.
Well, the admin also has a feature to cancel those invites that were sent to the expected new users. I was trying to check the invite link to see if it’s still valid even after the invitation has been canceled. I fired up my burp and intercepted the request for cancellation.
The application is generating a request on the DELETE method to the server with an API endpoint. Whatever the case, I looked closer at the endpoint: “/snappy/api/pending_invites/sats3yhb4xt6”, The endpoint contains an id. I marked this one as an invitation ID.
I decided to try an IDOR here. I invited another user from a different account. I collected the invite ID from that other account and pasted it here. And it worked! A successful IDOR The response showed the user’s email.
But a new question arrived, how can I collect other users’ invite IDs without accessing their admin accounts? Without better exploits, I can’t report this.
I looked again at the invite ID and tried to identify if there was any encryption algorithm. But no result! I went to the repeater and resent the previous request that I had sent a few minutes before.
And this time I got a different response! “Couldn’t find UserInvite with ‘id’=3724993831954625322”. That means the numeric id 3724993831954625322 is connected to the invite ID (sats3yhb4xt6), or one of these is encrypted, which was unpredictable for me!
So I decided to go deep. I replaced a random character with the string id at the endpoint (/snappy/api/pending_invites/b). And the response I received was quite interesting!
The parameter ‘id’ and its value = 10! I’ve changed the string value to “b,” and this time I found a different value at the “id” parameter!
That means maybe the string id is generated by a numeric id.
Whatever the case, if the application is showing me a dedicated numeric id with a message “Couldn’t find UserInvite with ‘id’=numeric_id”, that means the application is accepting my request and trying to remove a pending invite but couldn’t find the id! Because maybe that invite was canceled or accepted already and the string ID has expired, but the numeric id is still connected to the string id. What if I give any random string or character that might be valid?
In intruder, I decided to fuzz the endpoint with a random string value. And I got a lot of pending invites canceled!
Conclusion: The API endpoint was validating the request only. It was just removing pending invites whenever a request came to the server with that string id. It was just verifying the invite ID and, if it was valid, removing the invite. The application was not validating the request, regardless of where it was coming from or which user made it.
“About the author: Muhammad Julfikar Hyder is a bug bounty hunter and cybersecurity enthusiast. You can follow them on Twitter at @thejulfikar for more security tips and updates on their latest findings.”