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
參考資料:
WOW,這個要與時間競賽
WOW,這個要與時間競賽
自定一個 POST REQUEST 就可以攻擊
強烈建議大家不要測試升級是否有問題,直接能多快就多快地更新,其實也只有一行,可以只手動更新那一行修復。