• XSS动态检测


    0x00 起

    前一段时间,因为工作原因接触到XSS漏洞检测。前人留下的锅,是采用pyqt webkit来解析网页内容。作为Python webkit框架,相比于PhantomJS,pyqt在捕获错误,重载函数等方面有比较多的优势,但pyqt也有很有缺点:占用资源较多、底层解析还是用C++,许多错误是C++直接抛出的,Python依然无法捕获、历史遗留等等问题。
    最近做毕设,考虑到以上的优缺点,动态解析部分采用了PhantomJS来编写。本文就介绍一下XSS动态解析的思路及部分关键代码。
     

    0x10 漏洞判别标准

    XSS漏洞,说到底还是用户输入被当成页面代码解析了。解析的结果,可能是执行了JS代码,也可能是在页面中创建/修改了某个DOM节点。所以我们将Payload分为两类:第一类,执行了指定的JS代码(alert(1)),第二类,创建了新的DOM节点(<xsstest></xsstest>)。
    根据这两种Payload,自然而然的推出了漏洞判别标准:页面弹窗(在PhantomJS中重载window.alert)、新节点(解析玩页面后,判断document.getElementsByTagName('xsstest')是否为空)。
    page.onAlert = function (message) {
        if(message == xss_mark) {
            xss_exists = 1;
            ret = "Success, xss exists";
            phantom_exit(ret); 
        }
        console.log('Alert: ' + message);
     
        return true;
    };
     
    function check_dom_xss_vul(){
        return document.getElementsByTagName(dom_xss_mark).length;
    }
     
    为了验证检测代码,编写一个简单存在XSS漏洞的页面。
    <?php
    echo $_GET['test'];
    ?>
     
    经测试,访问 http://127.0.0.1:8000/xss.php?test=<img src=1 onerror=alert(1)>,我们的检测代码成功检测到了弹窗,并返回了正确的结果。但是,如果是下面这种情况呢?
    <?php
    $click = $_GET['test'];
     
    echo "<div onclick=$click></div>";
    ?>

     

    0x20 执行事件代码

    很明显,我们需要执行onclick中的代码,才能检测到漏洞。首先我们想到的是触发事件,仅仅是触发click事件,很简单,javascript本身就提供了click事件: document.getElementsByTagName('div')[0].click()。但是javascript也就仅仅提供了click事件的触发函数而已。
     
    但既然代码直接输出在了onclick/onmouseover之类的属性里,我们遍历所有节点的属性,针对onxxxxx的属性值,直接调用eval方法,执行对应的代码就可以了。
    var nodes = document.all;
    for(var i=0;i<nodes.length;i++){
        var attrs = nodes[i].attributes;
        for(var j=0;j<attrs.length;j++){
            attr_name = attrs[j].nodeName;
            attr_value = attrs[j].nodeValue;
            if(attr_name.substr(0,2) == "on"){
                console.log(attrs[j].nodeName + ' : ' + attr_value);
                eval(attr_value);
            }
        }
    }
    访问http://127.0.0.1:8000/xss.php?test=alert(1) 成功执行代码,但新的问题很快出现:并不是所有的JS代码都是以内联的形式写入到HTML代码中的,程序猿们往往更喜欢通过 document.addEventListener 或者 jQuery中的 $('dom').click 直接绑定事件。例子如下:
    <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
     
    <div class="link-area"></div>
     
    <?php
    echo '<script>$("#image").click(function(){$(".link-area").html("'.$_GET['test'].'")});</script>';
    ?>

     

    0x30 触发事件

    所以我们现在需要这样的接口: 能够触发某个DOM节点的某个事件,包括但不仅限于click事件。PhantomJS和Javascript都可能存在这样的接口,但是找遍了PhantomJS,甚至是CasperJS的接口,也只是发现了触发click事件的接口。所以聚焦点重新回到Javascript上来。很快,我们发现了dispatchEvent函数。
    // phantom_finish.js
    var evt = document.createEvent('CustomEvent');
    evt.initCustomEvent(click, true, true, null);
    document.getElementsByTagName("div")[0].dispatchEvent(evt);
     
    成功执行了click事件,但是如何能获取到所有节点的绑定事件呢?有两种方法:
    • 遍历所有节点,获取每个节点绑定的事件
    • 在dom节点加载前,重写addEventListener方法,并将所有的绑定的事件及节点记录到一个数组中。
     
    方法一在遇到jQuery绑定事件的时候扑街了。方法二明显比方法一节省资源,并且测试通过。核心代码如下:
    // phantom_init.js
    _addEventListener = Element.prototype.addEventListener
    Element.prototype.addEventListener = function(a,b,c) {
            save_event_dom(this, a);      // 将所有的绑定事件节点信息存储起来
            _addEventListener.apply(this, arguments);
    };
    这样,我们的JS代码也算告一段落,PhantomJS组件能够执行内联代码及触发所有的绑定事件。万事具备,只欠一个调度系统了~

     

    0x40 调度系统

    XSS扫描是URL粒度扫描,针对网站的每一个链接都要进行测试。XSS检测系统的输入值包括:
    • URL (如:http://127.0.0.1:8000/xss.php?a=1&b=2)
    • method
    • post_data
    • headers
    调度系统的功能就是处理这个URL,拼接对应的payload,并调用PhantomJS组件,检测是否含有XSS漏洞。举个例子,当payload为 <img src=1 onerror=alert(1)> 时,需要调用两次PhantomJS组件,输入的URL分别为:
    • http://127.0.0.1:8000/xss.php?a=<img src=1 onerror=alert(1)>&b=2
    • http://127.0.0.1:8000/xss.php?a=1&b=<img src=1 onerror=alert(1)>

     

    0x50 合

    上述种种,已经基本将动态XSS检测的思路分析透彻。XSS有很多种玩法,在payload中可以带进一些有意思的攻击代码,比如钓鱼、打Cookie、甚至探测网络状况等等不再赘述。
  • 相关阅读:
    107. 二叉树的层次遍历 II
    c#、ASP.NET core 基础模块之一:linq(原创)
    sql 查询 一张表里面的数据 在另一张表中是否存在 和 比对两个集合中的差集和交集(原创)
    winform从table1获取需要的数据转存储到table2中
    Winform学习之随笔一:Log4net
    VS中让用户选择路径
    HttpWebRequest中GetResponse或者说GetRequestStream偶尔超时,或者是各种操作超时造成的假死的一些解决方案
    使用JSON JavaScriptSerializer进行反序列化和序列化时报错,字符的长度超出了MaxJsonLength的长度
    c#中常用集合类和集合接口之接口系列【转】
    c#中常用集合类和集合接口之集合类系列【转】
  • 原文地址:https://www.cnblogs.com/kuoaidebb/p/5787109.html
Copyright © 2020-2023  润新知