Uploader checks for forbidden files more carefully. And: #56 fixed. Thanks again, Matthias!
This commit is contained in:
		
							parent
							
								
									27622c0c50
								
							
						
					
					
						commit
						c1e368b222
					
				| @ -19,7 +19,7 @@ class admin_uploader extends AdminPanel { | ||||
| 	var $actions = array( | ||||
| 		'default' => true | ||||
| 	); | ||||
| 	 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class admin_uploader_default extends AdminPanelAction { | ||||
| @ -35,73 +35,208 @@ class admin_uploader_default extends AdminPanelAction { | ||||
| 
 | ||||
| 	function onupload() { | ||||
| 		$success = false; | ||||
| 		 | ||||
| 
 | ||||
| 		/* | ||||
| 		 * first check if user is logged in | ||||
| 		 * to prevent remote admin.uploader.php script execution | ||||
| 		 * | ||||
| 		 * By testing the admin/main.php made the redirect job | ||||
| 		 * By direct URL call PHP throw a visible error -> AdminPanel class not found! | ||||
| 		 * | ||||
| 		 * 2019-11-23 - laborix | ||||
| 		 */ | ||||
| 		if (!user_loggedin()) { | ||||
| 			utils_redirect("login.php"); | ||||
| 			die(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!file_exists(IMAGES_DIR)) | ||||
| 			fs_mkdir(IMAGES_DIR); | ||||
| 		 | ||||
| 
 | ||||
| 		if (!file_exists(ATTACHS_DIR)) | ||||
| 			fs_mkdir(ATTACHS_DIR); | ||||
| 		 | ||||
| 		/* | ||||
| 		 * Blacklist entries from OWASP and | ||||
| 		 * https://stackoverflow.com/questions/4166762/php-image-upload-security-check-list | ||||
| 		 * | ||||
| 		 * 2019-11-23 - laborix | ||||
| 		 */ | ||||
| 		$blacklist_extensions = array( | ||||
| 			'htaccess', | ||||
| 			'phtml', | ||||
| 			'php', | ||||
| 			'php3', | ||||
| 			'php4', | ||||
| 			'php5', | ||||
| 			'php6', | ||||
| 			'php7', | ||||
| 			'phps', | ||||
| 			'cgi', | ||||
| 			'exe', | ||||
| 			'pl', | ||||
| 			'asp', | ||||
| 			'aspx', | ||||
| 			'shtml', | ||||
| 			'shtm', | ||||
| 			'fcgi', | ||||
| 			'fpl', | ||||
| 			'jsp', | ||||
| 			'htm', | ||||
| 			'html', | ||||
| 			'wml' | ||||
| 		); | ||||
| 
 | ||||
| 		$imgs = array( | ||||
| 			'.jpg', | ||||
| 			'.gif', | ||||
| 			'.png', | ||||
| 			'.jpeg' | ||||
| 		); | ||||
| 		$forbidden = array( | ||||
| 			'.php', | ||||
| 			'.php3', | ||||
| 			'.php4', | ||||
| 			'.php5', | ||||
| 			'.php7', | ||||
| 			'.phtml' | ||||
| 		); | ||||
| 		 | ||||
| 
 | ||||
| 		// intentionally
 | ||||
| 		// I've not put BMPs
 | ||||
| 		 | ||||
| 
 | ||||
| 		$uploaded_files = array(); | ||||
| 		 | ||||
| 
 | ||||
| 		foreach ($_FILES ["upload"] ["error"] as $key => $error) { | ||||
| 			 | ||||
| 
 | ||||
| 			if ($error == UPLOAD_ERR_OK) { | ||||
| 				$tmp_name = $_FILES ["upload"] ["tmp_name"] [$key]; | ||||
| 				$name = $_FILES ["upload"] ["name"] [$key]; | ||||
| 				 | ||||
| 
 | ||||
| 				$dir = ATTACHS_DIR; | ||||
| 				 | ||||
| 				$ext = strtolower(strrchr($name, '.')); | ||||
| 				 | ||||
| 				if (in_array($ext, $forbidden)) { | ||||
| 					$success = false; | ||||
| 					continue; | ||||
| 
 | ||||
| 				/* | ||||
| 				 * second check extension list | ||||
| 				 * https://stackoverflow.com/questions/4166762/php-image-upload-security-check-list | ||||
| 				 * | ||||
| 				 * 2019-11-24 - laborix | ||||
| 				 */ | ||||
| 
 | ||||
| 				$uploadfilename = strtolower($tmp_name); | ||||
| 
 | ||||
| 				$isForbidden = false; | ||||
| 				$deeptest = array(); | ||||
| 				$extcount = 0; | ||||
| 				$deeptest = explode('.', $uploadfilename); | ||||
| 				$extcount = count($deeptest); | ||||
| 
 | ||||
| 				if ($extcount == 1) { | ||||
| 					/* | ||||
| 					 * none extension like .jpg or something else | ||||
| 					 * | ||||
| 					 * possible filename = simple-file-without-extension - linux like ok | ||||
| 					 */ | ||||
| 					$isForbidden = false; | ||||
| 				} elseif ($extcount == 2) { | ||||
| 					/* | ||||
| 					 * Only one possible extension | ||||
| 					 * | ||||
| 					 * possible filename = 1.jpg | ||||
| 					 * possible filename = admin.uploader.php | ||||
| 					 * possible filename = .htaccess | ||||
| 					 * and so on... | ||||
| 					 */ | ||||
| 					$check_ext1 = ""; | ||||
| 					$check_ext1 = trim($deeptest [1], "\x00..\x1F"); | ||||
| 					if (in_array($check_ext1, $blacklist_extensions)) { | ||||
| 						$isForbidden = true; | ||||
| 					} else { | ||||
| 						$isForbidden = false; | ||||
| 					} | ||||
| 				} elseif ($extcount > 2) { | ||||
| 					/* | ||||
| 					 * Chekc only the last two possible extensions | ||||
| 					 * | ||||
| 					 * Hint: OWASP - Unrestricted File Upload | ||||
| 					 * | ||||
| 					 * In Apache, a php file might be executed using the | ||||
| 					 * double extension technique such as "file.php.jpg" | ||||
| 					 * when ".jpg" is allowed. | ||||
| 					 * | ||||
| 					 * possible filename = 1.PhP.jpg | ||||
| 					 * possible filename = admin.uploader.php.JPg | ||||
| 					 * and so on... | ||||
| 					 */ | ||||
| 					$check_ext1 = ""; | ||||
| 					$check_ext2 = ""; | ||||
| 					$check_ext1 = trim($deeptest [$extcount - 1], "\x00..\x1F"); | ||||
| 					if (in_array($check_ext1, $blacklist_extensions)) { | ||||
| 						$isForbidden = true; | ||||
| 					} else { | ||||
| 						$isForbidden = false; | ||||
| 					} | ||||
| 					/* Test only if first extension check are not in the blacklist */ | ||||
| 					if (!$isForbidden) { | ||||
| 						$check_ext2 = trim($deeptest [$extcount - 2], "\x00..\x1F"); | ||||
| 						if (in_array($check_ext2, $blacklist_extensions)) { | ||||
| 							$isForbidden = true; | ||||
| 						} else { | ||||
| 							$isForbidden = false; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				/* | ||||
| 				 * If one blacklisted extension found then | ||||
| 				 * return with -1 = An error occurred while trying to upload. | ||||
| 				 */ | ||||
| 				if ($isForbidden) { | ||||
| 					$this->smarty->assign('success', $success ? 1 : -1); | ||||
| 					sess_add('admin_uploader_files', $uploaded_files); | ||||
| 					return -1; | ||||
| 				} | ||||
| 
 | ||||
| 				/* | ||||
| 				 * third check extension | ||||
| 				 * if someone upload a .php file as .gif, .jpg or .txt | ||||
| 				 * if someone upload a .html file as .gif, .jpg or .txt | ||||
| 				 * | ||||
| 				 * 2019-11-24 - laborix | ||||
| 				 */ | ||||
| 
 | ||||
| 				if (version_compare(PHP_VERSION, '5.3.0') < 0) | ||||
| 					return -1; | ||||
| 				if (!function_exists('finfo_open')) | ||||
| 					return -1; | ||||
| 
 | ||||
| 				$finfo = finfo_open(FILEINFO_MIME_TYPE); | ||||
| 				$mime = finfo_file($finfo, $tmp_name); | ||||
| 				finfo_close($finfo); | ||||
| 
 | ||||
| 				if (($mime == "text/x-php") || ($mime == "text/html")) { | ||||
| 					$this->smarty->assign('success', $success ? 1 : -1); | ||||
| 					sess_add('admin_uploader_files', $uploaded_files); | ||||
| 					return -1; | ||||
| 				} | ||||
| 
 | ||||
| 				$ext = strtolower(strrchr($name, '.')); | ||||
| 
 | ||||
| 				if (in_array($ext, $imgs)) { | ||||
| 					$dir = IMAGES_DIR; | ||||
| 				} | ||||
| 				 | ||||
| 
 | ||||
| 				$name = sanitize_title(substr($name, 0, -strlen($ext))) . $ext; | ||||
| 				 | ||||
| 
 | ||||
| 				$target = "$dir/$name"; | ||||
| 				@umask(022); | ||||
| 				$success = move_uploaded_file($tmp_name, $target); | ||||
| 				@chmod($target, 0766); | ||||
| 				 | ||||
| 
 | ||||
| 				$uploaded_files [] = $name; | ||||
| 				 | ||||
| 
 | ||||
| 				// one failure will make $success == false :)
 | ||||
| 				$success &= $success; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 
 | ||||
| 		if ($uploaded_files) { | ||||
| 			$this->smarty->assign('success', $success ? 1 : -1); | ||||
| 			sess_add('admin_uploader_files', $uploaded_files); | ||||
| 		} | ||||
| 		 | ||||
| 
 | ||||
| 		return 1; | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
|  | ||||
| @ -41,7 +41,7 @@ function user_login($userid, $pwd, $params = null) { | ||||
| 
 | ||||
| 	$user = user_get($userid); | ||||
| 
 | ||||
| 	if (user_pwd($userid, $pwd) == $user ['password']) { | ||||
| 	if (isset($user) && user_pwd($userid, $pwd) == $user ['password']) { | ||||
| 
 | ||||
| 		$loggedin = true; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 azett
						azett