CVE-2021-3745: Unrestricted Upload of File with Dangerous Type (CWE-434)
value: flatcore-cms is vulnerable to Unrestricted Upload of File with Dangerous Type
CWE description: The product allows the upload or transfer of dangerous file types that are automatically processed within its environment.
CVSS v3 base score: 6.6
Published: 2021-10-28T17:15Z
Repository: https://github.com/flatcore/flatcore-cms
Language: PHP
Files changed: acp/core/files.upload_gallery.php, acp/templates/gallery_upload_form.tpl
Commit date: 2021-10-20 10:18:27 +0200
Commit message: secure gallery upload

- add csrf token
- add random int to filenmae
- check for image file suffix

Diff: diff --git a/acp/core/files.upload_gallery.php b/acp/core/files.upload_gallery.php
index 3d0df7a..d036709 100644
--- a/acp/core/files.upload_gallery.php
+++ b/acp/core/files.upload_gallery.php
@@ -1,7 +1,23 @@
 <?php
 
+session_start();
+
+if($_SESSION['user_class'] != "administrator"){
+	header("location:../index.php");
+	die("PERMISSION DENIED!");
+}
+
+require '../../config.php';
+if(is_file('../../'.FC_CONTENT_DIR.'/config.php')) {
+	include '../../'.FC_CONTENT_DIR.'/config.php';
+}
+
+if($_POST['csrf_token'] !== $_SESSION['token']) {
+	die('Error: CSRF Token is invalid');
+}
+
 $year = date('Y',time());
 $gallery_id = 'gallery'. (int) $_REQUEST['gal'];
 $uploads_dir = '../../content/galleries/'.$year.'/'.$gallery_id;
 
 $max_width = (int) $_REQUEST['w']; // max image width
@@ -18,31 +34,38 @@ if(!is_dir($uploads_dir)) {
 } else {
 	$result['uploaddir'] = "Folder okay";
 }
 
 if(array_key_exists('file',$_FILES) && $_FILES['file']['error'] == 0 ){
+	
 	$tmp_name = $_FILES["file"]["tmp_name"];
 	$timestring = microtime(true);
+	$random_int = random_int(0, 999);
 	      
-	$suffix = strrchr($_FILES["file"]["name"],".");
-	$org_name = $timestring . $suffix;
-	$img_name = $timestring."_img.jpg";
-	$tmb_name = $timestring."_tmb.jpg";
+	$suffix = substr(strrchr($_FILES["file"]["name"],"."),1);
+	$org_name = $timestring .'.'. $suffix;
+	$img_name = $timestring.$random_int."_img.jpg";
+	$tmb_name = $timestring.$random_int."_tmb.jpg";
+
+	if(!in_array($suffix, $fc_upload_img_types)) {
+		exit;
+	} else {
         
-	if(move_uploaded_file($tmp_name, "$uploads_dir/$org_name")) {
-		create_thumbs($uploads_dir,$org_name,$img_name, $max_width,$max_height,90);
-		create_thumbs($uploads_dir,$img_name,$tmb_name, $max_width_tmb,$max_height_tmb,80);
-		unlink("$uploads_dir/$org_name");
-		print ('Uploaded');
+		if(move_uploaded_file($tmp_name, "$uploads_dir/$org_name")) {
+			create_thumbs($uploads_dir,$org_name,$img_name, $max_width,$max_height,90);
+			create_thumbs($uploads_dir,$img_name,$tmb_name, $max_width_tmb,$max_height_tmb,80);
+			unlink("$uploads_dir/$org_name");
+			print ('Uploaded');
+		}
 	}
 }
 function create_thumbs($updir, $img, $name, $thumbnail_width, $thumbnail_height, $quality){
 	$arr_image_details	= GetImageSize("$updir/$img");
 	$original_width		= $arr_image_details[0];
 	$original_height	= $arr_image_details[1];
 	$a = $thumbnail_width / $thumbnail_height;
-  $b = $original_width / $original_height;
+	$b = $original_width / $original_height;
 	
 	
 	if ($a<$b) {
      $new_width = $thumbnail_width;
      $new_height	= intval($original_height*$new_width/$original_width);
diff --git a/acp/templates/gallery_upload_form.tpl b/acp/templates/gallery_upload_form.tpl
index 99de927..772a26b 100644
--- a/acp/templates/gallery_upload_form.tpl
+++ b/acp/templates/gallery_upload_form.tpl
@@ -1,12 +1,11 @@
 <div class="modal fade" id="uploadGalModal" tabindex="-1" role="dialog">
   <div class="modal-dialog modal-lg modal-dialog-centered" role="document">
     <div class="modal-content">
       <div class="modal-header">
-        <h5 class="modal-title">Upload into {post_id}</h5>
+        <h5 class="modal-title">Upload into Gallery ID #{post_id}</h5>
         <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
-          <span aria-hidden="true">&times;</span>
         </button>
       </div>
       <div class="modal-body">
 				<form method="post" action="core/files.upload_gallery.php?gal={post_id}" id="myDropzone" class="dropzone dropzone-default">
 					<div class="fallback">
@@ -24,10 +23,11 @@
   </div>
 </div>
 
 <form action="acp.php?tn=posts&sub=edit" method="POST" id="reload_form">
 	<input type="hidden" name="post_id" value="{post_id}">
+	<input type="hidden" name="csrf_token" value="{token}">
 </form>
 
 <script>
 $(function() {
 	$('#uploadGalModal').on('hidden.bs.modal', function (e) {

Vulnerable code: 	$suffix = strrchr($_FILES["file"]["name"],".");
	$org_name = $timestring . $suffix;
	$img_name = $timestring."_img.jpg";
	$tmb_name = $timestring."_tmb.jpg";
	if(move_uploaded_file($tmp_name, "$uploads_dir/$org_name")) {
		create_thumbs($uploads_dir,$org_name,$img_name, $max_width,$max_height,90);
		create_thumbs($uploads_dir,$img_name,$tmb_name, $max_width_tmb,$max_height_tmb,80);
		unlink("$uploads_dir/$org_name");
		print ('Uploaded');
  $b = $original_width / $original_height;
        <h5 class="modal-title">Upload into {post_id}</h5>
          <span aria-hidden="true">&times;</span>
Fixed code: session_start();

if($_SESSION['user_class'] != "administrator"){
	header("location:../index.php");
	die("PERMISSION DENIED!");
}

require '../../config.php';
if(is_file('../../'.FC_CONTENT_DIR.'/config.php')) {
	include '../../'.FC_CONTENT_DIR.'/config.php';
}

if($_POST['csrf_token'] !== $_SESSION['token']) {
	die('Error: CSRF Token is invalid');
}

	
	$random_int = random_int(0, 999);
	$suffix = substr(strrchr($_FILES["file"]["name"],"."),1);
	$org_name = $timestring .'.'. $suffix;
	$img_name = $timestring.$random_int."_img.jpg";
	$tmb_name = $timestring.$random_int."_tmb.jpg";

	if(!in_array($suffix, $fc_upload_img_types)) {
		exit;
	} else {
		if(move_uploaded_file($tmp_name, "$uploads_dir/$org_name")) {
			create_thumbs($uploads_dir,$org_name,$img_name, $max_width,$max_height,90);
			create_thumbs($uploads_dir,$img_name,$tmb_name, $max_width_tmb,$max_height_tmb,80);
			unlink("$uploads_dir/$org_name");
			print ('Uploaded');
		}
	$b = $original_width / $original_height;
        <h5 class="modal-title">Upload into Gallery ID #{post_id}</h5>
	<input type="hidden" name="csrf_token" value="{token}">