一则有趣的XSS WAF规则探测与绕过
Posted FreeBuf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一则有趣的XSS WAF规则探测与绕过相关的知识,希望对你有一定的参考价值。
前言
本文是以B站一个有趣的XSS(已修复)为引子(为什么说有趣后面再解释),作为实例分析其WAF的规则,方便大家加深对XSS WAF探测以及针对性bypass的理解。
进入主题
一、一般waf是由多条正则配合使用,因而绕过也必须根据实际情况构造xss探针'
";>
二、个人对于waf bypass的理解:本来应当被wa会生效的payload不在规则库里或用本来就不会生效的payload(这时候是大概率能通过waf的)经过服务器处理后payload最后生效了。
三、过程
1. 首先是7师傅给了一个链接,让我们绕一绕b站的waf,callback参数存在xss。
2. 上xss探针:';
">
可以看到探针成功被解析为标签和属性。
3. 上经典payload(这里由于可以控制标签,优先使用<img><script>
):
对于<img src=x onerror=alert(1)>
对于<script>alert(1)<script>
可以看到均被waf拦截了。
4. 分析waf规则:基于从局部到整体的思想(这里是可以写成一个自动化的waf规则探测脚本的,xsstrike有简单的waf探测规则)
这里是xsstrike的简单探测截图:
于是可以率先得到一条waf规则:<script\s+[^>]*src=.*
(注意实际的正则可能特别复杂,这里是简化版的,没有考虑一些特殊字符,比如字母和数字可能可以互换,还有一些特殊字符,空格等等,这里能大致描述清楚waf的正则表达式的主要结构就可以了,下面出现的正则表达式同理) 。
验证一下确实如此 :
5. 开始我们的手工waf规则分析
(1) 局部探测
<img>
会wa么,没有wa:
alert(1)会wa么,没有wa :
单独的onerror会wa么,没有:
src=x会wa么,没有wa:
因此是某部分组合起来了才导致被wa了,单独的并没有 。
(2) 尝试逐步组合
<img src=x>
会wa么,没有wa:
<img src=x onerror=xxxx>
会wa么,没有wa:
<img src=x onerror=alert(>
会wa么,没有wa:
<img src=x onerror=alert(xxxx>
会wa么,终于wa了哈哈:
(3) 回溯waf规则,<img src=x onerror=aaa(bbb>
会wa么,不wa :
这里我们就可以得知aaa处存在黑名单校验,alert在黑名单里,试试prompt/confirm呢 :
均被wa了,单独提取出onerror=alert(xxxx
呢,竟然不会:
再试试onerror=alert(xxxx)
,终于wa了 :
这里就要分析为什么<img src=x onerror=alert(xxxx>
会wa,但onerror=alert(xxxx
不会,只有补全了右括号才会的原因,我的猜测是前者触发了另一条waf规则(针对标签开头的waf规则<[^>]*\s+on\w+=(?:prompt|alert|confirm){1}\(\w+
,用<..aaaa onbbbb=alert(ccc
成功触发waf(注意这里用\w的原因是比较懒,经过测试数字型on1111并不会被wa,描述清结构即可=。=)
而后者对应的waf规则直接是on\w+=(?:prompt|alert|confirm){1}\(\w+\)
。
到这里我们明白我们的payload被wa的原因是触发了下列这两条(同时触发或者触发其中一条都会wa)。
on\w+=(?:prompt|alert|confirm){1}\(\w+\)<[^>]*\s+on\w+=(?:prompt|alert|confirm){1}\(\w+
分析第一条规则和第二条规则,最主要的是对弹框函数的过滤,因此使用黑名单之外的函数可能bypass,测试发现console.log可以绕过:
但这里要求是弹框,对于函数的黑名单我们想到了可以用top对象绕过top['alert'](1)
或者top['al'+'ert'](1)
由于[]
的存在不匹配字母数字或者下划线(\w
)导致<img src=x onerror=top['alert'](1)>
不匹配正则表达式也就不会被wa。
(4) 对于7师傅的解法的分析:
a. 使用script标签利用响应包会拼接双写payload绕过(基于特殊情景构造不在waf规则里的无效payload,经过组合后又生效了,也就是上文之前对于bypass的第二种理解)
利用</script><script>
+</script></script>
拼接闭合中间的<script>标签
,然后浏览器解析的时候为我们补上了最后的</script>
payload向量结构:aaa</script>bbb<script>ccc
可以看到最后aaa和ccc都是在<script>
标签里了,并且aaa换成函数名+括号可以绕过了正则<script>.*\(.*\)
,将a替换为alert(document.cookie)
,将c替换为任意一个不被wa的变量或内置函数对象名即可console.log
payload:alert(document.cookie)</script>bbb<script>console.log
b. 7师傅的解法巧妙利用了前后双写拼接闭合中间的方式绕过<script>
后的绝大部分正则检测,但对于正则的描述还不够具体,<script>aaa(bbb)
并不会被wa
因此联想到<script>alert(1)</script>
被wa还是因为函数的原因,所以正则应该是<script>.*\s(?:alert|prompt|confirm)\(.*\)
,因此简单的做法还是直接利用top对象绕过即可,payloads:<script>top['alert'](1)</script>
(5) 到这里发现了什么吗?
前面的截图中有的是弹1有的是弹document.cookie,因为7师傅的解法可以弹document.cookie,而其他两种解法的document.cookie被wa了,也就是说我们触发了某些waf规则了。
a. 被wa
对比<script>aaa(document.cookie)
和<bbb>aaa(document.cookie)
可以发现与<script>
有关,经测试<script>document.cookie
和<script>doucment['cookie']
均wa,再缩小,发现 <script>document[xxx]
和<script>document.xxx
也wa了,但是<script>documentxxx
不wa,于是乎可以判断又有两个waf规则很显然,即<script>.*\s?document\.\w+
和<script>.*\s?document\[\w+\]
再对比<script>aaa[](document.cookie)
与<script>aaa[bbb](document.cookie)
可以发现后者被wa了,此时想到用反引号代替括号,但反引号内的document.cookie
并不会被解析为对象,确实绕过了规则但并没有实现弹cookie,
到这里基本可以归纳补充加入反引号的规则的逃逸为<script>[^
]document.\w+
缩小的过程的还发现<script>\w+\.cookie
也会wa,到这里我就不想弹cookie了,打扰了。
尝试加载远程src,发现<script\s(.*\s)?src(=\w+)?>
也wa了,到这里基本放弃对<script>
后的规则的bypass了,打扰了。
b. <img src=x onerror=top['alert'](document.cookie)>
经过a的分析,对于标签内的document.cookie的规则我觉得也是凶多吉少,这里不再尝试
c. 尝试了下a标签,发现<a href=javascript:xxx
就会被wa,但是<a href=ccc>
和<a yyy=javascript:xxx>
和<bbb href=javascript:xxx>
以及javascript:xxx(yyy)
都不会wa,于是可以明白对a标签的href属性的伪协议做了针对,为<a\s(.*\s)?href=javascript:.*>
d. 最终的变相绕过:利用window.name或location.hash放置payload,由于window.name和location.hash.slice(1)不会经过服务器也就不会触发waf
window.name版的payload:<img%20src=x%20onerror=top[%27alert%27](window.name)>
![image.png](https://image.3001.net/images/20181202/1543684005_5c02bfa5ce803.png!small)
location.hash.slice(1)版的payload:<img%20src=x%20onerror=top[%27alert%27](location.hash.slice
1)>#document.cookie
,测试发现触发了另一条规则导致被wa了,<img\s[^>]*on\w+=\w+\[\w*\]\(\w*\)
和<img\s[^>]*on\w+=
\w*.*
(6) 由于可以控制标签,也就是说可以对b站的waf规则做一遍深入的探测,同时可能利用的姿势也会很多,也可能利用多种编码以及特殊字符等等,但fuzz的工作量也会增多,这里的重点是对waf规则的探测分析与针对正则层面的bypass,因此就不继续下去了。
(7) 至今已发现的b站waf规则总结:
on\w+=(?:prompt|alert|confirm){1}\(\w+\)<[^>]*\s+on\w+=(?:prompt|alert|confirm){1}\(\w+ <script>[^`]*document\[\w+\]<script>[^`]*document\.\w+<script>\w+\.cookie<script\s(.*\s)?src(=\w+)?><a\s(.*\s)?href=javascript:.*><img\s[^>]*on\w+=\w+\[\w*\]\(\w*\)<img\s[^>]*on\w+=`\w*`.*
当然这些规则可能不会很准确,但能帮助我们基本了解大概的waf规则结构,然后才可以做出相应的bypass。
从我们已经分析出的规则,b站对on事件的过滤、对a标签的href属性的过滤和对<script>
后的极尽苛责的过滤可以看出b站的waf确实很有故事=。=。
(8) 修复方案:增加规则库或者实体编码转义尖括号
总结
上述仅仅讲述了waf 规则探测的基本思想和简单的bypass以及自己对waf的一些理解,师傅们当茶点看看就好,不喜勿喷哈,欢迎交流=。=
以上是关于一则有趣的XSS WAF规则探测与绕过的主要内容,如果未能解决你的问题,请参考以下文章