How I bypassed IDOR (Access Control) Protection

While pentesting a HackerOne‘s private program. I noticed that there was an option to create a team, it also had an option to invite other members using email. And on the same page, the emails (which were invited and which were already part of the team) were displayed. Since now, I’ve been calling it ‘team’, but the site represents it with the name ‘brand’.

The program being private on hackerone, we will scrutinize the site as:!

So, while testing for race-conditions on the invite members option, I came upon this GET request:

GET /_ajax/profile/brands/BACawjzt-Xk/invitations? HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-[sitename]-Analytics: AAMAA1dFQgA=
X-[sitename]-Brand: BACawjzt-Xk
X-[sitename]-Build-Name: vikachu
X-[sitename]-Build-Sha: 523fa138b0e9bf1142857fe3093fc196d7fae55f
Cookie: __cfduid=d001041a315ddda7daf205bd739e3379c1499609824; ajs_user_id=%22UACawu1inbU%22; ajs_group_id=null; _ga=GA1.2.14298406.1499609833; _gid=GA1.2.283747709.1499609833;; ajs_anonymous_id=%226b19b45b-a10f-4746-b51e-e80cb7857ebd%22; CB=BACawjzt-Xk; CID=qwnCP4SBWmwKK7G5TMHo_1i9fZkR--6jbAveJhXv0TtZSW9ZxFYo7_6hJbdClX222magRgndXFuELRSor_Y7rjpKG0d1Zw9ASs5iwBmCEHcehxkG; CAZ=Echg-KSowZ4_zul8qvTPkug0EPdfwBltvGYHLUozgSr6VheNLgSuxmdoQ7yxIdG90k2UlsCqBv_jjql2I34Sb52f251wkfqdur56KY_5N4Ww71sMGqQ_BTWBFHXjwzzSiPBagAS7g9oTefYK3aQsx-MB93YuCObXfoeFiqpJ-RGUy-qE1hoRftM7oixjuLNHz9zCmL3hqVZcMVwofELtI88z3chGhHWtuCvHVW6fRpore-YJ59DKkhOL_w_yi_XW8BcQG7CJti_eCXPZ6SW1Q_MCxzCvi_ITSCYRFgNbk4Mtbwu9; CL=en; CS=1; __vero_user=UACawu1inbU; __stripe_mid=7cfed837-f29b-41d1-9559-93c1707bdc1e; __stripe_sid=ae257182-0b7a-45b5-8d29-5296b81c4442; CC=PK; __veroc4=%5B%5D; __vero_visit=true
Connection: close 

Repeating this request, in response I got all the emails which were invited to my brand (team). Now this is interesting, since there was a brand ID in the GET request. I quickly created a new account on another machine (VM), invited some emails and grabbed the brand ID of the victim account (which was created on VM).

Back to the attackers machine, with full hope of getting an IDOR (missing access control). I changed the ID in the GET Request: /_ajax/profile/brands/[victim-brand-id]/invitations?=> Repeated the request, and all I got was a 403 Forbidden! 🙁

I decided to dig deeper, and found that the brand ID was *not* just in the GET data, but there were 3 values on the brand ID in the same request:

  • GET request /_ajax/profile/brands/BACawjzt-Xk/invitations?
  • X-[sitename]-Brand: BACawjzt-Xk (Header)
  • CB=BACawjzt-Xk (One of the cookie values)

Now this is really compelling, quickly changed the brand ID values in all three options: (The GET request, X-Site-Brand header, CB cookie value) to the victim (VM machine) account’s brand ID.

Replayed the request, and BOOM! 😉 All the invited emails in the victim’s brand were displayed in front of me! 😀

I quickly wrote a report and submitted it via HackerOne to the private program. But since this doesn’t seem to be a big issue (only emails being disclosed), I started digging deeper and found that this was a site-wide vulnerability in the X-Site-Brand header and CB cookie value. Now, exploiting both of them to bypass the IDOR (Access Control) protection allowed me to do anything with the team just by knowing the brand ID: Disclosing sensitive information, removing members, adding members, and last but not the least: adding administrators which lead to complete takeover of the brand! I quickly sent all this information to the site’s security head (via email and told him about the report ID on HackerOne).

After 3 days of reporting, they fixed the issue, and since they mostly reward bounty under $256, and this was a critical one, so they rewarded a bit more:

Thanks for reading till here, I hope you learned something. Happy hacking!

Ahsan Tahir