ce安全网绿色资源分享

教程资讯|常用软件|安卓下载|下载排行|最近更新

软件
软件
文章
当前位置:首页网络安全安全文章 → ThinkPHP框架SQL注入技术分析

ThinkPHP框架SQL注入技术分析

时间:2018-05-23 07:00:02人气:作者:本站作者我要评论

简要描述

ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生的12年间一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。目前ThinkPHP框架是国内使用量最大的框架之一,国内用户量众多。

近日,360企业安全集团代码卫士团队安全研究人员发现该框架V5.1.7-V5.1.8 版本在底层数据处理驱动解析数据的时候存在缺陷,一定场景下,攻击者可以通过构造恶意数据包利用SQL注入的方式获取用户数据库内容。360企业安全集团代码卫士团队已第一时间和ThinkPHP团队进行沟通修复,建议相关用户及时更新官方发布的新版本。

漏洞分析

注:该漏洞ThinkPHP官方团队在报送当天(2018-04-06)紧急进行了修复处理

以下漏洞分析基于ThinkPHP V5.1.8

这里我们主要跟进分析执行update操作的过程。为了方便理解,先直接放出函数的调用栈。

  1. Mysql.php:200, thinkdbbuilderMysql->parseArrayData()
  2. Builder.php:147, thinkdbBuilder->parseData()
  3. Builder.php:1139, thinkdbBuilder->update()
  4. Connection.php:1149, thinkdbConnection->update()
  5. Query.php:2571, thinkdbQuery->update()
  6. Index.php:18, appindexcontrollerIndex->testsql()
  7. Container.php:285, ReflectionMethod->invokeArgs()
  8. Container.php:285, thinkContainer->invokeReflectMethod()
  9. Module.php:139, thinkroutedispatchModule->run()
  10. Url.php:31, thinkroutedispatchUrl->run()
  11. App.php:378, thinkApp->think{closure}()
  12. Middleware.php:119, call_user_func_array:{C:wamp64wwwthink518thinkphplibrarythinkMiddleware.php:119}()
  13. Middleware.php:119, thinkMiddleware->think{closure}()
  14. Middleware.php:74, call_user_func:{C:wamp64wwwthink518thinkphplibrarythinkMiddleware.php:74}()
  15. Middleware.php:74, thinkMiddleware->dispatch()
  16. App.php:399, thinkApp->run()
  17. index.php:21, {main}()

缺陷关键点为thinkphp解析用户传递过来的Data可控,且可以绕过安全检查。

根据文件 Connection.php:1149,thinkdbConnection->update()第1102行update函数分析,这个函数的主要功能是用于执行update SQL语句。

  1. $options = $query->getOptions(); if (isset($options['cache']) && is_string($options['cache']['key'])) {
  2.        $key = $options['cache']['key'];
  3.    }
  4.    $pk   = $query->getPk($options);
  5.    $data = $options['data']; if (empty($options['where'])) { // 如果存在主键数据 则自动作为更新条件 if (is_string($pk) && isset($data[$pk])) {
  6.            $where[$pk] = [$pk, '=', $data[$pk]]; if (!isset($key)) {
  7.                $key = $this->getCacheKey($query, $data[$pk]);
  8.            } unset($data[$pk]);
  9.        } elseif (is_array($pk)) { // 增加复合主键支持 foreach ($pk as $field) { if (isset($data[$field])) {
  10.                    $where[$field] = [$field, '=', $data[$field]];
  11.                } else { // 如果缺少复合主键数据则不执行 throw new Exception('miss complex primary data');
  12.                } unset($data[$field]);
  13.            }
  14.        } if (!isset($where)) { // 如果没有任何更新条件则不执行 throw new Exception('miss update condition');
  15.        } else {
  16.            $options['where']['AND'] = $where;
  17.            $query->setOption('where', ['AND' => $where]);
  18.        }
  19.    } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
  20.        $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
  21.    } // 更新数据 $query->setOption('data', $data); // 生成UPDATE SQL语句 $sql  = $this->builder->update($query);
  22.    $bind = $query->getBind(); if (!empty($options['fetch_sql'])) { // 获取实际执行的SQL语句 return $this->getRealSql($sql, $bind);
  23.    } // 检测缓存 $cache = Container::get('cache'); if (isset($key) && $cache->get($key)) { // 删除缓存 $cache->rm($key);
  24.    } elseif (!empty($options['cache']['tag'])) {
  25.        $cache->clear($options['cache']['tag']);
  26.    } // 执行操作 $result = '' == $sql ? 0 : $this->execute($sql, $bind); if ($result) { if (is_string($pk) && isset($where[$pk])) {
  27.            $data[$pk] = $where[$pk];
  28.        } elseif (is_string($pk) && isset($key) && strpos($key, '|')) { list($a, $val) = explode('|', $key);
  29.            $data[$pk]     = $val;
  30.        }
  31.        $query->setOption('data', $data);
  32.        $query->trigger('after_update');
  33.    } return $result;

第1146行, $query->setOption(‘data’,$data);这里将用户传递的 $dataset到 $query变量中,为下一步的生成 UPDATE SQL语句做准备,执行 $sql=$this->builder->update($query);语句,重点马上要来了,跟进 Builder.php:1139,thinkdbBuilder->update()函数

  1. $options = $query->getOptions();
  2.    $table = $this->parseTable($query, $options['table']);
  3.    $data  = $this->parseData($query, $options['data']); if (empty($data)) { return '';
  4.    } foreach ($data as $key => $val) {
  5.        $set[] = $key . ' = ' . $val;
  6.    } return str_replace(
  7.        ['%TABLE%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],
  8.        [ $this->parseTable($query, $options['table']),
  9.            implode(' , ', $set), $this->parseJoin($query, $options['join']), $this->parseWhere($query, $options['where']), $this->parseOrder($query, $options['order']), $this->parseLimit($query, $options['limit']), $this->parseLock($query, $options['lock']), $this->parseComment($query, $options['comment']),
  10.        ], $this->updateSql);

刚刚我们将用户可控的 $dataset到 $query[‘options’]中,这里我们先获取 $query[‘options’]内容到 $options中,然后对Data进行解析 $data=$this->parseData($query,$options[‘data’]);

  1. if (empty($data)) { return [];
  2.    }
  3.    $options = $query->getOptions(); // 获取绑定信息 if (empty($bind)) {
  4.        $bind = $this->connection->getFieldsBind($options['table']);
  5.    } if (empty($fields)) { if ('*' == $options['field']) {
  6.            $fields = array_keys($bind);
  7.        } else {
  8.            $fields = $options['field'];
  9.        }
  10.    }
  11.    $result = []; foreach ($data as $key => $val) {
  12.        $item = $this->parseKey($query, $key); if ($val instanceof Expression) {
  13.            $result[$item] = $val->getValue(); continue;
  14.        } elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $this->connection->getFieldsType($options['table'], $key))) {
  15.            $val = json_encode($val);
  16.        } elseif (is_object($val) && method_exists($val, '__toString')) { // 对象数据写入 $val = $val->__toString();
  17.        } if (false !== strpos($key, '->')) { list($key, $name) = explode('->', $key);
  18.            $item             = $this->parseKey($query, $key);
  19.            $result[$item]    = 'json_set(' . $item . ', '$.' . $name . '', ' . $this->parseDataBind($query, $key, $val, $bind, $suffix) . ')';
  20.        } elseif (false === strpos($key, '.') && !in_array($key, $fields, true)) { if ($options['strict']) { throw new Exception('fields not exists:[' . $key . ']');
  21.            }
  22.        } elseif (is_null($val)) {
  23.            $result[$item] = 'NULL';
  24.        } elseif (is_array($val) && !empty($val)) { switch ($val[0]) { case 'INC':
  25.                    $result[$item] = $item . ' + ' . floatval($val[1]); breakcase 'DEC':
  26.                    $result[$item] = $item . ' - ' . floatval($val[1]); breakdefault:
  27.                    $value = $this->parseArrayData($query, $val); if ($value) {
  28.                        $result[$item] = $value;
  29.                    }
  30.            }
  31.        } elseif (is_scalar($val)) { // 过滤非标量数据 $result[$item] = $this->parseDataBind($query, $key, $val, $bind, $suffix);
  32.        }
  33.    } return $result;

在第115行,通过 foreach($dataas$key=>$val)处理 $data,然后解析 $key保存到 $item变量中去,之后执行下面的判断逻辑,想要合理地进入各个判断分支,就要巧妙的构造 $key和 $value也就是 $data的值。紧接着我们进入漏洞触发点 $value=$this->parseArrayData($query,$val);,跟进函数 $value=$this->parseArrayData($query,$val);

  1. list($type, $value) = $data; switch (strtolower($type)) { case 'point':
  2.            $fun   = isset($data[2]) ? $data[2] : 'GeomFromText';
  3.            $point = isset($data[3]) ? $data[3] : 'POINT'; if (is_array($value)) {
  4.                $value = implode(' ', $value);
  5.            }
  6.            $result = $fun . '('' . $point . '(' . $value . ')')';//需要简单的构造一下sql语句 break; default:
  7.            $result = false;
  8.    } return $result;

这里 $type、 $value和 $data均为可控值,那么函数返回的 $result也就是可控的。回到上一个 Builder.php文件中,将返回的结果赋值到 $result[$item]=$value;中,之后的生成SQL语句和常见的流程没有任何差别不再展开具体分析。

验证截图

ThinkPHP框架SQL注入技术分析

相关文章

猜你喜欢

  • 深入解析浅谈《快3单双准确率方法》成功方案

    2022-09-28 /

  • 全网首发《快3单双大小必中方法技巧》思路汇总

    2022-09-28 /

  • 资深攻略《快3大小必中技巧》上岸方法

    2022-09-28 /

  • 【最准确的玩法】《回血上岸计划导师QQ》操作系列

    2022-09-28 /

  • 经验教程《导师一分快三计划》最新窍门

    2022-09-28 /

  • 高手教你《大小单双最安全的打法》三期必中

    2022-09-28 /

网友评论

验证码:

请自觉遵守互联网相关政策法规,评论内容只代表网友观点,与本站立场无关!

最新评论

已有人参与,点击查看更多精彩评论

本类推荐

关于CE安全网 | 联系方式 | 发展历程 | 版权声明 | 下载帮助(?) | 广告联系 | 网站地图 | 友情链接

Copyright 2019-2029 cesafe.com 【CE安全网】 版权所有 琼ICP备2021004244号-1| 琼ICP备2021004244号-1

声明: 本站为非赢利性网站 不接受任何赞助和广告 所有软件和文章来自互联网 如有异议 请与本站联系 技术支持:ce安全网