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 注入

  1. prepare($SQL) 编译 SQL 语句
  2. bindValue( p a r a m , param, param,value) 将 value 绑定在 param 的位置上
  3. 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交互进行的

非模拟预处理的情况下,参数化绑定过程分两步:

  1. 第一步是 prepare 阶段,发送带有占位符的 sql 语句到 mysql 服务器(parsing->resolution)
  2. 第二步是多次发送占位符参数给 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分布式任务调度框架-源码分析-任务调度执行流程及实现原理

spark-sql执行流程分析

spring mvc控制框架的流程及原理1: 总概及源码分析

spring mvc控制框架的流程及原理1: 总概及源码分析

框架之认证接口的源码分析及自定义接口的使用

MyBatis源码分析-SQL语句执行的完整流程