师傅们情人节快乐~来一起分析个洞八
0x01漏洞描述
顶想信息科技 ThinkPHP是中国顶想信息科技公司的一套基于PHP的、开源的、轻量级Web应用程序开发框架。
ThinkPHP 5.0.x <=5.1.22 存在SQL注入漏洞,该漏洞源于通过Builder.php中的parseOrder函数。
0x02影响版本
ThinkPHP 5.0.x <=5.1.22
0x03环境搭建
Test on ThinkPHP-5.0.5,其完整版的源码:http://www.thinkphp.cn/donate/download/id/870.html
PHPstorm + Xdebug配置
具体配置过程不做详细说明,最后效果大概如下:
phpinfo页面中
数据库配置
在框架源码中的database.php
数据库配置文件中添加相关的数据库信息,这里以连接mysql默认已有的数据库为例
tp5源码配置
由于是tp5框架问题,所以可以在Index.php
访问页面中修改成以下代码
0x04漏洞分析
在Index.php
文件中断点逐步跟进即可~
访问页面在url传入以下参数及值
?test[user^updatexml(1,concat(0x7,user(),0x7e),1)%23]=1
先看到input()
中对接收http请求服务在Request.php
进行了简单的判断和处理,并且从中可得到我们所构造的恶意键值对
接着返回到Index.php
文件的第二个断点,helper.php
中的db()
函数对数据库进行connect连接操作,接着到Query.php
文件的where()
函数,这边也是没有任何的问题
紧接着来到order()
函数中,可以看到我们的$field
数据内容是直接存储到了$this->options['order']
当中
接着调用最后的find()
函数以在数据库做sql语句的执行,先是利用parseExpress()
函数提取sql语句中的关键字等操作
接着Query.php
中的$sql = $this->builder->select($options);
会调用Builder.php
中的Select()
函数生成Sql语句,关键在于该方法中对$options
中的order
键值对做了parseOrder()
函数的过滤
public function select($options = [])
{
$sql = str_replace(
['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],
[
$this->parseTable($options['table'], $options),
$this->parseDistinct($options['distinct']),
$this->parseField($options['field'], $options),
$this->parseJoin($options['join'], $options),
$this->parseWhere($options['where'], $options),
$this->parseGroup($options['group']),
$this->parseHaving($options['having']),
$this->parseOrder($options['order'], $options),
$this->parseLimit($options['limit']),
$this->parseUnion($options['union']),
$this->parseLock($options['lock']),
$this->parseComment($options['comment']),
$this->parseForce($options['force']),
], $this->selectSql);
return $sql;
}
在parseOrder()
函数中,将$key
和$options
参数传入parseKey()
函数过滤$key
值
在parseKey()
函数中未对key中做任何消除敏感字符的过滤、检测,即照常返回原来的key值
所以在parseOrder()
函数中将直接返回以下内容
将得到最终所要执行的sql语句
在事件回调代码块中对以上得到的sql语句,来到Connection.php
中的query()
函数进行sql语句的查询
$result = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
最后在此处触发了错误的sql注入
在此处将返回我们成功注入sql的报错信息
调用链如下:
helper#db --> 连接数据库
Query#where --> 匹配where关键字
Query#order --> 匹配order关键字
Query#find,Builer#select --> 生成sql查询语句
Builer#parseOrder --> 过滤$options中的order键值对
Mysql#parseKey --> 过滤order中的key值
Query#query,Connection#Query --> 执行sql语句
PDOException#getLastsql --> 返回报错信息
0x05总结一下
(仅个人理解)就是在键值对中的构造恶意sql语句到key即键中,接着在生成sql查询语句过程中未对order(包括其他关键字)中的key做敏感字符串的过滤,导致将key值内容拼接进sql语句中,达到sql注入的目的
- 本文作者: w1nk1
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/1291
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!