翻译自: Safari's URL redirection XSS - CVE-2016-4585
URL传递错误有时候会导致安全问题。我一年前报告了这样的漏洞: XSS bug of Safari,这篇文章主要谈谈这个漏洞的细节。
漏洞概要
-
概述: 经过一个精心制作的重定向URL,可能出现:
- HOST header 可控
- 域混淆XSS
如果目标网站满足特定的要求,这两种都会导致信息泄露或欺骗。
修复情况: Safari改进了验证机制,现在遇到不可用的重定向URL的时候,会抛出一个错误。
控制Host Header
当一个精心构造的URL被输出在HTTP Reponse中的Location参数中(通常是302或307)时,会出现漏洞。
URL的端口不是数字。Safari会连接到 example.jp:80, 发送一个包含如下header的请求:
不可用的端口被应用到Host Header中。这意味着我们可以控制从某个人的浏览器发送到某些地方的Host Header。但是有两个限制:出现在URL中的字符会被URL编码,只有部分出现在 :
后的字符可以被正常转发。
让我们来研究下如何利用这种浏览器行为。(为了重现漏洞,你需要移除burp之类的浏览器代理,并且使用老版本的Safari)
单引号XSS
有些符号,如'
、&
,是允许出现的,如下图所示。首先我测试了一个简单的XSS,输出在单引号闭合的HTML标签属性中。
令人惊讶的是,Safari的XSS Filter在这种情况下仍然有效。当然,在输出在<script>
标签里的情况中,XSS Filter没有起效。
然而这些都太浅显了,让我们深入挖掘下这个漏洞。
由hostname可控引起的XSS
Host header通常会输出在如下所示的点:
<script src="http://(HOST)/js/jquery.js">
<link href="http://(HOST)/css/style.css" rel="stylesheet" type="text/css">
你可以通过 github's code search 找到很多这样的案例,我在自己的安全测试项目里也发现了类似的案例。
我们来思考 <script src=
这样的场景下的利用。举个例子,假设 header 可控,将 hostname 从 example.jp
变成了 example.jp:xyz
。
<script src="http://example.jp:xyz/js/jquery.js">
Safari把 src 中的 URL 识别为畸形的,并不会加载它(这样的URL只允许出现在Location中)。即使Safari从 example.jp:80 加载了JS,也是毫无意义的,因为Safari只是加载了合法的JS。攻击者的目的是让Safari从他的服务器加载JS。
在几次尝试和错误后,我又有了新的思路。
step-1: 从攻击者的服务器接收的Reponse:
step-2: 向目标服务器发送的Request:
在收到Location后,Safari连接到了 example.jp:80,并且发送了如下所示的Host header:
在初始化的部分,a@
(包括基础认证信息)被剥离出去。
step-3: 从目标服务器获取的 Response:
Host header被目标应用输出在了 <script src=
中。
在@
符号前的字符再次被剥离。因此,用户浏览器从 evil host 获取到了非法JS,XSS攻击成功!
在这次攻击中,XSS Filter并没有生效,网络钓鱼警告也没有发出警告(当URL包含基础认证信息的时候,会发出警告)。所以攻击者顺利的完成了这次攻击。
译者补充: URL Hacking - 前端猥琐流
由hostname可控导致的信息泄露
上面的技巧也可以用于信息窃取攻击。假设一个Web应用程序,通过精心设计,重定向到一个包含敏感信息的URL。
Location: http://(HOST)/foo?token=fj0t9wj958...
在这个案例中,攻击者可以利用@
的技巧,控制受害者的Host Header,从而获取到token。
我认为这种情况是比较现实的,因为Location Header是最常见的服务器对Location产生影响的输出点。这不是因为web应用开发人员都这样做,而是因为一些web应用平台,传递Location Header的时候,将请求中的Host Header直接输出在Response中。一个很好的例子是Java的 HttpServletResponse#sendRedirect()
。
背后的因素之一是在之前的HTTP/1.1标准中,RFC2616 禁止在Location Header中输出相对网址(relative URLs),目前已经允许了。
如果hostname可控,除了Location Header,同样会影响 <form action=
、<a href=
。
译者补充: 利用HTTP host头攻击的技术
域混淆 XSS
在测试过程中,一个奇怪的表现吸引了我的注意:
正常状态下网站的截屏:
然而,当重定向到 http://www.mbsd.jp:xyz/ ,变成了这样:
产生原因是相对URL地址的资源文件没有正确加载。让我们来测试下载浏览器中发生了什么。
页面的Origin明显被破坏了。这应该是相对地址的资源没有加载的原因。另外,获取cookie的操作也被拒绝,并抛出了SecurityError,即使cookies在请求中被正确的包含。
因为Origin被破坏造成了局限,不仅影响了cookie的获取,还抑制了攻击者的JS执行。这看起来对攻击者毫无益处,但如果能找到利用方法或许故事会被改写。
在这种情况下,最好的工具就是 iframe。先来看下在iframe中的重定向是否有什么不同。目标网站和攻击者的网站如下:
目标站点: http://test.mbsd.jp/ (X-Frame-Options中添加了攻击者的站点)
攻击者的站点: http://example7.jp/ (iframe中重定向到:http://test.mbsd.jp:xyz/)
结果如下:
注意下JS console中的错误。在iframe中的MBSD页面,相对路径的资源(/js/jquery)抛出了404错误,但是路径是: http://example7.jp/js/jquery.js 。浏览器首先尝试从 http://test.mbsd.jp:xyz/ 加载资源,但是由于Origin被破坏,所以尝试从iframe的parent site加载JS。
坦率的说,这个结果并不是我所期望的。但无论如何,这表明了通过iframe加载目标网站,攻击者可以攻击如下所示的相对地址的资源。
<script src="/js/jquery.js">
带hostname的相对地址(如://example3.jp/a.js)不会被这个漏洞影响。
漏洞影响
前文中提到,在hostname混淆的目标网站中,JavaScript运行异常。所以攻击者的JS,既不能读取cookies,也不能通过XHR获取同源网站内容。
但仍然可以操作当前页面的内容。这意味着,攻击者可以泄露或者改变某些特定URL的内容。Cookie认证页面可以是目标,当Cookies被包含在请求中的时候,即可完成攻击。
附加文档
关于这个漏洞,更多的细节:
Safari会去请求默认端口(80,在https中为443),当URL中的端口不可用时。HTTP代理,比如Burp和Squid,会阻止攻击,因为它们不允许不可用的端口。
一个畸形的Host Header(如:Host: hostname:xyz)被发送到服务器时,Apache、Weblogic、Nginx会接收,但Tomcat和IIS不接收。
当页面为302或者307跳转的时候,HTTP method可以是GET或者POST。然而由于重定向的特点,Request body通常为空。
在iframe中,Base URL继承于它的父类。奇怪的是,
<base href=
完全被忽略。当JS在blank Origin被执行,甚至会与父iframe独立。除了cookie和localStorage,DOM对象都是可访问的。
CSP(or X-Frame-Options)或许会预防XSS攻击。