XSS報警機制(前端防火牆:第二篇)

wyzsk發表於2020-08-19
作者: Black_Hole · 2016/03/22 10:21

0x00 前言


在第一章結尾的時候我就已經說了,這一章將會更詳細的介紹前端防火牆的報警機制及程式碼。在一章出來後,有人會問為什麼不直接防禦,而是不防禦報警呢。很簡單,因為防禦的話,攻擊者會定位到那一段的JavaScript程式碼,從而下次攻擊的時候繞過程式碼。如果不防禦而報警的話,攻擊者會降低警覺,不會在看JavaScript程式碼(至少我是這樣)。回到正題,下面說的程式碼,是基於thinkphp框架和bootstrap3.3.5框架。如果你的網站沒有使用thinkphp3.2.3框架的話,可以參照我的思路重新寫一個。這裡我強調一下“前端防禦XSS是建立在後端忘記做過濾,沒有做過濾,疏忽做過濾的基礎上的...

0x01 前端要做的事


其實標題應該改成“XSS報警機制”的,因為在這一章裡使用了大量的後端程式碼。但是第一章的標題都出來了,也沒法改了。

前端要做的事情在第一章的時候就已經說了,程式碼如下:

p1

現在我們就是針對第38行進行修改,改成我們後臺接受的API URL。就像這樣:

p2

對,就這一行。沒有其他程式碼。在實際的線上環境中,也只需要上面5行。可以直接copy到您的線上環境中,記得把倒數第二行的url改成自己的地址就行了。難道就那麼簡單?不,0x05節還有一部分前端程式碼。0x01~0x04主要是針對於平臺。

0x02 資料庫要做的事


一共兩個表。fecm_user和fecm_bugdata。

fecm_user的欄位資訊如下:

p3

  • name:管理員賬戶名
  • md5name:3次name值的md5
  • password:3次密碼的md5
  • email:管理員郵箱
  • create_date:管理員建立時間

為了安全起見(其實就是懶)沒有寫新增管理員的,自行在資料庫裡新增

fecm_bugdata的欄位資訊如下:

p4

  • url:漏洞的url地址
  • category:漏洞型別
  • cookies:攻擊者的cookies
  • ua:攻擊者的User-Agent
  • hxff_ip:攻擊者的HTTP_X_FORWARDED_FOR
  • hci_ip:攻擊者的HTTP_CLIENT_IP
  • ra_ip:攻擊者的REMOTE_ADDR
  • time:攻擊者攻擊的時間
  • fixes:漏洞是否修復(0為未修復,1為已修復)

0x03 後端要做的事


因為後端程式碼太多,所以我就說一些核心的後端處理程式碼。

在0x01節裡,有個核心的程式碼是new Image().src = 'http://fecm.cn/Api/addVul/';

接下來我們來說說這個Api的處理方式(ThinkPHP程式碼)

#!php
public function addVul(){
    if(I('get.category','','int') == ""){
        $this->ajaxReturn(array(
            "typeMsg" =>  "error",
            "msgText" =>  "漏洞型別錯誤",
        ));
    }
    switch (I('get.category','','int')) {
        case '1':
            $vul['category'] = "觸發alret函式";
            break;
        case '2':
            $vul['category'] = "發現不在白名單裡的第三方JavaScript資源";
            break;
        default:
            $this->ajaxReturn(array(
                "typeMsg" =>  "error",
                "msgText" =>  "漏洞型別錯誤",
            ));
            break;
    }
    if($_SERVER['HTTP_X_FORWARDED_FOR'] === null){
        $vul['hxff_ip'] = "攻擊者沒有透過代理伺服器訪問";
    }else{
        $vul['hxff_ip'] = I('server.HTTP_X_FORWARDED_FOR'); //獲取攻擊者的HTTP_X_FORWARDED_FOR
    }
    if($_SERVER['HTTP_CLIENT_IP'] === null){
        $vul['hci_ip'] = "攻擊者資料包頭部沒有HTTP_CLIENT_IP";
    }else{
        $vul['hci_ip'] = I('server.HTTP_CLIENT_IP');//獲取攻擊者的HTTP_CLIENT_IP
    }
    $vul['ra_ip'] = I('server.REMOTE_ADDR');    //獲取攻擊者的REMOTE_ADDR
    $vulcookie    = I('cookie.');   //獲取攻擊者的cookies
    for($i = 0;$i<count($vulcookie);$i++){
        $vul['cookies'] .= array_keys($vulcookie)[$i].'='.$vulcookie[array_keys($vulcookie)[$i]].'; ';  //拼接成方便檢視的cookies格式
    }
    $vul['url']   = I('server.HTTP_REFERER');   //獲取攻擊者攻擊成功的url
    $vul['ua']    = I('server.HTTP_USER_AGENT');    //獲取攻擊者的User-Agent
    $vul['time']  = date("Y-m-d");  //獲取攻擊者攻擊的時間
    $vul['fixes'] = 0;  //預設為漏洞未修復
    $bugData = M('bugdata');    //連線fecm_bugdata資料庫
    $bugData->data($vul)->add();    //新增到資料庫中
}

因為這裡是接受攻擊資訊,不能有管理員驗證。

後臺有一個資料庫視覺化的表格,這裡我使用的Chart.js,下面是後端程式碼:

#!php
public function index(){
    $reportForm = M('bugdata'); //連線fecm_bugdata資料庫
    $dateTimeLabels = [];
    $dateTimeTotal = [];
    for($i = 0;$i < 7;$i++){    //獲取近7天的資料
        $time = date("Y-m-d",strtotime(-$i." day"));
        array_unshift($dateTimeLabels,$time);
        $data['time'] = array('like','%'.$time.'%');
        array_unshift($dateTimeTotal,$reportForm->where($data)->count());
    }
    $reportForm = json_encode(["Labels" => $dateTimeLabels,"Total" => $dateTimeTotal]); //轉化成json格式
    $this->assign('reportForm',$reportForm)->assign('total',total());   //交給前端模組
    $this->display();   //前端頁面生成
}

前端程式碼:

#!js
var lineChartData = {
    labels :eval({$reportForm})['Labels'],
    datasets : [
        {
            fillColor : "rgba(151,187,205,0.5)",
            strokeColor : "rgba(151,187,205,1)",
            pointColor : "rgba(151,187,205,1)",
            pointStrokeColor : "#fff",
            data : eval({$reportForm})['Total']
        }
    ]
}
var myLine = new Chart(document.getElementById("Statistics").getContext("2d")).Line(lineChartData);

實際的效果圖:

p5

p6

p7

0x04 讓我們實際測試一下


程式碼就用0x01節的程式碼。我們輸入<script>alert(1)</script>。看一下:

p8

我們再去平臺看一下:

p9

p10

成功顯示了。

0x05 檢測第三方js資源是否為xss指令碼


這一節需要用到之前長短短分享的程式碼:

#!js
for(var i=0,tags=document.querySelectorAll('iframe[src],frame[src],script[src],link[rel=stylesheet],object[data],embed[src]'),tag;tag=tags[i];i++){ 
    var a = document.createElement('a'); 
    a.href = tag.src||tag.href||tag.data; 
    if(a.hostname!=location.hostname){ 
        console.warn(location.hostname+' 發現第三方資源['+tag.localName+']:'+a.href); 
    }
}

但是他這裡只是在console裡顯示,沒有進一步的操作,而且他這裡同時檢測了iframe、frame、script、link、object、embed標籤,對我們來說只需要script標籤就行了,於是我重寫了這段程式碼,首先我們需要一個白名單列表,用於放置網站允許第三方載入的url地址:

#!js
var scriptList = [
    location.hostname,
]

這裡只是預設的只允許當前域名載入,打擊愛可以根據自己的需要新增。

然後就是獲取當前網頁的所有script標籤:

#!js
var webScript = document.querySelectorAll('script[src]');

在把當前的地址賦值var webHost = location.hostname;至於為什麼不放在for迴圈裡,因為根據js最佳化規則,for迴圈裡避免多次一樣的賦值。

接下來就是for迴圈裡的程式碼了:

#!js
for(var i = 0;i < webScript.length;i++){
    var a = document.createElement('a');    //建立一個新的a標籤,方便取值
    a.href = webScript[i].src;  //把script裡的src賦值給a標籤裡的href屬性
    if(a.hostname != webHost){  //對比,是否為第三方資源
        for(var j = 0;j < scriptList.length;j++){
            if(a.hostname != scriptList[i]){    //判斷當前的第三方資源是否在白名單裡
                new Image().src = 'http://fecm.cn/Api/addVul/category/2';   //傳送給FECM
            }
        }
    }
}

這裡我做了一個測試,載入hi.baidu.com的資源:

p11

重新整理後,開啟FECM平臺,看一下:

p12

p13

0x06 結語


因為窮,沒有伺服器和域名,也沒法新增郵件自動提醒功能了。感興趣的可以自己新增,如果後來我有錢了,我買個伺服器,會新增郵件自動提醒的,第一時間會在烏雲社群裡釋出。本來打算採用ED的on事件攔截程式碼的,但是發現on事件在程式裡也會大量使用,索性就沒有新增,如果你有思路

下載地址:http://pan.baidu.com/s/1jGVP7Ps

使用時記得在Application\Home\Conf\config.php改下配置(我已經全部加了註釋,即使不會thinkphp的也可以搭建)

個人程式碼寫的沒有多好,思路可能也比較爛。如果您有什麼意見歡迎提出來,我會進一步修改的。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章