CVE-2018-11331 (published 2018-05-21T21:29Z)

An issue was discovered in Pluck before 4.7.6. Remote PHP code execution is possible because the set of disallowed filetypes for uploads in missing some applicable ones such as .phtml and .htaccess.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-434
cwe_name: Unrestricted Upload of File with Dangerous Type
description: The product allows the upload or transfer of dangerous file types that are automatically processed within its environment.
extended_description: 
            
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/pluck-cms/pluck
commit_details: repo_url: https://github.com/pluck-cms/pluck
author: Bas S
author_date: 2018-05-21 12:21:01+02:00
msg: bugfix for XSS and backdoor file upload found by s7acktrac3 issue #58
repository: repo_url: https://github.com/pluck-cms/pluck
repo_name: pluck-cms/pluck
description: Central repo for pluck cms
repo_language: PHP
owner: pluck-cms
file_changes: filename: editpage.php
change_type: ModificationType.MODIFY
diff: @@ -39,10 +39,10 @@ if (isset($_POST['save']) || isset($_POST['save_exit'])) {
 			$title = $_POST['title'];
 		//If we are editing an existing page, pass current seo-name.
 		if (isset($_GET['page'])) {
-			$seoname = save_page($title, $_POST['content'], $_POST['hidden'], $_POST['sub_page'], $_POST['description'], $_POST['keywords'], $module_additional_data, $_GET['page']);
+			$seoname = latinOnlyInput(save_page($title, $_POST['content'], $_POST['hidden'], $_POST['sub_page'], $_POST['description'], $_POST['keywords'], $module_additional_data, $_GET['page']));
 		} else {
 		//If we are creating a new page, don't pass seo-name.
-			$seoname = save_page($title, $_POST['content'], $_POST['hidden'], $_POST['sub_page'], $_POST['description'], $_POST['keywords'], $module_additional_data);
+			$seoname = latinOnlyInput(save_page($title, $_POST['content'], $_POST['hidden'], $_POST['sub_page'], $_POST['description'], $_POST['keywords'], $module_additional_data));
 		}
 		//If seoname is false, a file already exists with the same name
 		if (empty($seoname)) {

programming_language: PHP
filename: files.php
change_type: ModificationType.MODIFY
diff: @@ -32,24 +32,27 @@ defined('IN_PLUCK') or exit('Access denied!');
 </div>
 <?php
 if (isset($_POST['submit'])) {
-		if (!copy($_FILES['filefile']['tmp_name'], 'files/'.$_FILES['filefile']['name']))
+		if (!copy($_FILES['filefile']['tmp_name'], 'files/'.latinOnlyInput(latinOnlyInput($_FILES['filefile']['name']))))
 			show_error($lang['general']['upload_failed'], 1);
 		else {
-			if (strcasecmp(substr($_FILES['filefile']['name'], -3),'php') == 0){
-				if (!rename('files/'.$_FILES['filefile']['name'], 'files/'.$_FILES['filefile']['name'].'.txt')){
+			$lastfour = strtolower(substr(latinOnlyInput($_FILES['filefile']['name']), -4));
+			$lastfive = strtolower(substr(latinOnlyInput($_FILES['filefile']['name']), -5));
+			$blockedExtentions = array('.php','php3','php4','php5','php6','php7','phtml');
+			if (in_array($lastfour, $blockedExtentions) or in_array($lastfive, $blockedExtentions) ){
+				if (!rename('files/'.latinOnlyInput($_FILES['filefile']['name']), 'files/'.latinOnlyInput($_FILES['filefile']['name']).'.txt')){
 					show_error($lang['general']['upload_failed'], 1);
 				}
-				chmod('files/'.$_FILES['filefile']['name'].'.txt', 0775);
+				chmod('files/'.latinOnlyInput($_FILES['filefile']['name']).'.txt', 0775);
 			}else{
-				chmod('files/'.$_FILES['filefile']['name'], 0775);
+				chmod('files/'.latinOnlyInput($_FILES['filefile']['name']), 0775);
 			}
 			?>
 				<div class="menudiv">
-					<strong><?php echo $lang['files']['name']; ?></strong> <?php echo $_FILES['filefile']['name']; ?>
+					<strong><?php echo $lang['files']['name']; ?></strong> <?php echo latinOnlyInput($_FILES['filefile']['name']); ?>
 					<br />
-					<strong><?php echo $lang['files']['size']; ?></strong> <?php echo $_FILES['filefile']['size'].' '.$lang['images']['bytes']; ?>
+					<strong><?php echo $lang['files']['size']; ?></strong> <?php echo latinOnlyInput($_FILES['filefile']['size']).' '.$lang['images']['bytes']; ?>
 					<br />
-					<strong><?php echo $lang['files']['type']; ?></strong> <?php echo $_FILES['filefile']['type']; ?>
+					<strong><?php echo $lang['files']['type']; ?></strong> <?php echo latinOnlyInput($_FILES['filefile']['type']); ?>
 					<br />
 					<strong><?php echo $lang['files']['success']; //TODO: Need to show this message another place, and with show_error(). ?></strong>
 				</div>
@@ -66,6 +69,7 @@ $files = read_dir_contents('files', 'files');
 	if ($files) {
 		natcasesort($files);
 		foreach ($files as $file) {
+			if (!($file == '.htaccess')){
 		?>
 			<div class="menudiv">
 				<span>
@@ -84,6 +88,7 @@ $files = read_dir_contents('files', 'files');
 				</span>
 			</div>
 			<?php
+			}
 		}
 		unset($files);
 	}

programming_language: PHP
filename: functions.all.php
change_type: ModificationType.MODIFY
diff: @@ -215,10 +215,28 @@ function sanitize($var, $html = true) {
  */
 function preventXSS($var) {
 	$var = str_replace('\'', '', $var);
+	$var = htmlspecialchars($var, ENT_COMPAT, 'UTF-8', false);
 
 	return $var;
 }
 
+/**
+ * latinOnlyInput from a URL, to make it ready for saving in a file.
+ *
+ * @since 4.7.5
+ * @package all
+ * @param string $var Variable 
+ * @return string The sanitized variable.
+ * 
+ * Added as bugfix for XSS and backdoor file upload found by s7acktrac3
+ */
+function latinOnlyInput($var) {
+	$var = str_replace(chr(0), '', $var);
+	$var = preg_replace("/[^a-zA-Z0-9.\ -_]+/", "", $var);;
+	return $var;
+}
+
+
 /**
  * Displays or returns an error, notice or success message.
  *

programming_language: PHP
filename: images.php
change_type: ModificationType.MODIFY
diff: @@ -39,17 +39,17 @@ if (isset($_POST['submit'])) {
         if (!in_array(strtolower(substr($_FILES['imagefile']['name'], -4)), $imagewhitelist))
 			show_error($lang['general']['upload_failed'], 1);
 		/* end of fix issue 44. Thanks to Klaus.  */
-		if (!copy($_FILES['imagefile']['tmp_name'], 'images/'.$_FILES['imagefile']['name']))
+		if (!copy($_FILES['imagefile']['tmp_name'], 'images/'.latinOnlyInput($_FILES['imagefile']['name'])))
 			show_error($lang['general']['upload_failed'], 1);
 		else {
 			chmod('images/'.$_FILES['imagefile']['name'], 0666);
 			?>
 				<div class="menudiv">
-					<strong><?php echo $lang['images']['name']; ?></strong> <?php echo $_FILES['imagefile']['name']; ?>
+					<strong><?php echo $lang['images']['name']; ?></strong> <?php echo latinOnlyInput($_FILES['imagefile']['name']); ?>
 					<br />
-					<strong><?php echo $lang['images']['size']; ?></strong> <?php echo $_FILES['imagefile']['size'].' '.$lang['images']['bytes']; ?>
+					<strong><?php echo $lang['images']['size']; ?></strong> <?php echo latinOnlyInput($_FILES['imagefile']['size']).' '.$lang['images']['bytes']; ?>
 					<br />
-					<strong><?php echo $lang['images']['type']; ?></strong> <?php echo $_FILES['imagefile']['type']; ?>
+					<strong><?php echo $lang['images']['type']; ?></strong> <?php echo latinOnlyInput($_FILES['imagefile']['type']); ?>
 					<br />
 					<strong><?php echo $lang['images']['success']; //TODO: Need to show this message another place, and with show_error(). ?></strong>
 				</div>
@@ -67,6 +67,7 @@ $images = read_dir_contents('images', 'files');
 	if ($images) {
 		natcasesort($images);
 		foreach ($images as $image) {
+			if (!($image == '.htaccess')){
 		?>
 			<div class="menudiv">
 				<span>
@@ -85,6 +86,7 @@ $images = read_dir_contents('images', 'files');
 				</span>
 			</div>
 			<?php
+			}
 		}
 		unset($images);
 	}

programming_language: PHP
filename: .htaccess
change_type: ModificationType.ADD
diff: @@ -0,0 +1,9 @@
+<FilesMatch \.php$>
+    SetHandler None
+</FilesMatch>
+
+<FilesMatch \.phtml>
+    SetHandler None
+</FilesMatch>
+
+Options -ExecCGI

programming_language: Markdown
filename: .htaccess
change_type: ModificationType.ADD
diff: @@ -0,0 +1,9 @@
+<FilesMatch \.php$>
+    SetHandler None
+</FilesMatch>
+
+<FilesMatch \.phtml>
+    SetHandler None
+</FilesMatch>
+
+Options -ExecCGI

programming_language: Markdown
filename: .htaccess
change_type: ModificationType.ADD
diff: @@ -0,0 +1,9 @@
+<FilesMatch \.php$>
+    SetHandler None
+</FilesMatch>
+
+<FilesMatch \.phtml>
+    SetHandler None
+</FilesMatch>
+
+Options -ExecCGI

programming_language: Markdown
filename: .htaccess
change_type: ModificationType.ADD
diff: @@ -0,0 +1,9 @@
+<FilesMatch \.php$>
+    SetHandler None
+</FilesMatch>
+
+<FilesMatch \.phtml>
+    SetHandler None
+</FilesMatch>
+
+Options -ExecCGI

programming_language: Markdown