在假設設計上不存在問題(即人解決某個應用的方式不存在問題)以及改採用的語言以及其他周邊組件是安全的情況下,程序的漏洞就大部分就是由於在實現問題的過程中,程序員對安全的漠視或是對安全的不太瞭解造成的,而從程序的角度看,這種漏洞不外乎是不安全的參數進入不安全的操作中引起的。
    不安全的操作大家都知道有很多,譬如文件讀寫,數據庫查詢,代碼執行以及其他的一些危險函數的使用等等,那麼不安全的參數主要是哪些呢?有人說所有用戶的輸入都是有害的,在我看來輸入可以分兩種,直接的輸入與間接的輸入。直接的輸入是可以看到的,如url裡的參數,瀏覽器與服務器的一些環境變量,用戶提交的Cookie,用戶通過表單進行的輸入等等,對於這些輸入大部分的程序員都會在安全上比較在意,比較注意參數的過濾,因為這些輸入是顯而易見的,觸發比較簡單,甚至一些輸入如果不做過濾的話會導致程序出錯,再加上PHP這種語言對於一些進入的參數的默認保護(Magic Quote選項),所以這種參數現在在大的程序裡比較少出問題,但是另外一種隱式的輸入卻被人們忽略了,那就是來自數據庫(包括Mysql這種數據庫,文本數據庫和一些人常用的cache以及php配置文件等等),可以嘗試為程序做一個流程圖:



處理流程    用戶的輸入==========>      程序處理(過濾)=========>              數據存儲      ==========>            程序處理==========>輸出給用戶
數據流程    原始的數據如'=======>  程序處理(安全的數據如\')==>  Mysql裡存儲(原始的數據如')========>程序處理(處理的是')=========>輸出給用戶



可以看到,如果用戶的輸入暫時性地存儲在數據庫裡然後被取出來使用而沒有加過濾的話是很危險的,因為這個時候數據就是用戶輸入的最原始的數據不受GPC等安全措施保護,另外就是這種漏洞觸發的條件比直接用戶的輸入要多一些操作,所以一般的測試比較難發現,而會被誤認為是安全的。
    上面的模型只是簡單地說明問題的存在,實際情況裡完全不侷限於上面提到的'和mysql等等,實際上,動網使用的將一個'轉換成''的處理Sql注射的方法還是很危險的,就很容易遭受這種攻擊,事實上我也發現過這種問題:)從程序員的角度想想,什麼時候會現這種安全問題呢?數據需要暫時地存儲在某個地方,然後在另外的地方需要從裡面取出來進行操作,那麼什麼時候會這樣什麼時候容易出現問題呢?譬如註冊的時候的用戶名,如果允許'的話就等於是把禍根引入了,因為很多地方都需要使用用戶名,而且用戶名是存儲在數據庫裡的,如果在後面的操作裡不小心把用戶名取出來直接送到數據庫操作裡就會出現問題(或者是將用戶名放到session裡然後進行操作),這種情況下可以看成是數據庫到數據庫的操作,不受GPC影響噹然會出問題啦!當然問題不只是',用於文件操作的 \0呢?通常會被addslashe的\0,如果有從數據庫直接到文件操作的數據流程,危險是很大的。而且在程序員的眼睛裡,可能無意識地認為從數據庫裡出來的東西都是經過檢查的東西,但是事實上常常相反。
    那麼如何避免並且檢測這種漏洞呢?對於開發者首先就是良好的編程習慣以及安全意識,明白數據庫以及緩存文件裡出來的東西一樣不安全,其次就是在進行數據過濾的時候,不要只是暫時地讓數據失去危害,可以考慮永久地讓數據失去危害,譬如在過濾的時候不是將'變成\'等,而是在條件允許的情況下將其直接轉換成 HTML字符',這樣並不影響顯示但是數據卻不再會包含讓數據庫的元字符所以不用擔心注射了,其他的字符可以一樣考慮處理。另外就是儘量對數據庫進行嚴格的設計,實際上在存儲的過程中有一層隱含的數據過濾,譬如數據字段的大小限制了數據的長度,數據字段的類型限制了數據的類型,所以我們儘量在允許的條件下使用數字類型的字段,並且儘量將數據字段的大小縮小,無論是在存儲還是安全上還是很有意義的。對於檢測的人員來說,如果是白盒操作,可以將數據庫的字符類型的字段取出來,然後在程序裡檢查這些字段的去向,實際上就是將視角放到隱含的輸入上檢查問題,譬如我這裡就有段檢查類型的代碼:

<?php
/*Codz By 劍心*/
$host='localhost';
$user='root';
$password='loveshell';
$dbname='discuzl';


$link = mysql_connect($host, $user, $password);
if (!$link) {
  die('Could not connect: ' . mysql_error());
}
echo "Connected successfully\r\n";
if(mysql_select_db($dbname, $link)) {
    echo "Select Database successfully\r\n";
}

$result=mysql_list_tables($dbname);

while ($row = mysql_fetch_row($result)) {
      print "Table: $row[0]\r\n";
      print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n";
        $result2=mysql_query("show full fields from `$dbname`.`$row[0]`");
        while ($row2 = mysql_fetch_row($result2)) {
            if(strpos($row2[1],'int')===false&&strpos($row2[1],'enum')===false&&strpos($row2[1],'decimal')===false&&strpos($row2[1],'date')===false){
                print "字段: $row2[0]\t\t屬性: $row2[1]\r\n";
            }
        }
        print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n";
  }
?>

然後就可以關注這些字段來檢查問題了,當然並不是所有的字段都是可以控制的,關注對字段的insert update 操作可以知道輸入可以有哪些更改,而select之後的操作可以檢查這些字段將會進入哪些危險的操作,而如果是黑盒操作,因為代碼的不透明就只能根據自己的一些探測來猜測對方的代碼是如何實現的來檢測是否含有二次漏洞了。
    文章比較簡單,期待更有意義的東西出來,譬如基於數據庫的Fuzz等等。

by rootshell
資料來源 安全警戒線 www.hackeroo.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 ivan0914 的頭像
    ivan0914

    I'n Blog 之萬象真藏

    ivan0914 發表在 痞客邦 留言(0) 人氣()