DEDECMS資料庫執行原理、CMS程式碼層SQL隱碼攻擊防禦思路

Andrew.Hann發表於2014-03-16

我們在上一篇文章中學習了DEDECMS的模板標籤、模板解析原理,以及通過對模板核心類的Hook Patch來對模板的解析流量的攻擊模式檢測,達到修復模板類程式碼執行漏洞的目的

http://www.cnblogs.com/LittleHann/p/3574694.html

通過這段時間的思考,我大概對目前CMS中主流的WEB漏洞進行了大致的分類,這裡給朋友們分享一些我的想法:

1) 本地變數覆蓋型別的漏洞: 在common.inc.php這種本地變數註冊的關口進行流量監控,通過正則規則,防止黑客通過在GET、POST、COOKIE位置提交以下兩類資料:
        1.1) 輸入"未正確初始化的變數",來達到修改程式原本變數的資料型別的目的
        http://www.yunsec.net/a/security/bugs/script/2013/0120/12286.html
        1.2) 覆蓋已經存在的變數達到修改程式碼流的目的
        http://sebug.net/vuldb/ssvid-20859

2) 模板類程式碼執行漏洞,對CMS中負責模板標籤解析的核心檔案進行Hook Patch,檢測模板解析中的流量,對涉及:
http://ha.cker.in/1006.seo
        2.1) 程式碼執行
        2.2) webshell寫入的攻擊模式進行檢測

3) 資料庫注入類漏洞,黑客通過在變數輸入的地方新增額外的攻擊性SQL程式碼來達到修改原始SQL語句的目的: 在CMS中一般有一個核心類專門用來進行資料庫操作,對這個核心類進行Hook,
對即將流入資料庫的流量進行檢測

4) 程式碼注入執行類漏洞,典型的如 $var = "${${phpinfo()}}"(注意,如果是單引號就失效了)這種語法,這種攻擊場景真實存在,但是卻沒有一個很好的"中心流量節點",目前還沒想到好
的方法做Hook Patch。這種程式碼執行常常和模板類程式碼執行同時出現
http://ha.cker.in/1006.seo

5) 利用伺服器錯誤請求、資料庫錯誤請求會被記錄到日誌中(常常是.php形式),然後將webshell寫進日誌的做法進行GETSHELL
http://sebug.net/vuldb/ssvid-24262

6) 利用檔案上傳漏洞,檔案上傳的漏洞主要有以下幾個攻防的點
    1) 利用畸形檔名進行繞過防禦程式碼:
        1.1) shell.asp;.jpg(IIS解析漏洞)
        1.2) shell.PhP(大小寫繞過黑名單)
    2) 利用配置漏洞,CMS一般都會有"允許上傳檔案的字尾、型別"的黑名單限制
        2.1) 管理員自己不小心錯誤配置了"允許上傳檔案的字尾、型別",導致了允許.php這類指令碼的直接上傳
        2.2) 黑客通過別的手段拿到了網站後臺的密碼,進行了配置資訊的修改
        2.3) 通過register_globals=on漏洞,進行了變數覆蓋,進而繞過防禦邏輯,進行非法檔案上傳
    3) 利用一些主流的存在漏洞的檔案上傳開源元件: FCKeditor、kindeditor進行檔案上傳
        3.1) 防禦程式碼漏洞: asp.asp;jpg
        3.2) IIS解析漏洞: 建立shell.asp/資料夾,則在這個目錄下的任意副檔名的檔案都可以被當作asp執行
        

以上的思路,我會在今後的文章中逐一和大家一起學習,並努力找到一種修復CMS漏洞的底層方法。

這篇文章中,我們一起來學習一下DEDECMS中涉及資料庫操作的程式碼邏輯,並思考怎麼在"關鍵流量節點"上進行Hook Patch,從而達到解決資料庫注入類漏洞的目的

本文主要分為以下幾個部分:

1. DEDECMS中資料庫操作的方法、原理
2. 對資料庫查詢的SQL流量的攻擊模式檢測

 

相關學習資料

http://blog.sina.com.cn/s/blog_56f273130100ul0l.html
http://www.chinab4c.com/dedecmsjiaocheng/201112/22944.html
http://hi.baidu.com/tong_jh/item/e64b2a402fed8c11886d107e
http://blog.chinaunix.net/uid-286494-id-2134474.html
http://open.taobao.com/doc/detail.htm?spm=0.0.0.0.FytuX1&id=813

 

1. DEDECMS中資料庫操作的方法、原理

在開始學習DEDECMS中資料庫操作核心類原理之前,我覺得有兩點要先明確一下:

1) DEDECMS嚴格來說是一個MVC框架,很適合網站開發者在其上進行二次開發
2) 因為DEDE從架構上是一個MVC架構,所以很多的底層操作,例如資料庫操作、資料變數清洗、輸入變數本地化、模板解析的關鍵程式碼都會集中在幾個特定的檔案中,即OOP的設計思想,
  這就為我們針對不同種類的漏洞做流量分析提供很好的基礎出發點

既然是基於MVC的二次開發法,我們先編寫一些PHP程式碼,測試一下怎麼使用DEDE提供的單例模式(工廠模式)資料庫操作類來進行方便的資料庫操作

在DEDE網站的根目錄(注意,是網站的根目錄)下編寫test.php

E:\wamp\www\dede5.7\test.php

<?php 
    //引入涉及資料庫操作的核心類檔案
    require_once (dirname(__FILE__) . "/include/common.inc.php");
    //遵從單例模式(工廠模式),直接呼叫$dsql類進行資料庫操作
    //IsTable: 判斷指定的表是否存在
    if($dsql->IsTable('dede_admin'))
    {    //1. SetQuery+Execute: 執行一個帶返回結果(結果陣列)的SQL語句,如SELECT,SHOW等
        $sql = "SELECT value FROM #@__sysconfig where varname='cfg_mb_open'";
        $dsql->SetQuery($sql);
        $dsql->Execute();

        //2. ExecuteNoneQuery: 執行一個不返回結果集(陣列)的SQL語句,如update,delete,insert等,但它會返回mysql的執行結果,例如插入的row的ID等資訊
        $sql = " DELETE from `#@__mytag` WHERE aid=1";
        $rs = $db->ExecuteNoneQuery($sql); 

        //3. ExecuteNoneQuery2: 執行一個返回影響記錄條數的SQL語句,如update,delete,insert等
        $sql = "UPDATE `#@__downloads` SET downloads = downloads+1 WHERE hash='$hash' ";
        $rs = $dsql->ExecuteNoneQuery2($sql);
    }
?>

以上的3種SQL程式碼執行方法就是DEDECMS中所有涉及到資料庫操作所使用的方法了,其他的方法都是這3種的別名方法,即轉接層。

可以看到在MVC模式下進行二次開發是很方便的,這是很多開源框架:CI、TP、主流框架WordPress的常用開發模式接下來,我們來深入原始碼,學習一下

require_once (dirname(__FILE__) . "/include/common.inc.php");

這個檔案是DEDECMS中的一個核心配置檔案,其中包含了很多方面的內容,我們今後學習變數覆蓋類漏洞的攻防還會涉及到這個檔案,今天我們重點關注的是這個檔案中和資料庫有關的程式碼

/*
    引入資料庫類
    1. 如果在安裝時選擇了mysqli資料庫連線方式,並且當前PHP支援了mysqli模組,則包含dedesqli.class.php檔案
    2. 預設情況下,包含dedesql.class.php
*/
if ($GLOBALS['cfg_mysql_type'] == 'mysqli' && function_exists("mysqli_init"))
{
    require_once(DEDEINC.'/dedesqli.class.php');
} 
else 
{
    require_once(DEDEINC.'/dedesql.class.php');
}

dedesql.class.php和dedesqli.class.php程式碼邏輯上是一樣的,只有在關鍵函式的最後會加上一個字母"i",表示是原始mysql函式的改進(improve)版本(當然嚴格來說,這兩個檔案在某些細節上還是不一樣的,例如dedesql.class.php的ExecuteNoneQuery2函式就存在一個SQL隱碼攻擊漏洞,而dedesqli.class.php則做了有效的過濾,這些問題都是我們在本文需要解決的問題,我們的目標就是找到"所有資料庫請求流量的最終的節點",在這個節點上運用正則規則進行攻擊模式檢測)

require_once(DEDEINC.'/dedesql.class.php');

這個類非常龐大,裡面封裝了資料庫Meta資訊i獲取、資料庫操作、SQL錯誤執行資訊記錄...

我們逐一來學習一下:

/*
    在工程所有檔案中均不需要單獨初始化這個類,可直接用 $dsql 或 $db 進行操作
    為了防止錯誤,操作完後不必關閉資料庫
*/
$dsql = $db = new DedeSql(FALSE);

$dsql = $db = new DedeSql(FALSE);

//用外部定義的變數初始類,並連線資料庫
function __construct($pconnect=FALSE,$nconnect=FALSE)
{
    //標識是否關閉資料庫
    $this->isClose = FALSE;
    //標識是否開啟安全檢查
    $this->safeCheck = TRUE;
    //標識是否已經存在先前的資料庫連線資源識別符號(預設為FALSE)
    $this->pconnect = $pconnect;
    //標識是否需要重新進行連線(預設為FALSE)
    if($nconnect)
    { 
        //如果需要重新進行連線,呼叫Init進行初始化
        $this->Init($pconnect);
    }
}

$this->Init($pconnect);

function Init($pconnect=FALSE)
{
    $this->linkID = 0; 
    /*
        1. 這裡是一個關鍵,程式"信任"了來自全域性變數$GLOBALS中和資料庫配置資訊有關的資料,用以之後進行資料庫連線
        2. 利用全域性變數覆蓋+資料庫連線方向劫持的繞過漏洞就是源自於這個不太安全的步驟
        3. 個人覺得,這種關鍵資訊不能從記憶體中去提取,應該直接從配置檔案中去讀取會比較安全一點
        4. 另外,完全可以使用持久單例模式,一次資料庫連線完成之後,之後的請求就可以複用這個連線識別符號,不用再重複連線、關閉了
    */
    $this->dbHost   =  $GLOBALS['cfg_dbhost'];
    $this->dbUser   =  $GLOBALS['cfg_dbuser'];
    $this->dbPwd    =  $GLOBALS['cfg_dbpwd'];
    $this->dbName   =  $GLOBALS['cfg_dbname'];
    $this->dbPrefix =  $GLOBALS['cfg_dbprefix'];
    $this->result["me"] = 0;
    //連線資料庫
    $this->Open($pconnect);
}

以上就是我們在inlcude這個common.inc.php後,程式進行的資料庫連線初始化工作,之後,我們就可以方便地在程式中呼叫$dsql、或$db的方法進行SQL操作了

從某種程式上來說,這實現了一個工廠模式(雖然這樣說可能不太準確),但是這極大的方便了我們在DEDE的框架內進行二次開發確實不爭的事實,理解了這種思想對我們理解CI、TP這樣的開源框架的基本原理也是大有裨益的

接下來,我們回到剛才的話題,前面說過,在DEDE中的SQL操作只有3種,也就是說,所有的SQL請求流量最終都會通過這4個函式得以實現,我們一起來對這4個函式進行一下程式碼審計學習,我會直接COPY原始的DEDECMS V5.7的原始碼,並盡我所能去在程式碼中加上我的理解註釋

0x1: SetQuery+Execute

$sql = "SELECT value FROM #@__sysconfig where varname='cfg_mb_open'";
$dsql->SetQuery($sql);

//設定SQL語句,會自動把SQL語句裡的#@__替換為$GLOBALS['cfg_dbprefix'](在配置檔案中為$cfg_dbprefix)
function SetQuery($sql)
{
    $prefix="#@__";
    /*
        1. 這樣做的目的是為了相容多個DEDECMS同時安裝在同一個資料庫中,它們可以使用不同的字首
        2. 在原始的SQL中,所有的字首都採用一個佔位符"#@__",然後在程式碼執行前,根據當天配置的字首(例如"dede_")進行替換。這是一種典型的介面卡程式碼層的思想
    */
    $sql = str_replace($prefix,$GLOBALS['cfg_dbprefix'],$sql);
    //將替換後的SQL程式碼賦值給$this->queryString,用以之後傳送給資料庫
    $this->queryString = $sql;
}

$dsql->Execute();

//執行一個帶返回結果的SQL語句,如SELECT,SHOW等
function Execute($id="me", $sql='')
{
    global $dsql;
    /*
        1. 這是第一個要重點注意的關鍵程式碼,我們知道,Init這個函式會從全域性變數$GLOBALS中獲取資料庫連線資訊,從而給黑客以利用本地變數覆蓋來達到修改資料庫連線方向的目的。
       那我們要問自己一個問題了,什麼時候能觸發這個Init的執行條件呢? 2. 答案很明顯: $dsql->isInit == FLASE的時候,那什麼時候能滿足這個條件呢? 3. 答案是在每次指令碼請求中的第一次涉及資料庫操作的時候(GetOne、Execute、ExecuteNoneQuery、ExecuteNoneQuery2中任意一種)的時候 4. 因為我們知道: PHP是一種解釋性的指令碼語言,每次的指令碼解釋執行都會有自己獨立的程式碼空間,指令碼請求之間不會互相共享記憶體。所以在每次的指令碼請求中,$dsql這個物件初始都
       是null的,$dsql->isInit的初始預設值也是FALSE,在一個指令碼請求中多次出現資料庫操作的時候,從第二次開始的資料庫請求就不需要再重新進行資料庫連線了(除非程式碼強制
       進行重連線) 5. 這種在同一個指令碼中的"持久化連線"和ADO.NET中的持久化資料庫連線不是一個層次的技術,要注意區別 6. 這也給了我們一點關於漏洞挖掘的啟示,如果想挖掘"利用全域性變數覆蓋+資料庫連線方向劫持的繞過漏洞",就必須尋找那種在指令碼中第一次出現的、黑客可以控制輸入引數的資料庫
       操作函式,這也是一種程式碼審計的思路
*/ if(!$dsql->isInit) { $this->Init($this->pconnect); } //如果這個連線已經關閉,則重新開啟連線 if($dsql->isClose) { $this->Open(FALSE); $dsql->isClose = FALSE; } if(!empty($sql)) { $this->SetQuery($sql); } /* 1. 這個80Sec為DEDE提供的SQL語句安全檢查 2. 個人愚見: 覺得這個Hook點還不夠"中心化"、"底層化",我的觀點是在SetQuery這個函式進行Hook Patch,因為SetQuery是整個dedesql.class.php中所有涉及到SQL操作都
       會涉及到的函式,在這個點進行流量分析,能做到更好的覆蓋效果
*/ if($this->safeCheck) { CheckSql($this->queryString); } $t1 = ExecTime(); //呼叫PHP原生的mysql擴充套件介面,執行資料操作 $this->result[$id] = mysql_query($this->queryString,$this->linkID); //記錄執行時間 if($this->recordLog) { $queryTime = ExecTime() - $t1; $this->RecordLog($queryTime); } /* 記錄資料庫執行錯誤資訊,方便除錯,這裡可能涉及到另一種利用傳送附帶webshell程式碼的錯誤伺服器、資料庫請求來將webshell注入日誌中達到getshell的目的,不過這不是資料
     庫防禦方案能解決的問題,這屬於另一類解決方案了,我們之後的文章中會談到這類漏洞
*/ if(!empty($this->result[$id]) && $this->result[$id]===FALSE) { $this->DisplayError(mysql_error()." <br />Error sql: <font color='red'>".$this->queryString."</font>"); } }

0x2: ExecuteNoneQuery

//執行一個不返回結果的SQL語句,如update,delete,insert等
function ExecuteNoneQuery($sql='')
{
    global $dsql;
    //這裡的注意點和Execute函式是一樣的
    if(!$dsql->isInit)
    {
        $this->Init($this->pconnect);
    }
    if($dsql->isClose)
    {
        $this->Open(FALSE);
        $dsql->isClose = FALSE;
    }
    if(!empty($sql))
    {
        $this->SetQuery($sql);
    }else{
        return FALSE;
    }
    //DEDE實現的一種引數化查詢方法
    if(is_array($this->parameters))
    {
        foreach($this->parameters as $key=>$value)
        {
            $this->queryString = str_replace("@".$key,"'$value'",$this->queryString);
        }
    }
    //SQL語句安全檢查,和之前的一樣
    if($this->safeCheck) CheckSql($this->queryString,'update');
    $t1 = ExecTime();
    $rs = mysql_query($this->queryString,$this->linkID);
    
    //查詢效能測試
    if($this->recordLog) {
        $queryTime = ExecTime() - $t1;
        $this->RecordLog($queryTime);
        //echo $this->queryString."--{$queryTime}<hr />\r\n"; 
    }
    return $rs;
}

0x3: ExecuteNoneQuery2

//執行一個返回影響記錄條數的SQL語句,如update,delete,insert等
function ExecuteNoneQuery2($sql='')
{
    global $dsql;
    if(!$dsql->isInit)
    {
        $this->Init($this->pconnect);
    }
    if($dsql->isClose)
    {
        $this->Open(FALSE);
        $dsql->isClose = FALSE;
    }

    if(!empty($sql))
    {
        $this->SetQuery($sql);
    }
    if(is_array($this->parameters))
    {
        foreach($this->parameters as $key=>$value)
        {
            $this->queryString = str_replace("@".$key,"'$value'",$this->queryString);
        }
    }
    $t1 = ExecTime();
    mysql_query($this->queryString,$this->linkID);
    
    //查詢效能測試
    if($this->recordLog) {
        $queryTime = ExecTime() - $t1;
        $this->RecordLog($queryTime);
        //echo $this->queryString."--{$queryTime}<hr />\r\n"; 
    }
    
    return mysql_affected_rows($this->linkID);
}

 以上3個函式在DEDECMS中的不同資料庫操作場景中出現,它們提供不同粒度的SQL操作介面,但對於程式碼安全審計者來說,我們關注的並不是它們的業務場景的功能,我更注重的是關鍵節點流量的攻擊模式檢測。即對SetQuery這個函式進行Hook Patch,檢測所有通過它的流量。

 

2. 對資料庫查詢的SQL流量的攻擊模式檢測

在進行Hook Patch之前,我們首先要解決一個問題,SQL隱碼攻擊都有什麼樣的攻擊模式,我們該怎樣把它們抽象成正則規則來進行模式匹配呢?

這裡參考了一篇部落格的思路

http://blog.chinaunix.net/uid-286494-id-2134474.html

不過它和我們的應用場景還不太一樣,他寫的SNORT規則是基於HTTP層的流量檢測,而我們這裡要做的SQL Inject Hook Patch是在資料庫執行層做注入檢測,我們面對的是純的SQL語法。我們必須結合SQL語法的自身情況進行分析,找到一種好的方法來區分出正常的業務SQL、以及攻擊性SQL。

根據我自身的經驗來說,確定一種規則不能僅僅考慮能不能有效地檢測出注入SQL,還要考慮另一個方面: "誤報",我們的規則不能太嚴,否則會造成對正常的業務SQL造成誤攔截,而這個規則的優化過程應該是一個震盪曲線,即一個不斷修改、精細化的過程。大致的步驟可以是這樣:

1. 根據目前手上掌握的攻擊SQL,對這些語句進行"骨架抽取",找出它們共同的正則特徵
2. 編寫僅僅剛好夠覆蓋這些特徵的正則規則
3. 將這些正則規則上線測試執行,同時做好攔截、誤報、漏報記錄
4. 定期對日誌記錄進行梳理,根據誤報、漏洞的情況進行小範圍的正則規則修改,注意是小範圍的修改,一次儘量只作剛好能解決現有的誤報、漏洞問題的修改
5. 重複迴圈3、4的過程,不斷達到誤報、漏洞、準確性的一個平衡點

我目前就是在做3、4的這個迴圈過程,希望能在不斷的攻防分析中找到一種好的SQL隱碼攻擊模式的檢測模式,分享一下我的思路,也希望有更好想法的朋友能不吝賜教,分享一些別的檢測想法

/*
    檢測傳入的SQL語句是否是攻擊性SQL。即注入性檢測
    返回1: 有攻擊性
    返回0: 沒有攻擊性
*/
public function CheckSql($db_string)
{
/*
    規則1:
    最常見的注入點往往發生在where子句的and邏輯表示式後面,黑客通過在and後面的子句中構造:
        1) 子查詢來直接進行非法資料獲取(以獲取資料為目的)
        2) 或者進行盲注推理(逐字元二分推理)
        3) Error Based Inject(報錯注入)
    典型語句如下:
    1) error based group by inject
    select * from admin where id=5 and name='littlehann' order by=5 and (select 1 from(select count(*),concat((select password from users where 
username=0x41646d696e),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a) -- 2) ASCII、ORD Bitwise Blind Inject select * from admin where id=5 and name='littlehann' order by password,if((substring(password,1,1) > 'F'),1,2)--
*/ $express_1 = "/([A-Za-z])?(where(\s)*)(.)*?(concat\(\).*|char|(chr.*){4,}|floor\(\).*|substr(ing)?.*|ascii\(\).*|ord\(\).*)/i"; /* 規則2: 黑客常用利用where子句的注入點,進行union select注入探測,目的是獲取目標的表、庫結構資訊。為進一步滲透作準備。 典型的語句如下: 1) volumn numbers detection where 1=2 union select 1, from dual where 1=2 union select 1,1 from dual where 1=2 union select 1,1,1 from dual ... */ $express_2 = "/([A-Za-z])?(where).*(union)(\s)*(all)?(\s)*select(\s)*((\d|null),(\s)*){2,}/i"; /* 規則3: 在sql查詢中,有一些敏感關鍵字是不允許使用的 典型語句如下: 1) Time Delay Based Inject、DDOS(基於時間延遲的盲注、或者DDOS) select * from admin where id=5 and name='littlehann' or sleep(ord(substr(password,1,1)))-- select * from admin where id=5 and name='littlehann' or sleep(9999999990999999)-- select * from admin where id=5 and name='littlehann' or benchmark(ord(substr(password,1,1))*1000000,MD5(1))-- 2) load_file、outfile important data leak select id,name from admin where id=5 and name='littlehann' and 1=2 union select 1,concat(select loadfile '...') 3) database api funcion always-true inject detection select * from admin where id=5 and name='littlehann' or database() = database() */ $express_3 = "/[^0-9a-z@\._-]{1,}(sleep|benchmark|waitfor|load_file|outfile|(database\(\).*){1,}|((current_|system_){0,1}user\(\).*){1,}|@@version)
[^0-9a-z@\.-]{1,}/i
"; /* 規則4: 黑客在滲透測試的前期,會使用手工方法、或自動化的掃描工具,在SQL查詢中"拼接"一種"注入性永真" 典型語句如下: 1) always-true detection(對於永真的位置如果出現在where子元素的第二個位置判斷為注入探測的可能性更大,即and後面跟上永真) select * from admin where id=5 and 1=1 */ $express_4 = "/([A-Za-z])?(where)(.|\s)*?(or|and|like)(\s)(('\d'|\d)(=|>|<|like)('\d'|\d))/i"; /* 規則5: 黑客在進行注入的時候,常常會使用到一些註釋符,目的是在注入攻擊性paylaod之後,直接關閉原始SQL語句,避免引號、閉合導致的SQL語法錯誤,使SQL隱碼攻擊成功執行 典型語句如下 1) #、-- Comment Based Inject select g.goods_barcode,g.payment_ft,g.goods_sn,c.color_name,s.size_name,g.id,g.goods_id,g.color_id,g.size_id from order_return_goods g,size
s,color c where g.size_id=s.size_id and g.color_id=c.color_id and g.return_order_id='52099' UNION ALL SELECT NULL, NULL, NULL, NULL# AND
'WnZS'='WnZS'
*/ $express_5 = "/([A-Za-z])?(where(\s|.)*)(#.*|--)/i"; if (preg_match($express_1, $db_string) || preg_match($express_2, $db_string) || preg_match($express_3, $db_string) || preg_match($express_4,
$db_string) || preg_match($express_5, $db_string)) { //die("detected!!!"); return 1; } else { //die("good"); return 0; } }

解決了規則問題,我們現在可以開始我們本文的真正目的了: CMS程式碼漏洞修復

Hook Patch Point

E:\wamp\www\dede5.7\include\dedesql.class.php -> SetQuery

E:\wamp\www\dede5.7\include\dedesqli.class.php -> SetQuery

//設定SQL語句,會自動把SQL語句裡的#@__替換為$this->dbPrefix(在配置檔案中為$cfg_dbprefix)
function SetQuery($sql)
{
    $prefix="#@__";
    $sql = str_replace($prefix,$GLOBALS['cfg_dbprefix'],$sql);
    
    if($this->CheckSql($sql) == 1)
    {
        die("Request Error!");
    } 
    $this->queryString = $sql;  
}

 
public function CheckSql($db_string)
{ 
    $express_1 = "/([A-Za-z])?(where)(.|\s)*?(concat|char|(chr){4,}|case|floor|#.*|--)/i"; 
     
    $express_2 = "/([A-Za-z])?(where).*(union)(\s)*(all)(\s)*select(\s)*(\d|null,(\s)*){2,}/i";
     
    $express_3 = "/[^0-9a-z@\._-]{1,}(sleep|benchmark|load_file|outfile|(user\(\).*){1,})[^0-9a-z@\.-]{1,}/i";
    if (preg_match($express_1, $db_string) || preg_match($express_2, $db_string) || preg_match($express_3, $db_string)) 
    { 
        //die("detected!!!"); 
        return 1;
    }  
    else
    {
        //die("good");
        return 0;
    }
}

經過測試,拿目前DEDE主流的POC進行滲透,防禦效果較好,不過正如我們之前說的,這個正則規則需要一個不斷地優化、修正過程。正如那句名言一樣: 攻防對抗是一個長期的動態的過程,需要我們不斷的去擴充思維,從攻擊者、防禦者兩方面同時去思考。

我個人愚見: 目前雖然有烏雲等漏洞批量平臺不斷地幫助開源WEB系統廠商去發現並修補漏洞,但總體來說,防守方還是處於一種被動防守的情況。而且比起被動防守來說,更大的問題在於,大部分的網站對自己的WEB系統出現的漏洞不具備快速的響應能力,更不用說很多中小站長在阿里雲買了伺服器之後,在上面裝了一個DEDEV5.7之後,缺乏經常性的程式碼維護,導致了出現了高危漏洞的時候,這些站長沒有及時修補漏洞,進行導致被黑客滲透入侵。這樣的情況在阿里雲ECS上的情況尤其嚴重。

鑑於以上的情況,我提出2點YY(僅僅是YY)

1. 參考雲服務的思想,雲服務商直接提供"雲CMS"服務,使用者可以選擇需要購買什麼型別的CMS(例如DEDE、ECSHOP)、版本也可以自己定製。雲服務商在服務端統一維護一套WEB系統程式碼,進行嚴格的程式碼審計和加固,這樣可以起到和堡壘主機同樣的效果,通過放大單個節點的風險、從而減小防禦範圍面。

2. 將IDS的流量分析思想融入程式碼安全審計中,將目前遇到的所有CMS漏洞進行歸類,找到最底層的流量節點,對這些核心檔案進行Hook Patch,最終的目的是抽象出一個漏洞防禦規則庫,達到一勞永逸防禦現有程式碼、以及可能出現的0DAY的威脅,因為比起對單個檔案的修補,對一類漏洞,對底層程式碼邏輯的Hook,是可以達到提前預判的效果的

以上兩點是我個人的YY,但是我覺得,未來的WEB漏洞的攻防應該有一種更加有效、有概括性的修補方案。就像windows的里程碑技術: DEP、SageSEH、ASLR等技術,都是在做歸類性的漏洞修復,這些技術修復的不是某個漏洞,而是一整類漏洞,並同時很大程度上防禦了很多未知的漏洞,這種優秀的思想是很值得借鑑的。

 

Copyright (c) 2014 LittleHann All rights reserved

 

相關文章