这个漏洞本是2014年时候被人发现的,本着学习的目的,我来做个详细的分析。漏洞虽然很早了,新版的Drupal甚至已经改变了框架的组织方式。但是丝毫不影响对于漏洞的分析。这是一个经典的使用PDO,但是处理不当,导致SQL语句拼接从而导致注入的问题。从这个问题,以及以往我见过的很多的漏洞来看,我不得不说,代码底层做的再安全,过滤的再完全,如果程序员的一个不小心,也将会导致重大安全问题的出现。多少的编码绕过,逻辑漏洞正是不小心带来的问题。

  0x00 注入的定位

  首先我根据网络上已经出现过的EXP,然后进行追踪。无奈,这个框架实在太大,我在跟进的过程中,遇到了诸多的问题,甚至路由模式都没有搞的很明白。然后根据已有的漏洞细节,我迅速定位到了漏洞的发生点。

在文件 \modules\user\user.module 中 有 user_login_authenticate_validate() 函数,代码如下:

function user_login_authenticate_validate($form, &$form_state) {
$password = trim($form_state['values']['pass']);
if (!empty($form_state['values']['name']) && !empty($password)) {
// Do not allow any login from the current user's IP if the limit has been
// reached. Default is 50 failed attempts allowed in one hour. This is
// independent of the per-user limit to catch attempts from one IP to log
// in to many different user accounts. We have a reasonably high limit
// since there may be only one apparent IP for all users at an institution.
if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) {
$form_state['flood_control_triggered'] = 'ip';
return;
}
$account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject(); //省略无关代码...

很明显,这里的SQL查询就是漏洞触发现场了,我们跟进db_query这个函数,代码如下:

function db_query($query, array $args = array(), array $options = array()) {
if (empty($options['target'])) {
$options['target'] = 'default';
} return Database::getConnection($options['target'])->query($query, $args, $options);
}

继续跟进query函数:

  public function query($query, array $args = array(), $options = array()) {

    // Use default values if not already set.
$options += $this->defaultOptions(); try {
// We allow either a pre-bound statement object or a literal string.
// In either case, we want to end up with an executed statement object,
// which we pass to PDOStatement::execute.
if ($query instanceof DatabaseStatementInterface) {
$stmt = $query;
$stmt->execute(NULL, $options);
}
else {
$this->expandArguments($query, $args);
$stmt = $this->prepareQuery($query);
$stmt->execute($args, $options);
}
//省略无关代码...

我们知道,如果在PHP连接MySQL数据库中,如果我们使用PDO进行预编译的话,我们的语句是无法改变原有的查询结构的,也就是说,注入的语句,无法进行查询,只能是当做字符串。从而从数据库查询层对注入做了彻底防御。那么这里是怎么产生问题的呢?

0x01 错误的处理导致的安全问题

但是这里有个问题,就是当参数是数组的时候,就会用到expandArguments这个方法,然后这个方法由于处理不当会导致安全问题。

函数代码如下:

  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;
}

我们再来回顾一下之前的查询语句,

db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))

这个数组我们是可控的,首先在array_filter之后,使用foreach进行遍历,然后二轮遍历中创建了一个新的数组。接着把$query变量中的键,进行了替换,替换掉以后的内容是之前新数组键用 ', '进行合并成的一个新的字符串。这样我们通过键来进行SQL注入就行的通了。注入语句将会通过拼接进入。

0x03 测试

可以看得很清楚,name数组中的两个键都被拼接进了SQL查询。

0x04 反思

这里是挺有意思,也很常见的一个问题。我在开头的引言中也说了。本来是做好了处理的,但是却使用了拼接,导致可控的外部数据进入了SQL查询。类似这样的问题还很常见,当然了,这也为自己挖洞提供了思路,在挖洞越来越困难的当下,挖洞思路的变化显得十分重要了。

  

Drupal V7.3.1 框架处理不当导致SQL注入的更多相关文章

  1. 管中窥豹——框架下的SQL注入 Java篇

    管中窥豹--框架下的SQL注入 Java篇 背景 SQL注入漏洞应该算是很有年代感的漏洞了,但是现在依然活跃在各大漏洞榜单中,究其原因还是数据和代码的问题. SQL 语句在DBMS系统中作为表达式被解 ...

  2. 最新版SEMCMS_PHP_3.5 过滤不严导致sql注入

    一.漏洞分析 在分析过程中看到网上已经有人发现semcms V2.4存在过滤不严导致sql注入的漏洞,不知道咋还没改,而且最新版过滤的关键字更少了. 首先查看首页文件index.php的代码 < ...

  3. 浅析PHP框架Laravel最新SQL注入漏洞

    PHP知名开发框架Laravel,之前在官方博客通报了一个高危SQL注入漏洞,这里简单分析下. 首先,这个漏洞属于网站coding写法不规范,官方给了提示: 但官方还是做了修补,升级最新版本V5.8. ...

  4. dedecms SESSION变量覆盖导致SQL注入漏洞修补方案

    dedecms的/plus/advancedsearch.php中,直接从$_SESSION[$sqlhash]获取值作为$query带入SQL查询,这个漏洞的利用前提是session.auto_st ...

  5. 代码审计-Thinkphp3框架EXP表达式SQL注入

    最近看java框架源码也是看的有点头疼,好多还要复习熟悉 还有好多事没做...慢慢熬. 网上好像还没有特别详细的分析 我来误人子弟吧. 0x01 tp3 中的exp表达式 查询表达式的使用格式: $m ...

  6. yii框架各种防止sql注入,xss攻击,csrf攻击

    PHP中常用到的方法有: /*  防sql注入,xss攻击  (1)*/    function actionClean($str)    {        $str=trim($str);      ...

  7. Java SQL注入学习笔记

    1 简介 文章主要内容包括: Java 持久层技术/框架简单介绍 不同场景/框架下易导致 SQL 注入的写法 如何避免和修复 SQL 注入 2 JDBC 介绍 JDBC: 全称 Java Databa ...

  8. Python预编译语句防止SQL注入

    这个月太忙,最近不太太平,我的愿望是世界和平! ================================== 今天也在找python的预编译,早上写的sql是拼接来构成的.于是找了2篇文章,还 ...

  9. SQL注入不简单?那是你没有懂它的原理~

    我们真的了解SQL注入吗? 不管用什么语言编写的Web应用,它们都用一个共同点,具有交互性并且多数是数据库驱动.在网络中,数据库驱动的Web应用随处可见,由此而存在的SQL注入是影响企业运营且最具破坏 ...

随机推荐

  1. delphi FMX 数字下拉滑动

    滑动输入数字 NumberBox控件 HorzIncrement:划动自动增加输入值的步长 combobox控件 http://docwiki.embarcadero.com/RADStudio/Be ...

  2. 关于ios8模拟器不能输入中文问题以及软键盘不弹出问题

    在Xcode菜单栏中   Product->scheme->Edit Scheme->Options->Application Region改为中国,就可以输入中文了, 如果软 ...

  3. 【转】PowerShell入门(一):PowerShell能干什么?

    转至:http://www.cnblogs.com/ceachy/archive/2013/01/30/WhatCanPowerShellDo.html PowerShell能干什么呢?就像序言中提到 ...

  4. 团队项目NABCD模型的需求分析

    团队项目NABCD模型的需求分析 NABCD模型的介绍 Need(需求)-现在市场上未被满足但又急需满足的客户需求是什么?Approach(方法)-要满足这种需求,我能够提出什么独特的方法吗?Bene ...

  5. MySQL结果集处理

    问题: 1. MySQL对查询的结果集如果返回,一次性还是每条?2. 客户端如何接收结果集? 1. 对于有返回结果集的查询,server端和client端交互的数据包由以下组成: p1:meta da ...

  6. java 线程操作

    停止线程 创建“停止标记”,thread.interrupt() 准确的说interrupt()方法只是“告知线程该停止了”,而线程检查到该“告知”后,再通过其他的办法停止线程. 线程调用了inter ...

  7. Android Developers:传感器概述

    大 多数Android设备有内置的传感器,来测量运动,方向和各种环境条件.这些传感器能提供高精度和准确度的原始数据,如果你想监控设备三维运动或者位 置,或者你想监控设备周围的环境变化,是非常有用的.例 ...

  8. 一个Java系统测试

    实验感受: 本次实验最大的感受,就是不要改代码,自己写,代码改起来真的没完没了,不知道会出现什么问题.还有就是一定要清楚自己要怎么去写,流程很重要,一个个功能去实现. 主界面 数据库 主页面代码 &l ...

  9. Pandas 删除指定列中为NaN的行

    定位要删除的行 需求:删除指定列中NaN所在行. 如下图,’open‘ 列中有一行为NaN,定位到它,然后删除. 定位: df[np.isnan(df['open'])].index # 这样即可定位 ...

  10. 浅谈FFC

    FFC(Flexible Formatting Context) CSS3引入了一种新的布局模型——flex布局(之前有文章介绍过).flex是flexible box的缩写,一般称之为弹性盒模型.和 ...