Burp Xss Scanner 插件

0x00 前言

Burp虽然自带xss检测,但是Pyload与数量都不是自己能掌控的。所以自己写一款Xss检测插件,对一个参数进行测试的时候,要求只能发送一次Payload(检测能否进行逃逸当前分隔符),而且能够对Dom Xss进行检测。

0x01 检测思路

最开始的设想是发送带’”<>的http 请求,看能否返回’”<>这些字符,对于检测html-content xss 和 js-content xss的情况很好处理,但是无法检测dom xss。需要渲染页面,于是使用java中的htmlunit进行页面渲染,来判断’”<>的过滤情况(由于进行页面渲染,会自动修改错误的html语法),以及函数hook,改写js中的对象函数进行判断是否存在dom xss。

0x02 成品

html-content xss检测

js-content xss检测

dom xss检测

0x03 html-content xss检测

其实本来这个是最容易,但是上面提到htmlunit会自动修正错误的html语法,也需要提及一下。
使用如下测试函数,对渲染后的代码进行测试。

@org.junit.Test
public void CheckHtmlXss() throws IOException {
    WebClient webClient = new WebClient();
    webClient.getOptions().setJavaScriptEnabled(true);
    webClient.getOptions().setCssEnabled(false);
    webClient.getOptions().setUseInsecureSSL(true);
    webClient.getOptions().setThrowExceptionOnScriptError(false);

    //获取页面
    try
    {
        String url ="http://127.0.0.1/test2.php?url=xxxxx";
        HtmlPage page = webClient.getPage(url);

        System.out.println(page.asXml());
    } catch (ScriptException e) {
        System.out.println(e.getFailingLine());
        System.out.println(e.getPage().asXml());
    }
    webClient.close();
}

测试下面这个xss。

<?php
$url = $_GET['url'];
echo "<img src='".$url."'>";
?>

如果发送的请求是

test.php?url=TTT'"<>TTT

则使用htmlunit渲染的页面源码是

<html>
  <head/>
  <body>
    <img src="TTT" "<=""/>
    TTT'&gt;
  </body>
</html>

发现我们的payloadTTT'"<>TTT已经完全被打乱了。所以我们需要闭合前面的img标签。再发送如下请求。

test.php?url='"/>TTT'"<>TTT

返回包

<img src="" "=""/>
TTT'"&lt;&gt;TTT'&gt;

发现payload中的<>被转义了。如果我们往<>填入一些字符尼?

test.php?url='"/>TTT'"<xxx>TTT

返回包

<img src="" "=""/>
TTT'"
<xxx>
   TTT'&gt;
</xxx>

可以发现已经当成了<xxx>标签解析了,虽然<>没被转义,但是却不好正则匹配

TTT'"
<xxx>
   TTT'&gt;

这结果是三行,正则使用的是单行匹配,多行匹配的话,可能会匹配到我们不想匹配到的东西。

那把TTT'"TTT放入<>,是否当作标签解析。

test.php?url='"/><TTT'"TTT>

返回包

<img src="" "=""/>
<ttt '"ttt="">
   '&gt;
</ttt>

现在'"<>都在一行了,可以使用如下正则<ttt(.*?)'"ttt(.*?)>进行匹配。

但是遇到过滤了<>"的html xss,这个xss只要没过滤'还能进行x的。

<?php
$url = $_GET['url'];
$url = str_replace("<","00",$url);
$url = str_replace(">","11",$url);
$url = str_replace("\"","22",$url);
//$url = str_replace("'","22",$url);
echo "<img src='".$url."'>";
?>

请求payload

test.php?url='"/><TTT'"TTT>

从返回包可以看到,htmlunit删除了错误的000ttt’"ttt111内容,使用的payload又失效了。又没办法进行验证是否存在xss了。

<html>
  <head/>
  <body>
    <img src="000111&quot;"/>
  </body>
</html>

不过从上面的实验中可以看出,htmlunit在修正语法的时候,标签名和标签属性是不会被转义和删除的。于是我们不闭合标签,更改payload。

test.php?url=000111"'<TTT'"TTT>

返回包

<img src="00011122" 00ttt'22ttt11'=""/>

这样就可以进行可以检测出没有过滤',这样就可以让burp报html-content xss: the separator is ',but can escape.了。这样验证是否有利用的空间,至于再具体的利用,就需要手动测试了。

总结下html-content的检验,检测 html-content xss应该很简单的,不使用htmlunit渲染进行匹配,就很容易检测出来的。但是考虑dom xss的存在,又不想发送两次请求包。只能根据htmlunit进行语法修正的后的源码调整payload。

0x04 js-content xss检测

在这个插件中,检测js-content xss最容易,因为没有对错误的无法进行修正。

<?php
$url = $_GET['url'];
?>
<script>
var a = <?php echo $url;?>
</script>

请求

test.php?url=000111"'<TTT'"TTT>

返回包

<html>
  <head>
    <script>
//<![CDATA[

var a = "000111"'<TTT'"TTT>";

//]]>
    </script>
  </head>
  <body/>
</html>

使用正则<ttt(.*?)'"ttt(.*?)>进行匹配。判断是否能逃逸当前的分隔符,则使用正则判断,比如
'(.*?)ttt(.*?)'(.*?)ttt(.*?)'如果能匹配到结果,则说明能够逃逸分号。分号的逃逸判断类似。

0x05 dom xss检测

如何检测dom xss,绕了很多弯。比较幸运的是htmlunit是支持返回包的修改的(这样就可以对一些函数进行hook,修改,达到检查dom xss的目的)。
使用如下测试函数,进行返回包的js函数修改、hook。

public class WebConnectionListener extends FalsifyingWebConnection {
    public WebConnectionListener(WebClient webClient) throws IllegalArgumentException {
        super(webClient);
    }

    @Override
    public WebResponse getResponse(WebRequest request) throws IOException {
        WebResponse response = super.getResponse(request);
        String url = response.getWebRequest().getUrl().toString();
        return createWebResponse(response.getWebRequest(), reResponse, response.getContentType(), response.getStatusCode(), "Ok");
    }
}

@org.junit.Test
public void CheckDomXss() throws IOException {
    WebClient webClient = new WebClient();
    webClient.getOptions().setJavaScriptEnabled(true);
    webClient.getOptions().setCssEnabled(false);
    webClient.getOptions().setUseInsecureSSL(true);
    webClient.getOptions().setThrowExceptionOnScriptError(false);
    new WebConnectionListener(webClient);
    try
    {
        String url ="http://127.0.0.1/test.php?id=111";
        HtmlPage page = webClient.getPage(url);
        System.out.println(html);
    } catch (ScriptException e) {
        System.out.println(e.getFailingLine());
        System.out.println(e.getPage().asXml().toLowerCase());
    }
    webClient.close();
}

下面是
document.writeinnerHTML造成的xss,页面进行渲染后,前面的html-content xss检测过程就能检测出来的,但是evallocationSetTimeout函数确实没办法检测出来的。后来想起以前看的js反调试中的hook,能够监控这些函数的参数。在翻资料的时候,发现有前人已经使用hook进行检测dom xss,不过文章很复杂,而我们只需要hook几个简单的函数就可以了。
hookevalSetTimeout函数很顺利。但是location = "xss"location.href="xss"location.replace("xss")却遇到很大的障碍。因为这里是赋值操作,而且更为难得是,无法对location进行修改。

首先遇到问题是,在chrome无法对location对象进行修改,location.href = "xss",这赋值操作,如何拦截尼?幸运的是在htmlunit还能够使用__defineSetter__方法进行拦截。

location.__defineSetter__('href', function(url) {
    append("location",url);
});

接下来location = "xss"如何监控尼?这个纠缠了很久,翻了很多资料,包括看之前那篇hook js检测dom xss的文章(那篇文章也有人在问如何检测location),都没有解决方案。突然既然能修改返回报文,我直接在返回报文中把location = "xss"修改成location.href = "xss"。使用上面的方法就可以进行监控了。

最后是location.replace("xss")这个函数也是无法进行hook的,那我们直接修改location.replace_replace,

var _replace = function(url)
{
    append("location.replace",url);
};

上面的append函数,是判断函数参数或者赋的值,是否包含我们payload字符串,如果包含,则添加一个特定的p标签。插件以此判断该p标签的内容,报告xss漏洞。完整的监控的代码。

<script>
function append(type,payload)
{
    if(payload.indexOf("111000")>-1)
    {
        var para=document.createElement("p");
        var node=document.createTextNode(type + payload);
        para.appendChild(node);
        var element=document.getElementsByTagName("html")[0];
        element.appendChild(para);
    }
}
var _eval = eval;
window.eval = function(string) {
    append("eval",string);
    _eval(string);
};
var _setTimeout = setTimeout;
window.setTimeout = function(code,millisec) {
    append("settimeout",code);
    _setTimeout(code,millisec);
};
var _replace = function(url)
{
    append("location.replace",url);
};
location.__defineSetter__('href', function(url) {
    append("location",url);
});
</script>

0x06 下载地址

成品

源码

0x07 参考

http://xsst.sinaapp.com/example/1-1.php