Unsafe Deserialization and Remote Code Execution by an Authenticated user in pgAdmin 4 (CVE-2024-2044).

This commit is contained in:
Akshay Joshi 2024-03-04 13:22:09 +05:30
parent 0cbb5324bf
commit 4e49d752fb
2 changed files with 20 additions and 10 deletions

View File

@ -43,3 +43,4 @@ Bug fixes
| `Issue #7193 <https://github.com/pgadmin-org/pgadmin4/issues/7193>`_ - Ensure that the OAuth2 session is logged out when users log out from pgAdmin. | `Issue #7193 <https://github.com/pgadmin-org/pgadmin4/issues/7193>`_ - Ensure that the OAuth2 session is logged out when users log out from pgAdmin.
| `Issue #7217 <https://github.com/pgadmin-org/pgadmin4/issues/7217>`_ - Remove role related checks on the UI dashboard when terminating session/query and let PostgreSQL take care of it. | `Issue #7217 <https://github.com/pgadmin-org/pgadmin4/issues/7217>`_ - Remove role related checks on the UI dashboard when terminating session/query and let PostgreSQL take care of it.
| `Issue #7225 <https://github.com/pgadmin-org/pgadmin4/issues/7225>`_ - Fix an issue where type column in dependents/dependencies tab is not showing correct label. | `Issue #7225 <https://github.com/pgadmin-org/pgadmin4/issues/7225>`_ - Fix an issue where type column in dependents/dependencies tab is not showing correct label.
| `Issue #7258 <https://github.com/pgadmin-org/pgadmin4/issues/7258>`_ - Unsafe Deserialization and Remote Code Execution by an Authenticated user in pgAdmin 4 (CVE-2024-2044).

View File

@ -34,6 +34,8 @@ from collections import OrderedDict
from flask.sessions import SessionInterface, SessionMixin from flask.sessions import SessionInterface, SessionMixin
from werkzeug.datastructures import CallbackDict from werkzeug.datastructures import CallbackDict
from werkzeug.security import safe_join
from werkzeug.exceptions import InternalServerError
from pgadmin.utils.ajax import make_json_response from pgadmin.utils.ajax import make_json_response
@ -192,27 +194,30 @@ class FileBackedSessionManager(SessionManager):
self.skip_paths = [] if skip_paths is None else skip_paths self.skip_paths = [] if skip_paths is None else skip_paths
def exists(self, sid): def exists(self, sid):
fname = os.path.join(self.path, sid) fname = safe_join(self.path, sid)
return os.path.exists(fname) return fname is not None and os.path.exists(fname)
def remove(self, sid): def remove(self, sid):
fname = os.path.join(self.path, sid) fname = safe_join(self.path, sid)
if os.path.exists(fname): if fname is not None and os.path.exists(fname):
os.unlink(fname) os.unlink(fname)
def new_session(self): def new_session(self):
sid = str(uuid4()) sid = str(uuid4())
fname = os.path.join(self.path, sid) fname = safe_join(self.path, sid)
while os.path.exists(fname): while fname is not None and os.path.exists(fname):
sid = str(uuid4()) sid = str(uuid4())
fname = os.path.join(self.path, sid) fname = safe_join(self.path, sid)
# Do not store the session if skip paths # Do not store the session if skip paths
for sp in self.skip_paths: for sp in self.skip_paths:
if request.path.startswith(sp): if request.path.startswith(sp):
return ManagedSession(sid=sid) return ManagedSession(sid=sid)
if fname is None:
raise InternalServerError('Failed to create new session')
# touch the file # touch the file
with open(fname, 'wb'): with open(fname, 'wb'):
return ManagedSession(sid=sid) return ManagedSession(sid=sid)
@ -222,12 +227,12 @@ class FileBackedSessionManager(SessionManager):
def get(self, sid, digest): def get(self, sid, digest):
'Retrieve a managed session by session-id, checking the HMAC digest' 'Retrieve a managed session by session-id, checking the HMAC digest'
fname = os.path.join(self.path, sid) fname = safe_join(self.path, sid)
data = None data = None
hmac_digest = None hmac_digest = None
randval = None randval = None
if os.path.exists(fname): if fname is not None and os.path.exists(fname):
try: try:
with open(fname, 'rb') as f: with open(fname, 'rb') as f:
randval, hmac_digest, data = load(f) randval, hmac_digest, data = load(f)
@ -266,7 +271,11 @@ class FileBackedSessionManager(SessionManager):
if request.path.startswith(sp): if request.path.startswith(sp):
return return
fname = os.path.join(self.path, session.sid) fname = safe_join(self.path, session.sid)
if fname is None:
raise InternalServerError('Failed to update the session')
with open(fname, 'wb') as f: with open(fname, 'wb') as f:
dump( dump(
(session.randval, session.hmac_digest, dict(session)), (session.randval, session.hmac_digest, dict(session)),