您在這裡

[嚴重漏洞] 立即更新 Drupal 7.x 到 7.32

amouro's 的頭像
amouro 在 2014-10-16 (四) 01:14 發表

SA-CORE-2014-005 - Drupal core - SQL injection

今天午夜所發佈的 Drupal 核心 SQL injection 漏洞更新,請立即更新到 Drupal 7.32
或暫時使用 Patch 修正 /includes/database/database.inc 
Patch: https://www.drupal.org/files/issues/SA-CORE-2014-005-D7.patch

詳細說明:

這是 9 月 16 由德國 SektionEins [1]公司所發現並聯繫 Drupal 的安全小組,證明這個問題的存在。當時 Drupal 的團隊請求暫緩公告這個嚴重的問題,並於今日(10/15)發佈 7.32 的核心安全性更新。

所發現的 SQL Injection ,可能會讓惡意的使用者在未經授權的狀況下,由遠端執行任意的 SQL 查詢,借此控制 Drupal 站台,甚至執行程式。
 
問題發生在 Drupal 7 使用的 SQL 語法宣告規則,其中有一支 expandArguments 的函式,是專門用來展開陣列,並產生 SQL 語法中 “IN” 這項指令的程式。這個 expandArguments 函式,正是這次更新 Patch 的重點。
 
protected function expandArguments(&$query, &$args) {
      $modified = FALSE;

      // If the placeholder value to insert is an array, assume that we need
      // to expand it out into a comma-delimited set of placeholders.
      foreach (array_filter($args, 'is_array') as $key => $data) {
        $new_keys = array();
        foreach ($data as $i => $value) {
          // This assumes that there are no other placeholders that use the same
          // name.  For example, if the array placeholder is defined as :example
          // and there is already an :example_2 placeholder, this will generate
          // a duplicate key.  We do not account for that as the calling code
          // is already broken if that happens.
          $new_keys[$key . '_' . $i] = $value;
        }

        // Update the query with the new placeholders.
        // preg_replace is necessary to ensure the replacement does not affect
        // placeholders that start with the same exact text. For example, if the
        // query contains the placeholders :foo and :foobar, and :foo has an
        // array of values, using str_replace would affect both placeholders,
        // but using the following preg_replace would only affect :foo because
        // it is followed by a non-word character.
        $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);

        // Update the args array with the new placeholders.
        unset($args[$key]);
        $args += $new_keys;

        $modified = TRUE;
      }

      return $modified;
    }
這個函式預期得到的 $args 是一個不具有 key 值的簡單陣列,如以下範例:
db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('user1','user2')));
經由處理可得到這段 SQL 指令,並將 :name_0 代入 user1,:name_1 代入 user2:
SELECT * from users where name IN (:name_0, :name_1)
問題來了,若攻擊者帶入具有 key 值的 $args 且 key 值並非正整數,例如:
db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('test -- ' => 'user1','test' => 'user2')));
經由處理則將出現以下的 SQL 指令:
SELECT * FROM users WHERE name = :name_test -- , :name_test AND status = 1
看到問題了嗎?!此時 :name_test 會代入 user2,由於 Drupal 使用支援多重查詢的 PDO ,因此攻擊者可替換 “user2" 的資料,透過執行任意的 SQL 指令,新增、修改、下載資料庫或是清空,達成攻擊的目的。甚至,透過 Drupal 能夠執行資料庫中的 PHP 特色功能,執行任何攻擊程式。
 
因此修正的內容不難,透過限制取值的函式,即可避免植入有問題的 SQL 指令
$new_keys = array();
-    foreach ($data as $i => $value) {
+    foreach (array_values($data) as $i => $value) {
 
想知道需要花多少功夫就能達成攻擊?已經有 Drupaller 實作出來,在 30 分鐘之內就把整個網站的使用者密碼替換掉,其中還包括研究的過程。
 
此外,如果升級過程中有任何問題,或是對於這個漏洞有任何問題,都可以到 https://www.drupal.org/node/2357241 這裡去討論,或是查看其他人的問題是否與你相同。
 
以上說明大部分是由 SektionEins 所發佈的說明翻譯而來,如果說明或是我的理解有誤,歡迎指正!
 
Thanks!
Chris Wu
 
參考資料: