问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2024-6365 WordPress ProductTableByWBW插件 远程代码执行漏洞 分析复现
漏洞分析
本文主要分析了CVE-2024-6365的漏洞原理,同时也演示了如何从diff补丁、根据漏洞描述去定位漏洞触发点,从而回溯分析到用户传参入口点的整个漏洞复现过程,以及这个过程中碰到的一些坑。
一、漏洞简介 ------ WordPress插件“The Product Table by WBW”在小于等于2.0.1版本的`saveCustomTitle`方法存在一个未授权远程代码执行(RCE)漏洞。这个漏洞是由于在`languages/customTitle.php`文件中缺少授权验证以及对附加数据的清理不当导致的。这使得未经身份验证的攻击者有可以在安装了该插件的服务器上执行任意代码。建议用户更新到2.0.2或更高版本以修复此漏洞。 二、影响版本 ------ Product Table By WBW <= 2.0.1 三、漏洞原理分析 -------- 这个漏洞影响了小于等于2.0.1的版本,也就是说2.0.1版本是存在漏洞的,而这个漏洞在2.0.2版本已经修复了,我们可以直接diff这两个版本的源码,并且根据CVE给出的漏洞描述来快速定位漏洞点。 根据漏洞描述信息,漏洞是发生在`saveCustomTitle`方法中,我们在diff中快速找到了漏洞点。见下图,左边是2.0.1版本,右边则是已经修复了漏洞的2.0.2版本。可以看到了在第8-10行增加了权限校验,限制了只有拥有管理权限的用户才能调用此方法。而下面第26行增加的代码则是对特殊字符单引号、双引号和反斜杠进行了替换。并对替换后的字符串进行了消毒。  然后我们分析一下存在漏洞的2.0.1版本中的`saveCustomTitle`为什么存在漏洞。整个方法也就40多行代码,首先粗略的看了一眼这个方法,最后边有一个`file_put_contents`就比较容易联想到可能是用户传入的数据被写到了某个文件中从而导致RCE。然后来跟踪一下要写入的文件名和文件内容。被写入的文件名$file在第10行已经固定了,用户不可控,值为`WTBP_DIR . 'languages' . DS . 'customTitle.php';`其中这个DS是插件预定义的一个常量,代表反斜杠。直接访问这个文件能够访问到,但是会报错,因为名为`__`的方法没有被定义,所以在后面打payload的时候需要一点小技巧,要先把`__`这个方法重新定义一下,这个具体见后面payload 的写法就知道了。  然后来看下文件内容是否可控,文件内容的构成只要跟踪$str变量就可以了。往上看,在28-38行定义了一个$phrases数组,下面遍历了这个数组,将这个数组中的每个元素作为$data\["settings"\]的key,根据key取得对应的value,如果value不在$match\[1\]这个数组中,则会被拼接进$str中,从而写入到文件内容中,这是能够写入文件内容的第一条路径,不过上面还有一个触发点。 使用正则表达式`/__\('(.+?)'/`匹配了在第12行读取的customTitle.php文件的内容。customTitle.php文件的内容如下图所示,这个正则表达式用于匹配 `__()` 函数中的第一个参数。customTitle.php这个文件是插件自带的,肯定是存在的,所以第11行的if肯定是true。   在 PHP 的 `preg_match_all` 函数中,当使用圆括号 `()` 来创建一个捕获组时,函数会返回一个多维数组。这个多维数组包含了所有匹配的结果,以及每个捕获组中匹配的结果。`$matches[0]`是一个一维数组,包含了所有完整的匹配结果;`$matches[1]`是一个一维数组,包含了每个捕获组中匹配的结果。写个简单的例子就很容易懂。   在第21-26行则是能够写入文件的第二条路径。遍历了$table,$table来源于函数参数`$data['settings']['order']`,如果参数中有`display_name`则$title取自`display_name`字段,否则取自`original_name`字段,同样的如果$title不在$matches\[1\]中,也会被拼接进$str变量,从而写入文件内容,这个触发点相较于前一个触发点在方法中的执行位置更靠前,触发比较简单,下面漏洞复现环节也是用的这个触发点。 现在我们分析完了`saveCustomTitle`方法,需要去找在哪里调用了这个方法。`saveCustomTitle`方法一共有两处调用,就在下面的`save`方法中。两次调用只是因为if条件的不同,一次是入参$data中id不为空的情况,一次是入参$data中id为空的情况。不管那种情况,`save`方法的入参$data都是直接传入了`saveCustomTitle`方法。所以我们接下来看在哪里调用了`save`方法,以及它的入参是怎么被传进来的。  直接用IDE自带的查找调用没找到被调用的地方。因为PHP的框架或者插件有很多文件级别的操作,IDE对这种数据流动的跟踪支持的并不好。这时候看了下目录结构,`saveCustomTitle`和`save`方法都在`xxx/models/wootablepress.php`这个文件中,尝试直接搜索文件名,发现在`wootablepress\controller.php:104`有一处调用了`save`方法。  `controller.php#save()`的实现中(第96行)可以清晰地看到将用户post传入的数据直接传到了`wootablepress.php#save($data)`中。  到这整个数据流算是跑通了,整体调用链如下: ```php controller.php#save():104 <- ReqWtbp::get('post') wootablepress.php#save($data) wootablepress.php#saveCustomTitle($data) ``` 但还有一个问题,就是授权。从`controller.php#save()`的第92-94行看到这里其实做了权限校验,只有当前用户拥有管理员权限才可以调用这个方法,否则就直接走到`wp_die()`了就走不下去了。所以上面的数据流只是一个授权后的RCE。而我们从漏洞描述中可以看到这是一个未授权RCE,所以一定有其他的地方调用了`wootablepress.php#save($data)`。继续搜了一下发现`wootablepress.php#save($data)`其实有两处调用,进入另一处调用看看。  跟踪到controller.php的另一个方法`createTable()`。在第150行将用户post传入数据直接传递给了`wootablepress.php#save($data)`,并且也没看到有权限校验的地方。所以这才是这个未授权RCE的正确入口。  未授权rce的调用链如下: ```php controller.php#createTable():148 <- ReqWtbp::get('post') wootablepress.php#save($data) wootablepress.php#saveCustomTitle($data) ``` 至此整个未授权RCE就分析完了。 四、环境搭建 ------ PHP环境用的XP面板的WAMP,Apache 2.4.39,PHP 7.4.3  PHP必须选择7.4及以上的,因为在安装完ProductTableByWBW 插件后会要求再安装一个WooCommerce插件,要求PHP 7.4+  WordPress选择ProductTableByWBW插件 2.0.1兼容性测试通过的最高版本6.5.5  常规的配置完数据库之后就开始WordPress安装   登录后台后上传zip安装ProductTableByWBW插件   启用插件后在左边菜单栏会出现Product Tables的标签页,要使用里面的功能需要先安装WooCommerce插件,装完之后整个环境搭建环节就结束了。  五、漏洞复现 ------  可以看到我们的payload已经被写入customTitle.php文件了  直接访问这个文件即可触发。  六、总结 ---- 整个漏洞的原理其实并不复杂,调用链也只有三层,很容易跟踪。 本文主要在讲述了CVE-2024-6365这个漏洞原理的同时也演示了如何从diff补丁、根据漏洞描述去定位漏洞触发点,从而回溯分析到用户传参入口点的整个漏洞复现过程,以及这个过程中碰到的一些坑,比如由于PHP语法灵活导致的IDE无法查找到方法被调用的地方,需要手动去查找。以及如何找到一条未授权的链路将授权后的RCE变成未授权RCE。
发表于 2024-09-20 16:00:00
阅读 ( 9606 )
分类:
Web应用
0 推荐
收藏
0 条评论
请先
登录
后评论
晚风
1 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!