Post

Magic Links as Gateways to Account Takeovers

Hello, today I will discuss a 1-Click ATO bug that I encountered during a pen-test engagement at BugSwagger LLC. Let’s say the target name is: host.io.

Starting with Sign-up

During the sign-up process, there are two methods of registration: signing up with a non-existent email address and signing up with an existing email address.

Sign-up

The first kind of sign-up is the normal one. You simply input your email address and click submit. A confirmation email will be sent to you to ensure that you are the owner of the email address. After confirming your email address, you will proceed to insert your information and complete the account creation process (name, company name, etc.).

Signing up with an existing Email

The second option only works when you check the circle next to the sentence “I will be joining an existing Host account.” This option entails two scenarios:

First: If you have already registered with an account, you will be sent an email containing a magic link that allows you to log in directly without needing a password.

Second: If you have not registered with the email before, you will simply confirm your email and complete the sign-up process as mentioned above.

However, our focus is primarily on the first scenario!

The Misused Parameter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /account/v2/auth/magiclink/email/ HTTP/2
Host: sub.host.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://app.host.io/
Content-Type: application/json
Content-Length: 192
Origin: https://app.host.io
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Te: trailers

{"email":"myFirend@email.com","referral_code":null,"email_link_uri":"https://host.io","require_ad_spend":false,"account_type":"Standard"}

Upon sending this request I observed two things: first the email_link_uri parameter and second the response itself.

Response

The response received after investigation is not the token located on the magic link sent to the victim, which enables them to log in. The magic link that enables the victim to log in is structured as follows:

1
https://host.io/?login_token=[different_token]&account_type=Standard&require_ad_spend=False

This link contains a unique login token different from the one located in the response. The Trick here is how we can leak the token that was sent to the victim.

Remember the email_link_uri parameter? I tried manipulating it so I could hold the Collaborator link instead of the website URL itself. However, I encountered a weird response.

Response

That triggers the CORS Misconfiguration Bypasses inside my head 😄.

I tried to add the link below:

1
https://host.io.muk4beh062sbtx1v86cglfhd74dx1npc.oastify.com

And hell yeah! It succeeded!

Response

And the link that was sent to the victim looks like this one:

Response

Now, When the victim clicks on this link he will just go my collaboration server and the victim login token will be sent to my server as below:

Response

Now you can just remove the collaborator server and leave the URL as below to takeover the victim account:

https://host.io/?login_token=5c0cdce5658eae411247e6cfb015c7906088ff2b&account_type=Standard&require_ad_spend=False

In summary, always inspect every parameter in important requests like reset password, email change, set password, etc. It may uncover vulnerabilities that you couldn’t imagine existed. Thank you for reading, and you can follow me on Twitter: @sl4x0.

This post is licensed under CC BY 4.0 by the author.

Trending Tags