隐藏在URL凭据中的有效载荷:DOM XSS与凭证操纵技术解析

本文探讨了如何利用URL凭据部分隐藏恶意载荷,分析了document.URL与location对象的差异,Firefox对单引号的处理特性,以及通过锚元素用户名密码属性实现DOM Clobbering的高级利用技术。

隐藏在URL凭据中的有效载荷

去年Johan Carlsson发现可以在URL的凭据部分隐藏有效载荷。这一点特别吸引我,因为该载荷在Chrome和Firefox的URL中实际上不可见,甚至在同源导航中仍然保持隐藏。我像抓住骨头的狗一样不肯放手,试图探索可能的应用…

第一个令我惊讶的是document.URL并不总是与location匹配。

1
2
3
https://foo:bar@portswigger-labs.net
alert(location);//https://portswigger-labs.net/
alert(document.URL);//https://foo:bar@portswigger-labs.net/

我原本以为这两个属性是相同的,因为我从未观察到它们有差异,但事实证明document.URL包含URL的凭据部分,而location不包含。这意味着你可以在事件中使用URL从凭据中获取有效载荷:

1
2
https://alert(1)@portswigger-labs.net
<img src onerror=alert(URL.slice(8,16))>

从凭据中获取有效载荷

在模糊测试以识别URL凭据部分哪些字符会被编码后,Shazzer发现Firefox不会对单引号进行URL编码。这在DOM XSS场景中特别有用,特别是当网站移除查询字符串和哈希时。这使得以下漏洞在Firefox中可被利用:

1
2
3
4
function getBase(url) {
   return url.split(/[?#]/)[0];
}
document.write(`<script>const url='${getBase(document.URL)}';<\/script>`);

要利用此漏洞,你需要在Firefox的凭据部分提供有效载荷:

1
https://'-alert(1)-'@example.com

这可以通过重定向或用户导航来传递。你甚至可以使用此技术来控制锚链接的用户名或密码属性。这是因为每个锚元素都有这些属性,它们存储来自URL的凭据。如果是相对链接,它会继承父级凭据,允许你覆盖这些值:

1
2
https://clobbered@example.com
<a href=# onclick=alert(username)>test</a>

锚元素覆盖示例

你可以将此与DOM覆盖结合使用,从而控制具有用户名或密码属性的对象。注意,你甚至可以提供空白的href,仍然可以通过URL控制用户名或密码。

1
2
3
4
5
6
https://user:pass@example.com
<a href id=x>test</a>
<script>
eval(x.username)//user
eval(x.password)//pass
</script>

结论

发现locationdocument.URL之间的差异,以及document.URL如何保留URL的凭据部分——即使Chrome和Firefox等浏览器在地址栏中隐藏它——是相当令人惊讶的。Firefox对某些字符(如单引号)的处理方式(不进行URL编码)也可能对DOM XSS有用。

通过凭据隐藏有效载荷、操纵锚元素内的用户名和密码属性,以及可能将此与DOM覆盖结合使用的能力,可以用于更高级的利用。

注意:Safari会丢弃URL凭据。所有显示的示例仅在Chrome和Firefox中有效。此外,Chrome会阻止子资源使用URL凭据。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计