CVE-2022-4864 (published 2022-12-30T23:15Z)

Argument Injection in GitHub repository froxlor/froxlor prior to 2.0.0-beta1.

CVSS v3 base score: 5.4, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N)

Weakness information:
cwe_id: CWE-74
cwe_name: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
description: The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
extended_description: Software or other automated logic has certain assumptions about what constitutes data and control respectively. It is the lack of verification of these assumptions for user-controlled input that leads to injection problems. Injection problems encompass a wide variety of issues -- all mitigated in very different ways and usually attempted in order to alter the control flow of the process. For this reason, the most effective way to discuss these weaknesses is to note the distinct features that classify them as injection weaknesses. The most important issue to note is that all injection problems share one thing in common -- i.e., they allow for the injection of control plane data into the user-controlled data plane. This means that the execution of the process may be altered by sending code in through legitimate data channels, using no other mechanism. While buffer overflows, and many other flaws, involve the use of some further issue to gain execution, injection problems need only for the data to be parsed.
         

Fix information:
repo_url: https://github.com/froxlor/froxlor
commit_details: repo_url: https://github.com/froxlor/froxlor
author: Michael Kaufmann
author_date: 2022-12-30 21:43:27+01:00
msg: adjust Request-class methods to be more flexible

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: admin_admins.php
change_type: ModificationType.MODIFY
diff: @@ -39,7 +39,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettings'] == '1') {
 	if ($action == '') {

programming_language: PHP
filename: admin_configfiles.php
change_type: ModificationType.MODIFY
diff: @@ -41,8 +41,8 @@ if ($userinfo['change_serversettings'] == '1') {
 	}
 
 	// get distro from URL param
-	$distribution = Request::get('distribution');
-	$reselect = Request::get('reselect', 0);
+	$distribution = Request::any('distribution');
+	$reselect = Request::any('reselect', 0);
 
 	// check for possible setting
 	if (empty($distribution)) {

programming_language: PHP
filename: admin_cronjobs.php
change_type: ModificationType.MODIFY
diff: @@ -34,7 +34,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'cronjobs' || $page == 'overview') {
 	if ($action == '') {

programming_language: PHP
filename: admin_customers.php
change_type: ModificationType.MODIFY
diff: @@ -42,7 +42,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '0') {
 	if ($action == '') {

programming_language: PHP
filename: admin_domains.php
change_type: ModificationType.MODIFY
diff: @@ -47,7 +47,7 @@ use Froxlor\User;
 use Froxlor\Validate\Validate;
 use Froxlor\CurrentUser;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'domains' || $page == 'overview') {
 	if ($action == '') {

programming_language: PHP
filename: admin_index.php
change_type: ModificationType.MODIFY
diff: @@ -40,7 +40,7 @@ use Froxlor\UI\Response;
 use Froxlor\Validate\Validate;
 use Froxlor\Language;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($action == 'logout') {
 	$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "logged out");

programming_language: PHP
filename: admin_ipsandports.php
change_type: ModificationType.MODIFY
diff: @@ -36,7 +36,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'ipsandports' || $page == 'overview') {
 	if ($action == '') {

programming_language: PHP
filename: admin_message.php
change_type: ModificationType.MODIFY
diff: @@ -33,7 +33,7 @@ use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 use Froxlor\User;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 $note_type = null;
 $note_msg = null;

programming_language: PHP
filename: admin_mysqlserver.php
change_type: ModificationType.MODIFY
diff: @@ -36,7 +36,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'mysqlserver' || $page == 'overview') {
 	if ($action == '') {

programming_language: PHP
filename: admin_phpsettings.php
change_type: ModificationType.MODIFY
diff: @@ -37,7 +37,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'overview') {
 	if ($action == '') {

programming_language: PHP
filename: admin_plans.php
change_type: ModificationType.MODIFY
diff: @@ -39,7 +39,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == '' || $page == 'overview') {
 	if ($action == '') {
@@ -263,7 +263,7 @@ if ($page == '' || $page == 'overview') {
 			}
 		}
 	} elseif ($action == 'jqGetPlanValues') {
-		$planid = (int)Request::get('planid', 0);
+		$planid = (int)Request::any('planid', 0);
 		try {
 			$json_result = HostingPlans::getLocal($userinfo, [
 				'id' => $planid

programming_language: PHP
filename: admin_settings.php
change_type: ModificationType.MODIFY
diff: @@ -112,7 +112,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
 		if ($_part == '' || $_part == 'all') {
 			UI::view('settings/index.html.twig', ['fields' => $fields]);
 		} else {
-			$em = Request::get('em', '');
+			$em = Request::any('em', '');
 			UI::view('settings/detailpart.html.twig', ['fields' => $fields, 'em' => $em]);
 		}
 	}

programming_language: PHP
filename: admin_templates.php
change_type: ModificationType.MODIFY
diff: @@ -39,9 +39,9 @@ use Froxlor\UI\Response;
 use Froxlor\Validate\Validate;
 use Froxlor\CurrentUser;
 
-$id = (int)Request::get('id');
-$subjectid = intval(Request::get('subjectid'));
-$mailbodyid = intval(Request::get('mailbodyid'));
+$id = (int)Request::any('id');
+$subjectid = intval(Request::any('subjectid'));
+$mailbodyid = intval(Request::any('mailbodyid'));
 
 $available_templates = [
 	'createcustomer',

programming_language: PHP
filename: admin_traffic.php
change_type: ModificationType.MODIFY
diff: @@ -31,7 +31,7 @@ use Froxlor\UI\Panel\UI;
 use Froxlor\UI\Request;
 use Froxlor\UI\Response;
 
-$range = Request::get('range', 'currentmonth');
+$range = Request::any('range', 'currentmonth');
 
 if ($page == 'overview' || $page == 'customers') {
 	try {

programming_language: PHP
filename: api_keys.php
change_type: ModificationType.MODIFY
diff: @@ -49,7 +49,7 @@ if ($userinfo['adminsession'] == 1 && $userinfo['api_allowed'] == 0) {
 // and therefore does not need to require lib/init.php
 
 $del_stmt = Database::prepare("DELETE FROM `" . TABLE_API_KEYS . "` WHERE id = :id");
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 // do the delete and then just show a success-message and the apikeys list again
 if ($action == 'delete' && $id > 0) {

programming_language: PHP
filename: customer_domains.php
change_type: ModificationType.MODIFY
diff: @@ -47,13 +47,13 @@ if (Settings::IsInList('panel.customer_hide_options', 'domains')) {
 	Response::redirectTo('customer_index.php');
 }
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'overview' || $page == 'domains') {
 	if ($action == '') {
 		$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_domains::domains");
 
-		$parentdomain_id = (int)Request::get('pid', '0');
+		$parentdomain_id = (int)Request::any('pid', '0');
 
 		try {
 			$domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.domains.php';

programming_language: PHP
filename: customer_email.php
change_type: ModificationType.MODIFY
diff: @@ -47,7 +47,7 @@ if (Settings::IsInList('panel.customer_hide_options', 'email') || $userinfo['ema
 	Response::redirectTo('customer_index.php');
 }
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'overview' || $page == 'emails') {
 	if ($action == '') {

programming_language: PHP
filename: customer_extras.php
change_type: ModificationType.MODIFY
diff: @@ -46,7 +46,7 @@ if (Settings::IsInList('panel.customer_hide_options', 'extras')) {
 	Response::redirectTo('customer_index.php');
 }
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'overview' || $page == 'htpasswds') {
 	// redirect if this customer sub-page is hidden via settings

programming_language: PHP
filename: customer_ftp.php
change_type: ModificationType.MODIFY
diff: @@ -44,7 +44,7 @@ if (Settings::IsInList('panel.customer_hide_options', 'ftp') || $userinfo['ftps'
 	Response::redirectTo('customer_index.php');
 }
 
-$id = (int)Request::get('id', 0);
+$id = (int)Request::any('id', 0);
 
 if ($page == 'overview' || $page == 'accounts') {
 	if ($action == '') {

programming_language: PHP
filename: customer_mysql.php
change_type: ModificationType.MODIFY
diff: @@ -50,7 +50,7 @@ Database::needSqlData();
 $sql_root = Database::getSqlData();
 Database::needRoot(false);
 
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 if ($page == 'overview' || $page == 'mysqls') {
 	if ($action == '') {

programming_language: PHP
filename: customer_traffic.php
change_type: ModificationType.MODIFY
diff: @@ -37,7 +37,7 @@ if (Settings::IsInList('panel.customer_hide_options', 'traffic')) {
 	Response::redirectTo('customer_index.php');
 }
 
-$range = Request::get('range', 'currentyear');
+$range = Request::any('range', 'currentyear');
 
 if ($page == 'current') {
 	$range = 'currentmonth';

programming_language: PHP
filename: dns_editor.php
change_type: ModificationType.MODIFY
diff: @@ -40,7 +40,7 @@ use Froxlor\UI\Response;
 // This file is being included in admin_domains and customer_domains
 // and therefore does not need to require lib/init.php
 
-$domain_id = (int)Request::get('domain_id');
+$domain_id = (int)Request::any('domain_id');
 
 $record = isset($_POST['dns_record']) ? trim($_POST['dns_record']) : null;
 $type = isset($_POST['dns_type']) ? $_POST['dns_type'] : 'A';

programming_language: PHP
filename: error_report.php
change_type: ModificationType.MODIFY
diff: @@ -37,7 +37,7 @@ use Froxlor\UI\Response;
 // This file is being included in admin_domains and customer_domains
 // and therefore does not need to require lib/init.php
 
-$errid = Request::get('errorid');
+$errid = Request::any('errorid');
 
 if (!empty($errid)) {
 	// read error file

programming_language: PHP
filename: Ajax.php
change_type: ModificationType.MODIFY
diff: @@ -53,8 +53,8 @@ class Ajax
 	 */
 	public function __construct()
 	{
-		$this->action = $_GET['action'] ?? $_POST['action'] ?? null;
-		$this->theme = $_GET['theme'] ?? 'Froxlor';
+		$this->action = Request::any('action');
+		$this->theme = Request::any('theme', 'Froxlor');
 
 		UI::sendHeaders();
 		UI::sendSslHeaders();
@@ -112,7 +112,8 @@ class Ajax
 		$feed = "https://inside.froxlor.org/news/";
 
 		// Set custom feed if provided
-		if (isset($_GET['role']) && $_GET['role'] == "customer") {
+		$role = Request::get('role');
+		if ($role == "customer") {
 			$custom_feed = Settings::Get("customer.news_feed_url");
 			if (!empty(trim($custom_feed))) {
 				$feed = $custom_feed;
@@ -140,7 +141,7 @@ class Ajax
 
 		if ($news === false) {
 			$err = [];
-			foreach(libxml_get_errors() as $error) {
+			foreach (libxml_get_errors() as $error) {
 				$err[] = $error->message;
 			}
 			return $this->errorResponse(
@@ -205,7 +206,7 @@ class Ajax
 		} catch (Exception $e) {
 			// don't display anything if just not allowed due to permissions
 			if ($e->getCode() != 403) {
-				Response::dynamicError($e->getMessage());
+				return $this->errorResponse($e->getMessage(), $e->getCode());
 			}
 		}
 	}
@@ -215,7 +216,7 @@ class Ajax
 	 */
 	private function searchGlobal()
 	{
-		$searchtext = Request::get('searchtext');
+		$searchtext = Request::any('searchtext');
 
 		$result = [];
 
@@ -236,11 +237,11 @@ class Ajax
 	private function updateTablelisting()
 	{
 		$columns = [];
-		foreach ((Request::get('columns') ?? []) as $value) {
+		foreach ((Request::any('columns') ?? []) as $value) {
 			$columns[] = $value;
 		}
 		if (!empty($columns)) {
-			Listing::storeColumnListingForUser([Request::get('listing') => $columns]);
+			Listing::storeColumnListingForUser([Request::any('listing') => $columns]);
 			return $this->jsonResponse($columns);
 		}
 		return $this->errorResponse('At least one column must be selected', 406);
@@ -248,15 +249,15 @@ class Ajax
 
 	private function resetTablelisting()
 	{
-		Listing::deleteColumnListingForUser([Request::get('listing') => []]);
+		Listing::deleteColumnListingForUser([Request::any('listing') => []]);
 		return $this->jsonResponse([]);
 	}
 
 	private function editApiKey()
 	{
-		$keyid = isset($_POST['id']) ? (int)$_POST['id'] : 0;
-		$allowed_from = isset($_POST['allowed_from']) ? $_POST['allowed_from'] : "";
-		$valid_until = isset($_POST['valid_until']) ? $_POST['valid_until'] : "";
+		$keyid = Request::post('id', 0);
+		$allowed_from = Request::post('allowed_from', "");
+		$valid_until = Request::post('valid_until', "");
 
 		if (empty($keyid)) {
 			return $this->errorResponse('Invalid call', 406);
@@ -318,9 +319,9 @@ class Ajax
 	private function getConfigDetails()
 	{
 		if (isset($this->userinfo['adminsession']) && $this->userinfo['adminsession'] == 1 && $this->userinfo['change_serversettings'] == 1) {
-			$distribution = isset($_POST['distro']) ? $_POST['distro'] : "";
-			$section = isset($_POST['section']) ? $_POST['section'] : "";
-			$daemon = isset($_POST['daemon']) ? $_POST['daemon'] : "";
+			$distribution = Request::post('distro', "");
+			$section = Request::post('section', "");
+			$daemon = Request::post('daemon', "");
 
 			// validate distribution config-xml exists
 			$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
@@ -375,7 +376,7 @@ class Ajax
 	 */
 	private function loadLanguageString()
 	{
-		$langid = isset($_POST['langid']) ? $_POST['langid'] : "";
+		$langid = Request::post('langid', "");
 		if (preg_match('/^([a-zA-Z\.]+)$/', $langid)) {
 			return $this->jsonResponse(lng($langid));
 		}

programming_language: PHP
filename: Install.php
change_type: ModificationType.MODIFY
diff: @@ -80,8 +80,8 @@ class Install
 		$this->formfield = require dirname(__DIR__, 3) . '/lib/formfields/install/formfield.install.php';
 
 		// set actual step
-		$this->currentStep = $cliData['step'] ?? Request::get('step', 0);
-		$this->extendedView = $cliData['extended'] ?? Request::get('extended', 0);
+		$this->currentStep = $cliData['step'] ?? Request::any('step', 0);
+		$this->extendedView = $cliData['extended'] ?? Request::any('extended', 0);
 		$this->maxSteps = count($this->formfield['install']['sections']);
 
 		// set actual php version and extensions
@@ -114,7 +114,7 @@ class Install
 	public function handle(): void
 	{
 		// handle form data
-		if (!is_null(Request::get('submit')) && $this->currentStep) {
+		if (!is_null(Request::any('submit')) && $this->currentStep) {
 			try {
 				$this->handleFormData($this->formfield['install']);
 			} catch (Exception $e) {
@@ -266,7 +266,7 @@ class Install
 	{
 		$attributes = [];
 		foreach ($fields as $name => $field) {
-			$attributes[$name] = $this->validateAttribute(Request::get($name), $field);
+			$attributes[$name] = $this->validateAttribute(Request::any($name), $field);
 			if (isset($field['next_to'])) {
 				$attributes = array_merge($attributes, $this->validateRequest($field['next_to']));
 			}

programming_language: PHP
filename: Request.php
change_type: ModificationType.MODIFY
diff: @@ -31,19 +31,47 @@ use voku\helper\AntiXSS;
 class Request
 {
 	/**
-	 * Get key from current request.
+	 * Get key from current $_GET or $_POST request.
 	 *
 	 * @param $key
 	 * @param string|null $default
 	 * @return mixed|string|null
 	 */
-	public static function get($key, string $default = null)
+	public static function any($key, string $default = null)
 	{
 		self::cleanAll();
 
 		return $_GET[$key] ?? $_POST[$key] ?? $default;
 	}
 
+	/**
+	 * Get key from current $_GET request.
+	 *
+	 * @param $key
+	 * @param string|null $default
+	 * @return mixed|string|null
+	 */
+	public static function get($key, string $default = null)
+	{
+		self::cleanAll();
+
+		return $_GET[$key] ?? $default;
+	}
+
+	/**
+	 * Get key from current $_POST request.
+	 *
+	 * @param $key
+	 * @param string|null $default
+	 * @return mixed|string|null
+	 */
+	public static function post($key, string $default = null)
+	{
+		self::cleanAll();
+
+		return $_POST[$key] ?? $default;
+	}
+
 	/**
 	 * Check for xss attempts and clean important globals and
 	 * unsetting every variable registered in $_REQUEST and as variable itself

programming_language: PHP
filename: ajax.php
change_type: ModificationType.MODIFY
diff: @@ -42,5 +42,6 @@ require_once dirname(__DIR__) . '/lib/tables.inc.php';
 try {
 	echo (new Ajax)->handle();
 } catch (Exception $e) {
+	header("Content-Type: application/json");
 	echo \Froxlor\Api\Response::jsonErrorResponse($e->getMessage(), 500);
 }

programming_language: PHP
filename: functions.php
change_type: ModificationType.MODIFY
diff: @@ -43,5 +43,5 @@ function old(string $identifier, string $default = null, string $session = null)
 	if ($session && isset($_SESSION[$session])) {
 		return $_SESSION[$session][$identifier] ?? $default;
 	}
-	return Request::get($identifier, $default);
+	return Request::any($identifier, $default);
 }

programming_language: PHP
filename: init.php
change_type: ModificationType.MODIFY
diff: @@ -295,9 +295,9 @@ UI::twig()->addGlobal('theme_css', $css);
 unset($js);
 unset($css);
 
-$action = Request::get('action');
-$page = Request::get('page', 'overview');
-$gSearchText = Request::get('searchtext');
+$action = Request::any('action');
+$page = Request::any('page', 'overview');
+$gSearchText = Request::any('searchtext');
 
 // clear request data
 if (!$action && isset($_SESSION)) {

programming_language: PHP
filename: logfiles_viewer.php
change_type: ModificationType.MODIFY
diff: @@ -39,8 +39,8 @@ use Froxlor\UI\Response;
 // This file is being included in admin_domains and customer_domains
 // and therefore does not need to require lib/init.php
 
-$domain_id = (int)Request::get('domain_id');
-$last_n = (int)Request::get('number_of_lines', 100);
+$domain_id = (int)Request::any('domain_id');
+$last_n = (int)Request::any('number_of_lines', 100);
 
 // user's with logviewenabled = false
 if (AREA != 'admin' && $userinfo['logviewenabled'] != '1') {

programming_language: PHP
filename: ssl_certificates.php
change_type: ModificationType.MODIFY
diff: @@ -43,7 +43,7 @@ use Froxlor\UI\Response;
 // and therefore does not need to require lib/init.php
 
 $success_message = "";
-$id = (int)Request::get('id');
+$id = (int)Request::any('id');
 
 // do the delete and then just show a success-message and the certificates list again
 if ($action == 'delete') {

programming_language: PHP