搭建调试环境可以参考这篇博客,不过博客里没写在验证的时候,phpstorm会提醒你在php.ini里加上一行xdebug.mode=debug,不用phpstudy也可以,我是用apache起的web环境
普通模式(PATH_INFO 模式)
我们先访问/index路由看看
接下来开始调试
根据堆栈信息,我们从thinkphp框架的app.php开始调试。一般的cms项目,控制器是自己写的,但路由规则是由框架给出的,也就是我们访问怎样的路由可以触发这个控制器是框架决定的。
这里就根据config来处理我们的dispatch(调度)了。
注释中写了这里是根据模块/控制器/操作来分割的
而我们的三个值,只有第一个也就是模块的值为index,后面两个为空
先获取模块,配置的默认模块为index,如果没有模块就用默认模块,这里我们有,虽然也是index
如果不在拒绝访问的模块里(common)就可以访问
模块结束,为D:\Download\AppGallery\httpd-2.4.61-240703-win64-VS17\Apache24\htdocs\public/../application/index\
因为我们的控制器为空,所以用默认的index控制器,操作名同理,为index
得到类名为app\index\controller\Index
实例化这个类
最后invoke调用这个类的实例的这个方法
最后调用的时候还要加入参数
这里我自己写了一个控制器
但是其实我写的有问题,类的第一个字母要为大写才行
所以它找不到我们的类
我们改成Test就可以成功调用了
总结一下,第一个为模块名,也就是application下文件夹的名字,第二个为类名,第三个为方法名
不过这些都是无参方法的调用,现在我们来学有有参方法的调用
可以先看这篇文章
通过提示可以看到获取参数的方法有两种,一种是根据路由来,一种是根据请求给的参数来
/index/test/test/name/chhhchhoh/age/20
驼峰命名法
thinkphp默认会把控制器全转为小写,不过为了支持各种风格的命名,会把Xin_Xinhui这种带有_的再做一次转化。把_后面的字母转为大写,再删除_,最后把首字母转为大写,得到的控制器名就是XinXinhui。方法名好像没有转化为小写,直接访问就可以了。
兼容模式(s参数模式)
/index/test/test?name=chhhchhoh&age=20
?s=/index/test/test/name/chhhchhoh/age/20
路由也可以放入s参数,也可以解析
可以看到,如果有兼容模式的参数即s(可以自己配置),则路由信息为s的值。
得到路由信息后面就跟默认模式一样了。
混合模式(自定义路由+PATH_IFNO)
如果有自己定义的路由就优先根据这个规则,不然就采用默认模式。
下面是官方给的自定义路由的例子,详细的可以看这篇文章
这里设置了id要get传参且为数字,name要post传参且为字符
在Route.php#checkRule检测到我们自己定义的路由规则然后调用parseRule进行解析
最后解析为路由信息,后面又是默认模式了。
/public/hello/123
强制模式
相当于只允许自定义路由,不允许用默认模式。
thinkphp5 rce分析
直接给payload
/public/?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
这里用的是兼容模式,模块为index,类为think\app,方法为invokefunction
模块还是老样子,application那个文件夹
这里实例化的是think\app这个类
也就是这个
最后相当于调用了call_user_function_array('system',arrary('whoami'));
很容易想到/public/?s=index/think\app/invokefunction&function=system&vars=whoami可不可以呢,但这里的$vars一定要是数组,字符串会报错,但system又是接收一个字符串,所以没办法用