0×00 前言

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

0×01 检测思路

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

0×02 成品

html-content xss检测

1.jpg

js-content xss检测

2.jpg

dom xss检测

3.jpg

0×03 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" rel="external nofollow"  "<=""/> 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。

0×04 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(.*?)'如果能匹配到结果,则说明能够逃逸分号。分号的逃逸判断类似。

0×05 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" rel="external nofollow" 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> 

0×06 下载地址

成品

源码

0×07 参考

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

*本文原创作者:lufei