ThinkPHP v5.0.22 RCE分析

前言

距离上次php审计是在ThinkPHP v5.0.24反序列化漏洞分析,这篇笔记本来在很久之前应该就要写的,但是一直对tp路由还是不够熟悉,个人觉得难度要比反序列化高一些,拖了这么久今天做个了结。

环境搭建

使用环境:Apache + PHP 7.0.9

下载具有漏洞环境的ThinkPHP 5.0.22

https://github.com/top-think/think/releases/tag/v5.0.22

下载后通过composer安装依赖项:

composer install

或者可以通过composer直接拉取源码:

composer create-project topthink/think tp 5.0.22

查看thinkphp/library/think/App.php文件555行,注释如下3行代码,这是官方对5.0.22版本漏洞的修复

poc:/think-5.0.22/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

漏洞分析

分析工具:PhpStorm + Xdebug

通过poc和动态调试的方式进行跟踪分析,入口文件public/index.php

加载thinkphp/start.php

然后进入执行App::run,进到thinkphp/library/think/App.phprun方法中对路由处理的核心代码如下:

打上断点进行debug:

$dispatch为空,进行路由检测

进到routeCheck方法:

$path开头获取到路由,$depr为默认路由分隔符/

接下来的这一块主要是通过配置文件查看路由的开启情况以及读取路由缓存和导入路由配置信息这些,继续往下看

这一块依旧是路由检测,可以进到Route::check看一看,通过注释可以快速理解代码作用,内部经过一系列检测后,返回self::checkRoute方法返回值false

然后就是最后一块代码,通过Route::parseUrl进行路由的解析

先通过str_replace替换路由为index|think\app|invokefunction,然后进入parseUrlPath再将|替换成/然后提取模块/控制器/操作

返回parseUrl方法继续往下看,然后通过解析控制器、解析操作,通过模块/控制器/操作封装到$route中然后返回

然后再回到App::run中继续往下看,$dispatch接收返回值如下:

之后再139行,进入到exec方法

这里$dispatch['type']module,然后进入了module方法

再553行获取控制器名,官方补丁通过正则对$controller进行了过滤

然后继续获取操作名,然后从590行is_callable([$instance, $action])验证控制器中是否存在该操作,如果存在通过反射执行该操作。

在611行执行通过invokeMethod方法进入invokeFunction方法,这里传入的$vars为空

进入到invokeMethod方法,339行获取参数

然后在invokeMethod最后一行将参数传入invokeFunction方法

然后进到invokeFunction方法,又通过反射执行call_user_func_array函数,传入参数args

最后成功执行call_user_func_array("system", array("whoami"))

总结

这篇rce分析真的挺折磨我的,虽然说大致上明白了这个漏洞的成因,但是我觉得可能由于自己对框架的不熟悉,在debug中有很多的细节其实不太能看太懂,代码较多只能靠注释去尝试理解。这个漏洞对于有开发能力的朋友应该很容易理解,可能真的需要花一定的时间去了解一下Web框架的设计模式,包括其中涉及的反射提前学习过也会加快理解。

还差的太多,需要继续加油😥

posted @ 2023-01-23 20:52  seizer-zyx  阅读(630)  评论(0编辑  收藏  举报