ThinkPHP 3.2.3 find/select/delete注入
前言
select()、find()、delete()三个函数可以传入数组数据导致sql注入
环境
\Application\Home\Controller\IndexController.class.php
配置好数据库
分析
先给出payload
/?id[where]=1 and updatexml(1,concat(0x7e,version(),0x7e),1) |
跟进 I()
函数
获取了传进去的内容
M函数就不看了,进入find函数
因为这里$options
是一个数组所以这里跳过第一个if判断
这个getPk函数是查找mysql主键的函数
紧接着一个if判断:
因为这里的$pk
不是一个数组,所以直接跳出
进入一个_parseOptions()函数:
跟进:
使用array_merge函数将 $options
与options合并,合并结果还是 $option
因为 $this->option 是一个空数组
获取到了表名等
这里到了重点:
这里判断 $options[where]
不是一个数组,所以没有进入if判断直接跳出
进入 _options_filter
函数,是空的
从此跳出了 _parseOptions() 函数返回了 find
函数
紧接着进入select
函数:
跟进:
重点跟进 buildSelectSql
函数:
跟进parseSql函数:
重点看这个parseWhere:
这里判断为字符串直接返回:
parseSql函数返回sql语句:
进行查询:
更换payload为:
/?id=1 and updatexml(1,concat(0x7e,version(),0x7e),1) |
跟进到_parseOptions这里时出现了不同:
_parseType
函数对where进行处理
跟进函数:
这里经过intval处理后,消除了注入语句
总结
关键在于find函数第一步的处理这里
_parseOptions
:
如果传进去的是 $id[where]
那么 $options['where']
为字符串不进行操作,如果传进去是 $id
那么 $options['where']
为数组,$options['where'][id]
才是字符串,所以进行了处理
public function find($options=array()) { //$options = String |
此外不仅仅 parseWhere()
可以触发,与之类似拼接的 parseGroup()
、parseHaving()
、parseOrder()
, parseTable()
也能触发,可以用id[where]
和 id[alias]
等参数触发
修复:
在_parseOptions函数处理时不传入$options
,这样经过_parseOptions处理过后,$option始终为空.