CVE-2023-45197: Unrestricted Upload of File with Dangerous Type (CWE-434)
value: The file upload plugin in Adminer and AdminerEvo allows an attacker to upload a file with a table name of “..” to the root of the Adminer directory. The attacker can effectively guess the name of the uploaded file and execute it. Adminer is no longer supported, but this issue was fixed in AdminerEvo version 4.8.3.
CWE description: The product allows the upload or transfer of dangerous file types that are automatically processed within its environment.
CVSS v3 base score: 9.8
Published: 2024-06-21T15:15Z
Repository: https://github.com/adminerevo/adminerevo
Language: PHP
Files changed: plugins/file-upload.php
Commit date: 2023-10-17 22:19:17 +0200
Commit message: Plugin file-upload generate temp filename no extension + prevent file to be located elsewhere then under upload path

Diff: diff --git a/plugins/file-upload.php b/plugins/file-upload.php
index af352673..ef216f35 100644
--- a/plugins/file-upload.php
+++ b/plugins/file-upload.php
@@ -30,16 +30,26 @@ class AdminerFileUpload {
 
 	function processInput($field, $value, $function = "") {
 		if (preg_match('~(.*)_path$~', $field["field"], $regs)) {
 			$table = ($_GET["edit"] != "" ? $_GET["edit"] : $_GET["select"]);
 			$name = "fields-$field[field]";
-			if ($_FILES[$name]["error"] || !preg_match("~(\\.($this->extensions))?\$~", $_FILES[$name]["name"], $regs2)) {
+			if ($_FILES["fields"]["error"][$field["field"]] || !preg_match("~(\\.($this->extensions))?\$~", $_FILES["fields"]["name"][$field["field"]], $regs2)) {
 				return false;
 			}
-			//! unlink old
-			$filename = uniqid() . $regs2[0];
-			if (!move_uploaded_file($_FILES[$name]["tmp_name"], "$this->uploadPath$table/$regs[1]-$filename")) {
+			// create sub-directory if needed
+			if (file_exists(__DIR__ . '/' . $this->uploadPath . '/' . $table) === false) {
+				mkdir(__DIR__ . '/' . $this->uploadPath . '/' . $table);
+			}
+			// generate filename
+			$filename = realpath(tempnam(__DIR__ . '/' . $this->uploadPath . '/' . $table, ''));
+			
+			// prevent the final to be anywhere else then under the upload directory
+			if (strpos($filename, realpath(__DIR__ . '/' . $this->uploadPath)) !== 0) {
+				return false;
+			}
+			// move file to its final location
+			if (!move_uploaded_file($_FILES["fields"]["tmp_name"][$field["field"]], $filename)) {
 				return false;
 			}
 			return q($filename);
 		}
 	}

Vulnerable code: 			if ($_FILES[$name]["error"] || !preg_match("~(\\.($this->extensions))?\$~", $_FILES[$name]["name"], $regs2)) {
			//! unlink old
			$filename = uniqid() . $regs2[0];
			if (!move_uploaded_file($_FILES[$name]["tmp_name"], "$this->uploadPath$table/$regs[1]-$filename")) {
Fixed code: 			if ($_FILES["fields"]["error"][$field["field"]] || !preg_match("~(\\.($this->extensions))?\$~", $_FILES["fields"]["name"][$field["field"]], $regs2)) {
			// create sub-directory if needed
			if (file_exists(__DIR__ . '/' . $this->uploadPath . '/' . $table) === false) {
				mkdir(__DIR__ . '/' . $this->uploadPath . '/' . $table);
			}
			// generate filename
			$filename = realpath(tempnam(__DIR__ . '/' . $this->uploadPath . '/' . $table, ''));
			
			// prevent the final to be anywhere else then under the upload directory
			if (strpos($filename, realpath(__DIR__ . '/' . $this->uploadPath)) !== 0) {
				return false;
			}
			// move file to its final location
			if (!move_uploaded_file($_FILES["fields"]["tmp_name"][$field["field"]], $filename)) {