OpenSNS远程代码执行漏洞分析
前言
某天在微信上看到了 补天平台
的微信公众号文章推送, 是一篇PHP的代码审计文章。简单看了下觉得利用过程挺有意思的, 与普通的追溯敏感函数审计相对有意思些, 于是便有了文本。
ThinkPHP内置函数
OpenSNS
是基于 ThinkPHP 3.2.4框架开发的, 因此在复现漏洞时先温习一下其中的内置函数吧, ThinkPHP函数文件位于 ThinkPHP/Common/functions.php文件。
R函数
用于远程调用控制器的方法, 接收 $url
, $vars
, $layer
参数。
- 调用 pathinfo 函数解析
$url
参数 - 调用A函数实例化类
- 通过 call_user_func_array 函数调用远程控制器方法
A函数
用于实例化多层控制器, 接收 $name
, $layer
, $level
参数。
- 解析资源地址
- 类存在返回实例化对象, 反之返回false
D函数
实例化模型类, 拼接的路径默认是模块下的 Model
目录, 所以只能是 模型类。
- 解析资源地址
- 实例化类并返回
远程代码执行分析
漏洞位于 Application/Weibo/Controller/ShareController.class.php的 shareBox
方法, 功能很简单, 如下所示
- 从GET接收query参数后进行url解码
- 将接收的query参数解析为一个数组变量
- 调用assign方法传入可控的参数
- 调用T方法渲染模版
在模版文件中可以看到调用了 W
函数传入了两个参数, Weibo/Share/fetchShare
和前面调用 assign
方法时传入的可控的 $parse_array
变量。
W
函数调用 R
函数, 多传入了一个 Widget
字符串。
接下来的过程就不多赘述了, 不明白的看上面的函数分析就懂了, 程序会调用到 Application/Weibo/Widget/ShareWidget.class.php的 fetchShare
方法。
assignFetch
方法会调用 D
函数, 其会返回 Application/Weibo/Model/ShareModel.class.php的实例对象, 然后调用该对象的 getInfo
方法, 漏洞核心正是位于该方法。
可以看到在 getInfo
中调用的 D
函数参数完全可控, 前面说过只要通过 D
函数则可以实例化一个模型类, 而此处的参数完全可控则代表我们可以实例化任意一个模型类, 并且可以调用返回的模型类的任意方法且参数可控。唯一不足的是只有第一个参数是可控的。
在 ThinkPHP/Library/Think/Model.class.php 中的 _validationFieldItem
方法调用了 call_user_func_array
函数, 通过该函数我们又可以执行任意函数了, 但此次的 $val
参数并不可控, 上面说过了, 我们只能够控制调用方法的第一个参数。
而该漏洞的作者找到了 *Application/Common/Model/ScheduleModel.class.php *的 runSchedule
方法, 通过该方法再次调用 D
函数, 而这回调用的方法和两个参数都可控, 完美地弥补了前面所说的不足之处。
漏洞复现
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 |