一、环境
XSS Game - Learning XSS Made Simple! | Created by PwnFunction
二、开始介绍
如果notify为真的话那么html是
<div class="alert alert-warning" role="alert"><b>Meme</b> created from ${DOMPurify.sanitize(text)}</div>
代码解析
meme-code的值
在页面随便输入一个text=aaaa&img=bbbbb
很明显调用到这里因为text和img都存在了
而我们可以很明显看到一点Meme Code没值,没值的话那就代表onload根本没有加载,当我们什么都没写的情况下很明显加载值了
当我们把地址参数写对的情况下,我们的onload很明显是可以执行的
而我们从始至终都没有看到created...,因为notify是false
三、寻找触发点
很明显经过上面的介绍,我们必须要notify为true不然无法下手,那这不就是我们dom破坏的技巧
并且乍一看经过DOMPurify
后的这些交互点都很安全,但是使用html()
解析会存在标签逃逸问题。
两种解析html的方式:jquery.html&innerhtml。innerHTML
是原生js的写法,Jqury.html()
也是调用原生的innerHTML方法,但是加了自己的解析规则(后文介绍)。
关于两种方式:Jquery.html()
和innerHTMl
的区别我们用示例来看。
对于innerHTML:模拟浏览器自动补全标签,不处理非法标签。同时,<style>
标签中不允许存在子标签(style标签最初的设计理念就不能用来放子标签),如果存在会被当作text解析。因此<style><style/><script>alert(1337)//
会被渲染如下
<style>
<style/><script>alert(1337)//
</style>
对于Jqury.html()
,最终对标签的处理是在htmlPrefilter()
中实现:jquery-src,其后再进行原生innerHTML的调用来加载到页面。
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^/>x20trnf]*)[^>]*)/>/gi
jQuery.extend( {
htmlPrefilter: function( html ) {
return html.replace( rxhtmlTag, "<$1></$2>" );
}
...
})
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
有意思的是,这个正则表达式在匹配`<*/>`之后会重新生成一对标签(区别于直接调用innerHTML)
所以相同的语句`<style><style/><script>alert(1337)//`则会被解析成如下形式,成功逃逸`<script>`标签。
<style>
<style>
</style>
<script>alert(1337)//
我们知道DOMPurify的工作机制是将传入的payload分配给元素的innerHtml属性,让浏览器解释它(但不执行),然后对潜在的XSS进行清理。由于DOMPurify在对其进行innerHtml
处理时,script
标签被当作style
标签的text处理了,所以DOMPurify不会进行清洗(因为认为这是无害的payload),但在其后进入html()时,这个无害payload就能逃逸出来一个有害的script
标签从而xss。
3.1总结一下方法:
1.绕过过滤框架
2.html 逃逸出style标签
3.nofity dom破坏 使他为真
<img name=notify><style></style><script>alert//因为img是异步方法,那么DOMPurity会先写,那我们notify就会变成ture,那么我们就会触发
最终payload
text=<img name%3dnotify><style><style%2F><script>alert(1337)%2F%2F&img=https://i.imgur.com/PdbDexI.jpg
之后就搞定了
最终的加载就是加载到div标签里面了