CVE-2023-1033 (published 2023-02-25T01:15Z)

Cross-Site Request Forgery (CSRF) in GitHub repository froxlor/froxlor prior to 2.0.11.

CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/froxlor/froxlor
commit_details: repo_url: https://github.com/froxlor/froxlor
author: Michael Kaufmann
author_date: 2023-02-14 11:36:11+01:00
msg: check for existing fields when setting/updating tablelisting-columns

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
repository: repo_url: https://github.com/froxlor/froxlor
repo_name: froxlor/Froxlor
description: The server administration software for your needs - The official Froxlor development Git repository
repo_language: PHP
owner: froxlor
file_changes: filename: Ajax.php
change_type: ModificationType.MODIFY
diff: @@ -237,11 +237,11 @@ class Ajax
 	private function updateTablelisting()
 	{
 		$columns = [];
-		foreach ((Request::any('columns') ?? []) as $value) {
+		foreach ((Request::post('columns') ?? []) as $value) {
 			$columns[] = $value;
 		}
 		if (!empty($columns)) {
-			Listing::storeColumnListingForUser([Request::any('listing') => $columns]);
+			$columns = Listing::storeColumnListingForUser([Request::post('listing') => $columns]);
 			return $this->jsonResponse($columns);
 		}
 		return $this->errorResponse('At least one column must be selected', 406);
@@ -249,7 +249,7 @@ class Ajax
 
 	private function resetTablelisting()
 	{
-		Listing::deleteColumnListingForUser([Request::any('listing') => []]);
+		Listing::deleteColumnListingForUser([Request::post('listing') => []]);
 		return $this->jsonResponse([]);
 	}
 

programming_language: PHP
filename: Listing.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,7 @@ namespace Froxlor\UI;
 
 use Froxlor\CurrentUser;
 use Froxlor\Database\Database;
+use Froxlor\Froxlor;
 use Froxlor\UI\Panel\UI;
 use InvalidArgumentException;
 
@@ -247,9 +248,9 @@ class Listing
 	 * ]
 	 *
 	 * @param array $tabellisting
-	 * @return bool
+	 * @return array
 	 */
-	public static function storeColumnListingForUser(array $tabellisting): bool
+	public static function storeColumnListingForUser(array $tabellisting): array
 	{
 		$section = array_key_first($tabellisting);
 		if (empty($section) || !is_array($tabellisting[$section]) || empty($tabellisting[$section])) {
@@ -259,6 +260,22 @@ class Listing
 		if (CurrentUser::isAdmin()) {
 			$userid = 'adminid';
 		}
+		// include all possible tablelisting-definitions to check for the right section
+		foreach(glob(Froxlor::getInstallDir().'lib/tablelisting/{,*/}*.php', GLOB_BRACE) as $tbl_file) {
+			$table_listings = include $tbl_file;
+			if (!isset($table_listings[$section])) {
+				continue;
+			} else {
+				break;
+			}
+		}
+		$columns_available = array_keys($table_listings[$section]['columns']);
+		// filter out unknown columns
+		foreach ($tabellisting[$section] as $index => $column_changed) {
+			if (!in_array($column_changed, $columns_available)) {
+				unset($tabellisting[$section][$index]);
+			}
+		}
 		// delete possible existing entry
 		self::deleteColumnListingForUser($tabellisting);
 		// add new entry
@@ -273,7 +290,7 @@ class Listing
 			'section' => $section,
 			'cols' => json_encode($tabellisting[$section])
 		]);
-		return true;
+		return $tabellisting[$section];
 	}
 
 	/**

programming_language: PHP
filename: tablelisting.domains.php
change_type: ModificationType.MODIFY
diff: @@ -29,11 +29,14 @@ use Froxlor\UI\Callbacks\Style;
 use Froxlor\UI\Callbacks\Text;
 use Froxlor\UI\Listing;
 
+// used outside scope variables
+$customerCollectionCount = !is_null($customerCollection ?? null) ? $customerCollection->count() : 0;
+
 return [
 	'domain_list' => [
 		'title' => lng('admin.domains'),
 		'icon' => 'fa-solid fa-globe',
-		'empty_msg' => $customerCollection->count() == 0 ? lng('admin.domain_nocustomeraddingavailable') : '',
+		'empty_msg' => $customerCollectionCount == 0 ? lng('admin.domain_nocustomeraddingavailable') : '',
 		'self_overview' => ['section' => 'domains', 'page' => 'domains'],
 		'default_sorting' => ['d.domain_ace' => 'asc'],
 		'columns' => [

programming_language: PHP
filename: tablelisting.htaccess.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,9 @@ use Froxlor\UI\Callbacks\Ftp;
 use Froxlor\UI\Callbacks\Text;
 use Froxlor\UI\Listing;
 
+// used outside scope variables
+$cperlenabled = $cperlenabled ?? false;
+
 return [
 	'htaccess_list' => [
 		'title' => lng('menue.extras.pathoptions'),

programming_language: PHP
filename: tablelisting.mysqls.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,9 @@ use Froxlor\UI\Callbacks\Mysql;
 use Froxlor\UI\Callbacks\Text;
 use Froxlor\UI\Listing;
 
+// used outside scope variables
+$multiple_mysqlservers = $multiple_mysqlservers ?? false;
+
 return [
 	'mysql_list' => [
 		'title' => lng('menue.mysql.databases'),

programming_language: PHP
filename: tablelisting.dns.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,10 @@ use Froxlor\UI\Callbacks\Dns;
 use Froxlor\UI\Callbacks\Text;
 use Froxlor\UI\Listing;
 
+// used outside scope variables
+$domain = $domain ?? '';
+$domain_id = $domain_id ?? '';
+
 return [
 	'dns_list' => [
 		'title' => 'DNS Entries',

programming_language: PHP