OpenSNS远程代码执行漏洞分析

前言

某天在微信上看到了 补天平台的微信公众号文章推送, 是一篇PHP的代码审计文章。简单看了下觉得利用过程挺有意思的, 与普通的追溯敏感函数审计相对有意思些, 于是便有了文本。

ThinkPHP内置函数

OpenSNS 是基于 ThinkPHP 3.2.4框架开发的, 因此在复现漏洞时先温习一下其中的内置函数吧, ThinkPHP函数文件位于 ThinkPHP/Common/functions.php文件。

R函数

用于远程调用控制器的方法, 接收 $url, $vars, $layer参数。

  • 调用 pathinfo 函数解析 $url参数
  • 调用A函数实例化类
  • 通过 call_user_func_array 函数调用远程控制器方法

image-20210625211659225

A函数

用于实例化多层控制器, 接收 $name, $layer, $level参数。

  • 解析资源地址
  • 类存在返回实例化对象, 反之返回false

image-20210625212251435

D函数

实例化模型类, 拼接的路径默认是模块下的 Model目录, 所以只能是 模型类

  • 解析资源地址
  • 实例化类并返回

image-20210625213023433

远程代码执行分析

漏洞位于 Application/Weibo/Controller/ShareController.class.phpshareBox方法, 功能很简单, 如下所示

  • 从GET接收query参数后进行url解码
  • 将接收的query参数解析为一个数组变量
  • 调用assign方法传入可控的参数
  • 调用T方法渲染模版

image-20210625213906609

在模版文件中可以看到调用了 W函数传入了两个参数, Weibo/Share/fetchShare和前面调用 assign方法时传入的可控的 $parse_array变量。

image-20210625213838535

W 函数调用 R函数, 多传入了一个 Widget字符串。

image-20210625214100316

接下来的过程就不多赘述了, 不明白的看上面的函数分析就懂了, 程序会调用到 Application/Weibo/Widget/ShareWidget.class.phpfetchShare方法。

image-20210625214408975

assignFetch方法会调用 D函数, 其会返回 Application/Weibo/Model/ShareModel.class.php的实例对象, 然后调用该对象的 getInfo方法, 漏洞核心正是位于该方法。

可以看到在 getInfo中调用的 D函数参数完全可控, 前面说过只要通过 D函数则可以实例化一个模型类, 而此处的参数完全可控则代表我们可以实例化任意一个模型类, 并且可以调用返回的模型类的任意方法且参数可控。唯一不足的是只有第一个参数是可控的。

image-20210625215008896

ThinkPHP/Library/Think/Model.class.php 中的 _validationFieldItem方法调用了 call_user_func_array函数, 通过该函数我们又可以执行任意函数了, 但此次的 $val参数并不可控, 上面说过了, 我们只能够控制调用方法的第一个参数。

image-20210625220035838

而该漏洞的作者找到了 *Application/Common/Model/ScheduleModel.class.php *runSchedule方法, 通过该方法再次调用 D函数, 而这回调用的方法和两个参数都可控, 完美地弥补了前面所说的不足之处。

image-20210625220152599

漏洞复现

1
http://127.0.0.1/?s=Weibo/Share/shareBox&query=app%3DCommon%26model%3DSchedule%26method%3DrunSchedule%26id%5Bstatus%5D%3D1%26id%5Bmethod%5D%3D-%3E_validationFieldItem%26id%5Bargs%5D%3Dv%3D1%26id%5B%5D%3Dv%26id%5B%5D%3Dphpinfo%26id%5B%5D%3D1%26id%5B%5D%3D1%26id%5B%5D%3Dfunction%26id%5B%5D%3D1

image-20210625231906724

参考

某CMS代码执行漏洞分析