Fixed a remote code execution issue in the validate binary path (CVE-2024-3116). #7326

pull/7331/head
Khushboo Vashi 2024-04-01 11:34:01 +05:30 committed by Akshay Joshi
parent 26b279cc8a
commit fbbbfe22dd
7 changed files with 59 additions and 10 deletions

View File

@ -50,4 +50,4 @@ Bug fixes
| `Issue #7305 <https://github.com/pgadmin-org/pgadmin4/issues/7305>`_ - Fix an issue in query tool where custom keyboard shortcuts are not working for some.
| `Issue #7304 <https://github.com/pgadmin-org/pgadmin4/issues/7304>`_ - Fixed the issue where the update-user CLI command doesn't change the password.
| `Issue #7308 <https://github.com/pgadmin-org/pgadmin4/issues/7308>`_ - Fixed issue related to email authentication of Two-factor authentication.
| `Issue #7326 <https://github.com/pgadmin-org/pgadmin4/issues/7326>`_ - Fixed a remote code execution issue in the validate binary path (CVE-2024-3116).

View File

@ -469,6 +469,26 @@ DEFAULT_BINARY_PATHS = {
"ppas-16": ""
}
##########################################################################
# Admin can specify fixed binary paths to prevent users from changing.
# It will take precedence over DEFAULT_BINARY_PATHS.
FIXED_BINARY_PATHS = {
"pg": "",
"pg-12": "",
"pg-13": "",
"pg-14": "",
"pg-15": "",
"pg-16": "",
"ppas": "",
"ppas-12": "",
"ppas-13": "",
"ppas-14": "",
"ppas-15": "",
"ppas-16": ""
}
##########################################################################
# Test settings - used primarily by the regression suite, not for users
##########################################################################

View File

@ -49,6 +49,10 @@ export default class BinaryPathSchema extends BaseUISchema {
{
id: 'binaryPath', label: gettext('Binary Path'), cell: 'file', type: 'file',
isvalidate: true,
disabled: function (state) {
// If Fixed path is assigned, user will not able to edit it.
return state?.isFixed ? state.isFixed : false;
},
controlProps: {
dialogType: 'select_folder',
supportedTypes: ['*', 'sql', 'backup'],

View File

@ -11,7 +11,6 @@ import os
import json
import config
import copy
from flask import render_template
from flask_babel import gettext as _
from pgadmin.utils.preferences import Preferences
@ -240,15 +239,22 @@ class ServerType():
"""
is_default_path_set = ServerType.is_default_binary_path_set(bin_paths)
for path in config.DEFAULT_BINARY_PATHS:
path_value = config.DEFAULT_BINARY_PATHS[path]
is_fixed_path = (path in config.FIXED_BINARY_PATHS and
config.FIXED_BINARY_PATHS[path] != '' and
config.FIXED_BINARY_PATHS[path] is not None)
path_value = (is_fixed_path and config.FIXED_BINARY_PATHS[path]
) or config.DEFAULT_BINARY_PATHS[path]
if path_value is not None and path_value != "" and \
path.find(server_type) == 0 and len(path.split('-')) > 1:
set_binary_path(path_value, bin_paths, server_type,
path.split('-')[1])
set_binary_path(
path_value, bin_paths, server_type, path.split('-')[1],
is_fixed_path=is_fixed_path)
elif path_value is not None and path_value != "" and \
path.find(server_type) == 0:
set_binary_path(path_value, bin_paths, server_type,
set_as_default=not is_default_path_set)
set_as_default=not is_default_path_set,
is_fixed_path=is_fixed_path)
# Default Server Type

View File

@ -62,6 +62,8 @@ define('pgadmin.browser.utils',
/* GET Binary Path Browse config */
pgAdmin['enable_binary_path_browsing'] = '{{ current_app.config.get('ENABLE_BINARY_PATH_BROWSING') }}' == 'True';
pgAdmin['fixed_binary_paths'] = {{ current_app.config.get('FIXED_BINARY_PATHS') }};
/* GET the pgadmin server's locale */
pgAdmin['pgadmin_server_locale'] = '{{pgadmin_server_locale}}';

View File

@ -14,6 +14,7 @@ from flask import render_template, Response, request, current_app
from flask.helpers import url_for
from flask_babel import gettext
from flask_security import login_required
from pathlib import Path
from pgadmin.utils import PgAdminModule, replace_binary_path, \
get_binary_path_versions
from pgadmin.utils.csrf import pgCSRFProtect
@ -234,7 +235,11 @@ def validate_binary_path():
data = json.loads(data)
version_str = ''
if 'utility_path' in data and data['utility_path'] is not None:
# Do not allow storage dir as utility path
if 'utility_path' in data and data['utility_path'] is not None and \
Path(config.STORAGE_DIR) != Path(data['utility_path']) and \
Path(config.STORAGE_DIR) not in Path(data['utility_path']).parents:
binary_versions = get_binary_path_versions(data['utility_path'])
for utility, version in binary_versions.items():
if version is None:
@ -248,7 +253,8 @@ def validate_binary_path():
return make_json_response(data=gettext(version_str), status=200)
@blueprint.route("/upgrade_check", endpoint="upgrade_check", methods=['GET'])
@blueprint.route("/upgrade_check", endpoint="upgrade_check",
methods=['GET'])
@login_required
def upgrade_check():
# Get the current version info from the website, and flash a message if

View File

@ -14,13 +14,14 @@ import subprocess
from collections import defaultdict
from operator import attrgetter
from pathlib import Path
from flask import Blueprint, current_app, url_for
from flask_babel import gettext
from flask_security import current_user, login_required
from flask_security.utils import get_post_login_redirect, \
get_post_logout_redirect
from threading import Lock
import config
from .paths import get_storage_directory
from .preferences import Preferences
from pgadmin.utils.constants import UTILITIES_ARRAY, USER_NOT_FOUND, \
@ -308,11 +309,18 @@ def does_utility_exist(file):
:return:
"""
error_msg = None
if file is None:
error_msg = gettext("Utility file not found. Please correct the Binary"
" Path in the Preferences dialog")
return error_msg
if Path(config.STORAGE_DIR) == Path(file) or \
Path(config.STORAGE_DIR) in Path(file).parents:
error_msg = gettext("Please correct the Binary Path in the Preferences"
" dialog. pgAdmin storage directory can not be a"
" utility binary directory.")
if not os.path.exists(file):
error_msg = gettext("'%s' file not found. Please correct the Binary"
" Path in the Preferences dialog" % file)
@ -364,7 +372,8 @@ def get_binary_path_versions(binary_path: str) -> dict:
def set_binary_path(binary_path, bin_paths, server_type,
version_number=None, set_as_default=False):
version_number=None, set_as_default=False,
is_fixed_path=False):
"""
This function is used to iterate through the utilities and set the
default binary path.
@ -394,6 +403,8 @@ def set_binary_path(binary_path, bin_paths, server_type,
if path_with_dir is not None else binary_path
if set_as_default:
path['isDefault'] = True
# Whether the fixed path in the config file exists or not
path['isFixed'] = is_fixed_path
break
break
except Exception: