关于tp5的一种注入场景

前言

在控制器中如果where方法的参数完全可控

Db::name('users')->where($_POST['a'])->select();

则存在多种形式的注入,但是这种场景基本不会出现

在这种模式下衍生的最舒服的注入形式莫过于

Db::name('users')->where('id='.$_POST['a'])->select();

这是很常规的一种拼接注入

今天遇到一种实际的场景,不存在于控制器中,存在于model中

image-20210910174643597

实际代码

1
2
3
$ck = json_decode(cookie('merchant'), true);
$user_id = $ck['id'];
$this->user = UserModel::get($user_id);

分析

可以想到的是这里向get方法中传进的参数是完全可控的

跟进model的get方法

image-20210910174953739

进入了parseQuery方法处理我们传入的data

跟进此方法后可以看到,当我们传入的参数是数组的时候,会进入where方法

image-20210910175108056

跟进where方法

image-20210910175150415

跟进parseWhereExp方法

我们传入的数组,会进入下面的分支中

image-20210910175248763

处理完毕,置空data变量,并调用find方法

image-20210910175343626

跟进find方法,这里有一处很重要的方法就是getpk方法

image-20210910175745093

进入gettableinfo方法

image-20210910175820116

这里会有一个获取数据哭的所有字段,并判断器绑定类型,保存在bind参数中

这里获取到的字段均为idusername等形式

image-20210910175940523

接下来会进入build中

image-20210910180036367

直接定位到parseWhereItem方法中

映入眼帘的是第二个关键点parseKey方法

image-20210910180235046

跟进后可以发现,这里的处理方式不仅仅处理了id或者username的形式

同样处理了user.id或者user.username的形式

image-20210910180344592

第三个关键点

image-20210910180422984

这是第一次参数绑定的条件

之前的notlike注入就是没有进入这个条件

因为它不满足is_scalar($value)条件

正常经过下exists是必进入这个条件的,但是现在可以去看第二个条件

array_key_exists($field, $binds)

此时bind参数的类型

1
2
3
4
$bind = array(
"id" => 1,
"username" => 2
);

我们传入user.id很明显不在这个数组中,直接跳过

完成拼接注入

image-20210910180732577

复现

以上面的漏洞案例

测试结果如下

image-20210910180813457

poc

1
merchant={"id":{"user.id":["exists","select 1) and (updatexml(1,concat(0x7e,user()),1))-- 1"]}}