- A+
根据网上发布关于thinkphp 5.x远程代码执行漏洞预警,分析漏洞发生点,对比官方git更新版本,对照发现更新为request类,如下图所示:
观察发生更改的点为pathinfo()、method()、param()、post()、request()和cache()方法上,由此预测漏洞发生可能与这几个方法有关,进入5.0.10版本request.php中,如下图所示:
最后返回一个input方法,跟踪input方法,如下图所示:安全脉搏:https://www.secpulse.com/archives/95012.html
观察描述可得input方法可获得变量,支持过滤和默认值,查看如何获得默认值,如下图所示:
当输入数据为数组时采用array_walk_recursive函数,filterValue为返回函数,$filter为传参,filterValue函数为下图所示:
当$filter为可用函数时,就会进入call_user_func函数中,也就是当我们可控$value时,即可执行任意代码。目前清楚调用过程,考虑如何使用rop链,已知是post函数导致,查看何处调用或使用了此函数,观察request文件调用过程。初始化魔术方法__construct,如下图所示:
通过判断是否存在类中,将数组$options一次赋值给$item,此时如果可以获取到$options,即可完成rop链,观察可利用传值的方法,如下图所示:
发现发送的数据为config文件中get方法返回的数据,查询官方手册可得安全脉搏:https://www.secpulse.com/archives/95012.html
在此版本中var_method=>_method,所以此时rop链已经形成,通过post方式发送x=ipconfig&_method=__construct&filter[]=system,即可产生漏洞,如下图所示:
接着分析5.0.23版本,发现request文件中也使用了method函数,如下图所示:安全脉搏:https://www.secpulse.com/archives/95012.html
但是由于此版本在APP::run()初始化时对filter进行默认设置,无法进行直接覆盖,所以观察method函数,如下图所示:
查看server函数,如下图所示:
返回一个input方法和之前input方法一样,采用call_user_func函数执行任意代码。利用方式与5.0.10相同,post数据为:
_method=__construct&filter[]=system&server[REQUEST_METHOD]=dir
当开启debug时,会将命令执行回显在页面上,如下图所示:安全脉搏:https://www.secpulse.com/archives/95012.html
观察两次exp,可以看出第一次命令执行前可使用任意字符=要执行的命令,第二次命令执行前必须为server[REQUEST_METHOD]=要执行的命令,观察两次版本关于method方法的不同,如下图所示:
右边为5.0.10,左边为5.0.23,可得知5.0.10在非命令行下会调用server['REQUEST_METHOD'],此数组只有在create方法中赋值,所以直接到$_SERVER['REQUEST_METHOD']赋值为post,5.0.23在server函数中当$name为数组时,会将数组中的字符串赋值为$_SERVER['REQUEST_METHOD'],结果为post,达到与5.0.10同样的效果。
当然此exp的使用必须为debug开启时才有回显,原因为当开启debug时,会自动记录路由和请求信息,自动调用param方法,如下图所示:
根据官方修改中还有pathinfo()现在暂无在rop链中使用,观察此函数,如下图所示:
了解过5.1版本的远程命令执行的大佬,肯定对这个函数不陌生,这个函数是分析url后缀,关于路由协议的,由此猜测可能在路由协议中产生了远程命令执行漏洞,追踪pathino函数的调用情况,从入口函数观察到,如下图所示:
通过pathinfo的参数s导入相关模块,进入路由检测routeCheck方法,如下图所示:
接着进入check方法,如下图所示:安全脉搏:https://www.secpulse.com/archives/95012.html
接下来进入路由规则检测,为了大家理解方便,其中$request传入参数的值为下图所示:
进入到parseRule中,调用关键代码,如下图所示:
最终定位到\thinkphp5.0.23\vendor\topthink\think-captcha\src\helper.php文件中,代码为\think\Route::get('captcha/[:id]', "\\think\\captcha\\CaptchaController@index"),注册GET路由,通过self::rule、self::setRule到
self::$rules[$type][$rule]=['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern],由于在base.php中已经声明第三方类库vendor,会自动加载helper文件,当s=captcha时,rop链反射到helper文件下,形成rce。
首先通过前面的所述通过路由检测,到达app.php中,具体执行链如下图所示:
进入exec方法中,如下图所示:
进入到之前的param函数中,因为5.0.23中method方法要为get类型,所以在post数据时要加上method=get。
安全脉搏:https://www.secpulse.com/archives/95012.html
参考链接:
https://github.com/top-think/framework/commit/4a4b5e64fa4c46f851b4004005bff5f3196de003