文章首发于先知
前言
国外的一个xss challenge(规定时间内做出可得一年的Burp Suite正版证书)
题目分析
主要的功能逻辑代码为script.js, 如下:
1 | var hash = document.location.hash.substr(1); |
代码逻辑为:
通过触发location.hash的变化来调用displayReason函数,通过ajax请求得到./reasons/${reason}.txt,然后把response的内容返回给id为reason的标签。
首先测试了下直接在URL的锚部分写上xss语句
这里可以看到这个404的页面,在response时不仅对特殊字符进行了编码处理,而且还会将%替换为_,所以直接通过xss语句触发是没戏了。
接下来尝试了一下.htaccess等403页面的触发,看下对应的response内容有没有经过处理
可以看到,在403的response中我们的xss语句是完整存在的,那么接下来只需要把这个xss带到我们之前的页面就可以触发xss了
进行尝试
这里需要注意两个地方
- 第一个是默认ajax去请求是下reasons文件夹下,我们如果要请求.htaccess是需要向上跳一级目录的
- 第二个是我们需要拿到的是访问htaccess得到的response,所以htaccess的参数需要进行二次编码
最终访问效果如下:
可以看到img标签成功被解析。
不过此时仍然没法弹窗,因为这个challenge是有csp进行限制的,csp规则如下:
1 | default-src 'self'; |
限制了资源必须来自此站点
那么接下来就开始寻找一些可以当成js来执行的地方,我们可以通过之前的404页面返回的内容来当作我们的js语句,并且通过script标签的src属性进行引入,唯一需要注意的是要进行单引号的闭合
构造语句如下:
在控制台执行一下
成功触发,接下来把这个返回内容作为外部js引入就可以了
不过不能直接在response里面直接返回script标签,因为这里的赋值是
1 | reason.innerHTML = unescape(this.responseText); |
通过innterHTML产生的script标签并不可以执行
所以这里可以用iframe的srcdoc属性去解决这个问题,payload如下:
1 | <iframe/srcdoc='<script src="x%27-alert(document.domain)-%27"></script>'> |
将上面的payload二次编码后,放进location.hash
成功触发xss