[+] Author: fridayy

[+] Team: n0tr00t security team

[+] From: http://www.n0tr00t.com

[+] Create: 2016-10-29

XSS 是典型的瀏覽器端漏洞,由于用戶的輸入未經轉義直接輸出到頁面中,惡意代碼在用戶的瀏覽器中被解析,從而造成危害。傳統的反射型 XSS 可以通過判斷頁面源碼是否含有特定字符串來檢測。但由于 Web 2.0 的快速發展交互越來越復雜,DOM-XSS 也層出不窮,導致傳統的檢測方案的漏報率很高。本文主要介紹了如何利用 PhantomJS + Python 完成動態檢測。

0x01 PhantomJS

既然是動態檢測,那么就需要一個瀏覽器,但普通的瀏覽器在渲染頁面上花費了太多的資源和時間,并不適用。怎么辦?當然開源世界早有解決方案:PhantomJS、PyQt、CEF 等等。對比了一下上手難易程度、文檔豐富程度等,我選擇了 PhantomJS 進行開發。

PhantomJS 是無界面的 Webkit 解析器,提供了 JavaScript API 。由于去除了可視化界面,速度比一般 Webkit 瀏覽器要快很多。同時提供了很多監控和觸發接口,可以方便的操作頁面 DOM 節點,模擬用戶操作等。

0x02 漏洞判別標準

XSS 漏洞說到底還是用戶輸入被當成頁面代碼解析了,解析的結果可能是執行了JS代碼,也可能是在頁面中創建/修改了某個 DOM 節點(有部分過濾,無法執行JS代碼的情況下)。所以我們將 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>";
?>

0x03 執行事件代碼

很明顯,我們需要執行onclick中的代碼,才能檢測到漏洞。首先我們想到的是觸發事件,僅僅是觸發 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>';
?>

0x04 觸發事件

所以我們現在需要這樣的接口:能夠觸發某個 DOM 節點的某個事件,包括但不僅限于 click 事件。 PhantomJS 和 JavaScript 都可能存在這樣的接口,但是找遍了 PhantomJS 的接口,也只是發現了觸發 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 組件能夠執行內聯代碼及觸發所有的綁定事件。萬事具備,只欠一個調度系統了~

0x05 調度系統

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)>

當然 Payload 不止一個,會有很多種玩法,簡單提供幾個基礎 Payload :

'"><img src=1 onerror=alert(1)>
'"><script>alert(1)</script>
';alert(1)//
";alert(1)//
'" onmouseover=alert(1)
javascript:alert(1)
'"></script><img src=1 onerror=alert(1)>
"'></textarea><xsstest>

0x06 更多思考

采用了 Webkit 解析器來檢測XSS漏洞,提高了檢測的覆蓋率,也大幅降低了誤報率。但有些僅在 IE 下有效的漏洞,就無法覆蓋到了。上述種種,已經基本將動態XSS檢測的思路分析透徹。XSS有很多種玩法,在payload中可以帶進一些有意思的攻擊代碼,比如釣魚、打Cookie(配合XSS平臺)、甚至探測網絡狀況等等不再贅述。

最后,再次歡迎對 XSS 利用有各種猥瑣想法的同學來交流,微博 @Fr1day


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/93/