关于tp5的一种注入场景
前言
在控制器中如果where方法的参数完全可控
Db::name('users')->where($_POST['a'])->select();
则存在多种形式的注入,但是这种场景基本不会出现
在这种模式下衍生的最舒服的注入形式莫过于
Db::name('users')->where('id='.$_POST['a'])->select();
这是很常规的一种拼接注入
今天遇到一种实际的场景,不存在于控制器中,存在于model中

实际代码
1 | $ck = json_decode(cookie('merchant'), true); |
分析
可以想到的是这里向get方法中传进的参数是完全可控的
跟进model的get方法

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

跟进where方法

跟进parseWhereExp方法
我们传入的数组,会进入下面的分支中

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

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

进入gettableinfo方法

这里会有一个获取数据哭的所有字段,并判断器绑定类型,保存在bind参数中
这里获取到的字段均为id,username等形式

接下来会进入build中

直接定位到parseWhereItem方法中
映入眼帘的是第二个关键点parseKey方法

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

第三个关键点

这是第一次参数绑定的条件
之前的notlike注入就是没有进入这个条件
因为它不满足is_scalar($value)条件
正常经过下exists是必进入这个条件的,但是现在可以去看第二个条件
array_key_exists($field, $binds)
此时bind参数的类型
1 | $bind = array( |
我们传入user.id很明显不在这个数组中,直接跳过
完成拼接注入

复现
以上面的漏洞案例
测试结果如下

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












