Post

WooCommerce Designer Pro 插件 文件上传漏洞

太久没写漏洞分析了,先弄个简单的漏洞分析吧~这是一个相对简单的文件上传漏洞。

WooCommerce Designer Pro 插件 文件上传漏洞

漏洞描述

Ref:

用于 WordPress 的 WooCommerce Designer Pro 插件,被 Pricom - Printing Company & Design Services WordPress 主题使用,由于在所有版本至 1.9.26 中缺少文件类型验证,在’wcdp_save_canvas_design_ajax’函数中存在任意文件上传漏洞。这使得未经身份验证的攻击者能够上传任意文件到受影响站点的服务器上,从而可能实现远程代码执行。

获取源码

在发现这个是一个付费的插件之后,就决定了这个漏洞是难上手评估的了。但是还是给我通过查找关键字 wc-designer-pro 在 Github 的某个项目中查找到这个插件的源码。 项目地址是这个

后面发现也可以下载这个叫 Pricom 的主题来获取这个插件的源码,虽然这个主题也是付费主题,但是花点时间耐心找找还是可以找到的。 主题地址:https://sync.oybird.com/cb8d7f833fe25351/pricom_v1.8.1_package.zip?download_token=adc19d7136933f3bb3cd8dddd4f0f762199f2f68bcaad084c00b8ca2c43f9e19

这个地址大概率是无法下载了,但是找找还是可以找到的,需要注意的是,携带有漏洞的主题的版本是 1.8.1 之前,所以请下载正确的版本去分析。

代码分析

这里我分析的是 Github 项目中的源码,具体的版本可以在 wp-content/plugins/wc-designer-pro/changelog.txt 里面看到,第一行就是该插件的版本。我这里分析的是 1.9.24,公网绝大多数也是这个版本。

首先看到公告中说的具体的函数是 wcdp_save_canvas_design_ajax,我们直接查找源码就可以看到函数的位置了。

wc-designer-pro/includes/wcdp-save-design.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
function wcdp_save_canvas_design_ajax(){
    // 1. 解码用户通过POST请求提交的JSON字符串
    // stripslashes() 用于移除反斜杠,防止JSON解析错误
    // json_decode() 将JSON字符串转换为PHP数组 $pr
    // 关键点:$pr 数组的内容完全由用户控制
    $pr = json_decode(stripslashes($_POST['params']), true);

    // 2. 检查用户是否登录,获取用户ID,否则为false
	$userID = is_user_logged_in() ? get_current_user_id() : false;
	$response = array('userID' => $userID, 'filesCMYK' => array());
	
    // 3. 根据用户传入的 'mode' 参数,构造文件夹路径
    // 关键点:这里开始进行危险的路径拼接
	if($pr['mode'] == 'addtocart'){
        // 如果 mode 是 'addtocart',则将用户可控的 'uniq' 参数直接拼接到路径中
        // 漏洞核心:这里没有对 $pr['uniq'] 进行任何过滤或清理,存在明显的路径遍历风险
		$folder = '/temp/'. $pr['uniq'];
	}
	else if($pr['mode'] == 'publish' || $pr['mode'] == 'save'){
		if($pr['editor'] == 'frontend')
			$folder = ($userID ? '/save-user/' : '/temp/') . $pr['uniq'];
		else
			$folder = '/save-admin/designID'. $pr['designID'];
	}

    // 4. 将上传根目录和一个常量 与 上一步构造的 $folder 拼接,形成最终的完整物理路径
    // 例如:/var/www/html/wp-content/uploads/wcdp/temp/../../../
	$url_path = WCDP_PATH_UPLOADS . $folder;

    // 5. 检查路径是否存在,如果不存在,则递归创建目录
    // mkdir 的第三个参数 true 允许创建嵌套目录,这使得路径遍历攻击更容易成功
    if(!file_exists($url_path))
	    mkdir($url_path, 0755, true);

	// 6. 遍历用户传入的 'files' 数组,准备处理上传的文件
	$result = 0;
	foreach($pr['files'] as $file){
	    $count = $file['count']; // 从用户JSON中获取用于在 $_FILES 中查找的键名
		$name = $file['name'];     // 从用户JSON中获取文件名(不含扩展名)
		$ext = $file['ext'];       // 从用户JSON中获取文件扩展名
        $fileTEMP = $_FILES[$count]['tmp_name']; // 根据用户提供的键名,在$_FILES中找到上传的临时文件
        
        // 需要注意的是:$fileTEMP 不为空才进入这个分支
        // 也就是 $_FILES[$count]['tmp_name'] 不是空
        // $_FILES[$count]['tmp_name'] 就是文件上传的临时文件的位置,是php自动生成的,作为我们 sink 的第一个参数
        if(!empty($fileTEMP))
            // 7. 漏洞触发点 (Sink)
		    $result = move_uploaded_file($fileTEMP, $url_path .'/'. $name . ($ext == 'CMYK' ? '_CMYK.jpg' : '.'. $ext));
}

其次这个 action 是个未授权的接口,而且不需要验证用户的 nonce,所以这个很明显是一个未授权的 RCE。

1
add_action( 'wp_ajax_nopriv_wcdp_save_canvas_design_ajax','wcdp_save_canvas_design_ajax' );

其他

虽然公网中大多数安装了这个插件的 wordpress 应用都受影响,但是因为大概 90% 的应用都设置了 WAF,所以他们都无法被攻击成功。

This post is licensed under CC BY 4.0 by the author.