TP5 框架 SQL 执行流程分析及 5.0.9 SQL 注入漏洞分析
Posted OceanSec
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TP5 框架 SQL 执行流程分析及 5.0.9 SQL 注入漏洞分析相关的知识,希望对你有一定的参考价值。
文章目录
SQL查询流程
TP5手册:https://www.kancloud.cn/manual/thinkphp5/118044
在分析 tp5 漏洞之前,先来看一看 tp5 在查询时的流程,与 tp3 有什么异同,写一个控制器
<?php
namespace app\\index\\controller;
class Index
public function index()
$name = Input("name/d");
$data = db("test")->where("name",$name)->find();
dump($data);
tp5 输入输入使用 Input 函数,代替 tp3 中使用的 I 函数,Input 函数有一个功能可以使用变量修饰符对输入数据进行转换
ThinkPHP5.0版本默认的变量修饰符是/s
,如果需要传入字符串之外的变量可以使用下面的修饰符,包括:
修饰符 | 作用 |
---|---|
s | 强制转换为字符串类型 |
d | 强制转换为整型类型 |
b | 强制转换为布尔类型 |
a | 强制转换为数组类型 |
f | 强制转换为浮点类型 |
接下来看看 Sql 查询分析,tp5 使用了 pdo 预编译,基本流程如下,有效防止 SQL 注入
- prepare($SQL) 编译 SQL 语句
- bindValue( p a r a m , param, param,value) 将 value 绑定在 param 的位置上
- execute 执行
find 函数中有整个 pdo 查询流程
生成查询 SQL
获取参数绑定
执行查询
TP 5.0.9 SQL注入
5.0.9 及以下版本如果开启了 debug 都存在这个漏洞,危害较低,不能子查询,只能泄露一些信息,如 user()、database() 等
控制器
class Index
public function index()
$name = Input("name/a");
$data = db("test")->where("name","in",$name)->select();
dump($data);
payload
?name[0,updatexml(0,concat(0xa,database()),0),0]
database 同时还会泄露数据库配置信息
基础的调试流程
where() -> select -> parseWhere() -> buildWhere()
这里直接进入 buildWhere()
if 都不进入,到最后
进入 parseWhereItem()直接看重点
因为 $exp 是 in,满足条件进入 if,foreach 遍历拼接 $bindKey
$bindKey = $bindName . '_in_' . $k;
$bindKey = where_name_in_0,updatexml(0,concat(0xa,database()),0),0
最终 return wherestr
$whereStr = `name` IN (:where_name_in_0,updatexml(0,concat(0xa,database()),0),0)
完整的 sql 语句
:where_id_in_
的后面,直接拼接传入的 id 的键,并没有进行过滤,可以造成 SQL 注入
主要问题是 tp5 使用了 pdo,正常来说不会出现注入,但是这里缺可以报错注入,而且正常 pdo 执行流程为三步(上边介绍了),但是这里在 prepare 截断就执行了 SQL 查询
原因如下:
PDO::ATTR_EMULATE_PREPARES => false
这个选项涉及到 PDO 的“预处理”机制:
因为不是所有数据库驱动都支持 SQL 预编译,所以 PDO 存在“模拟预处理机制”。如果说开启了模拟预处理,那么 PDO 内部会模拟参数绑定的过程,SQL语句是在最后 execute() 的时候才发送给数据库执行
如果关闭即为 false 的话,PDO不会模拟预处理,参数化绑定的整个过程都是和mysql交互进行的
非模拟预处理的情况下,参数化绑定过程分两步:
- 第一步是 prepare 阶段,发送带有占位符的 sql 语句到 mysql 服务器(parsing->resolution)
- 第二步是多次发送占位符参数给 mysql 服务器进行执行(多次执行optimization->execution)
但是,如果你将user()改成一个子查询语句,那么结果又会爆出Invalid parameter number: parameter was not defined的错误。因为没有过多研究,说一下我猜测:预编译的确是mysql服务端进行的,但是预编译的过程是不接触数据的 ,也就是说不会从表中将真实数据取出来,所以使用子查询的情况下不会触发报错;虽然预编译的过程不接触数据,但类似user()这样的数据库函数的值还是将会编译进SQL语句,所以这里执行并爆了出来
修复
在 tp5 新版本中,改成对值得处理,而且拼接用得时$i
这个计数,最后拼接得预处理也只能是:where_id_in_1
,:where_id_in_1
这样的了
以上是关于TP5 框架 SQL 执行流程分析及 5.0.9 SQL 注入漏洞分析的主要内容,如果未能解决你的问题,请参考以下文章
XXL-JOB分布式任务调度框架-源码分析-任务调度执行流程及实现原理
spring mvc控制框架的流程及原理1: 总概及源码分析