gnome-remote-desktop: D-Bus system service in GNOME release 46 (CVE-2024-5148)
#CVE #local #D-BusTable of Contents
- Introduction
- Review Motivation and Scope
- A) Unauthenticated Handover D-Bus Interface (CVE-2024-5148)
- B)
find_cr_lf()
Suffers from a one Byte Overread - C)
grdctl
Utility Accepts Cleartext Password on the Command Line - Timeline
- References
Introduction
gnome-remote-desktop offers access to the graphics system either via the VNC or the RDP (Microsoft remote desktop) network protocol. Before version 46, gnome-remote-desktop was only used in the context of existing graphical user sessions. Starting with version 46, one can also configure a system daemon, that allows to connect to the GNOME display manager (GDM), allowing to create graphical sessions remotely.
The system daemon runs as a dedicated “gnome-remote-desktop” user. It provides a D-Bus interface on the D-Bus system bus. The daemon also interacts with a newly introduced D-Bus interface provided by GDM, to create remote displays.
While reviewing the new system service I found a number of local security issues and areas for security improvement. The more relevant issues are discussed in this report, while an upstream Gitlab issue contains a more detailed report and discussions also covering less severe aspects found during the review.
This report relates to gnome-remote-desktop release 46.0. Bugfixes for the issues described are found in release 46.2, except for item C) for which no fix is available yet.
Review Motivation and Scope
D-Bus system services require a review by the SUSE security team, before they can be added to openSUSE distributions and derived products. With the addition of the system daemon, a review of gnome-remote-desktop became necessary, before adding it to openSUSE Tumbleweed in the context of the larger GNOME 46 release.
The review was mainly concerned with the newly introduced system level gnome-remote-desktop daemon. The focus was furthermore on code paths related to the RDP protocol, which is the default and preferred over the VNC protocol.
Since the codebase of gnome-remote-desktop is rather large, I focused the review on the security of the D-Bus methods, the Polkit authentication and parts of the network processing. I also did not look closely into the FreeRDP library, which is used by gnome-remote-desktop for processing the majority of the RDP protocol.
A) Unauthenticated Handover D-Bus Interface (CVE-2024-5148)
Only the “org.gnome.RemoteDesktop.Rdp.Server” D-Bus interface is
protected by Polkit. auth_admin
authorization is required on this
interface for all methods. The other two interfaces “Dispatcher” and
“Handover” are not authorized and are accessible to all local users in
the system. This leads to a number of local security issues described in
the following subsections.
Local Private Key Leak
The system daemon keeps public SSL certificates and their corresponding private keys in “/var/lib/gnome-remote-desktop/.local/share/gnome-remote-desktop/certificates”. Access to the service’s home directory in “/var/lib/gnome-remote-desktop” is restricted to the service user “gnome-remote-desktop”, mode 0700.
Through the “org.gnome.RemoteDesktop.Rdp.Handover” D-Bus interface any
local user can intercept the private SSL key, though. The private key is
returned from the StartHandover
D-Bus function. When a remote desktop
client connects to the system daemon, then there is a rather long time
window, during which any local user (even nobody
) can call this method on
the created session object. This is an example call to achieve this:
gdbus call -y -d org.gnome.RemoteDesktop -o /org/gnome/RemoteDesktop/Rdp/Handovers/sessionc11 \
-m org.gnome.RemoteDesktop.Rdp.Handover.StartHandover someuser somepass
The username and password parameters are not important here, they will only be forwarded to the connecting client. Doing this, as another effect, also results in a denial-of-service, because the proper connection handover will be prevented.
A local attacker does not necessarily have to wait for somebody to connect to the system daemon, it can connect on its own via localhost, to achieve the same result. Valid credentials for RDP authentication are necessary to get to the handover stage, however.
The impact of this problem is a local information leak and local DoS. The information leak means that the integrity and privacy of RDP connections on the system are compromised. This simple Python script allows to reproduce the issue.
System Credentials Leak
If an RDP connection uses shared system credentials (see struct member
GrdRemoteClient.use_system_credentials
), then a local attacker with
low privileges can obtain these credentials in cleartext in a similar
fashion to the private key leak, by calling the unauthenticated
GetSystemCredentials()
D-Bus method of the Handover interface.
Using these system credentials, the attacker will be able to connect to the display manager via RDP. This should not directly grant access to a session, since a login on display manager level still has to happen. An exception would be if things like automatic login are enabled (I don’t know whether they apply to remote connections).
The Socket Connection can be Obtained via TakeClient()
The equally unauthenticated D-Bus method Handover.TakeClient()
allows
any local user in the system to obtain the file descriptor pertaining to
the RDP client that is in handover state. This could allow a local user
to perform a denial-of-service of the RDP connection or to setup a crafted RDP
session.
Obtaining the socket via this call only works in certain system daemon
states, most notably it seems the StartHandover()
needs to have been
performed for this to succeed. I did not fully investigate what the
exact preconditions are.
Bugfix and Affectedness
This CVE only affects gnome-remote-desktop releases 46.0 and 46.1, since the system daemon was only introduced in these versions. The bugfix is available starting from version 46.2 and is found in commit 9fbaae1a.
With the bugfix applied, only the user for whom a new session has been created will be able to call the handover interface anymore. This still means that all users with RDP access share the same private key, which, according to upstream, is by protocol design.
B) find_cr_lf()
Suffers from a one Byte Overread
This function processes untrusted pre-authentication RDP protocol
network data (the routing token) and looks for a terminating \r\n
sequence. The size calculation in the function’s for loop is wrong: if
the final byte of the buffer is 0x0D, then the logic will access the
next byte out of bounds. This buffer is not null terminated.
The impact should be negligible in most cases. This is the output of Valgrind I obtained after sending a crafted packet to the daemon:
==31119== Invalid read of size 1
==31119== at 0x15A1EF: UnknownInlinedFun (grd-rdp-routing-token.c:65)
==31119== by 0x15A1EF: UnknownInlinedFun (grd-rdp-routing-token.c:159)
==31119== by 0x15A1EF: UnknownInlinedFun (grd-rdp-routing-token.c:239)
==31119== by 0x15A1EF: peek_routing_token_in_thread (grd-rdp-routing-token.c:281)
<snip>
Bugfix
The bugfix is found starting in release 46.2 in commit 663ad63172.
C) grdctl
Utility Accepts Cleartext Password on the Command Line
The text-based grdctl
configuration utility, which is used for both,
system and session context RDP setups, accepts cleartext passwords in
the following invocation styles:
grdctl [--system] rdp set-credentials <username> <password>
grdctl [--system] vnc set-password <username> <password>
This means that the cleartext password will leak via the /proc file
system and will be visible in the process task list via ps
, when
configured this way. Other users can thus get access to the
authentication data.
Bugfix
Upstream declined assignment of a CVE for this issue. They consider the shared credentials to be of rather low sensitivity and state that other ways exist for users to set the credentials, that don’t leak information to other users (GNOME Control Center, the D-Bus API, writing the credentials file directly). A feature request to allow reading the password via stdin has been added to an existing Gitlab issue.
Timeline
2024-04-19 | I reported the issues and other recommendations and remarks via a private issue in the upstream Gitlab, offering coordinated disclosure. |
2024-04-22 | Upstream decided to handle all findings except for the unauthenticated Handover D-Bus methods publicly. No formal coordinated release date was established for the remaining private issue. |
2024-04-26 | I requested a CVE from Mitre to track the unauthenticated Handover D-Bus methods issue described in section A). |
2024-05-13 | After Mitre did not assign a CVE for weeks, it was agreed that upstream would request a CVE from RedHat instead. |
2024-05-20 | Upstream received CVE-2024-5148 to track the unauthenticated Handover D-Bus methods issue. |
2024-05-21 | After asking for the expected time frame for publication of the remaining private issue, upstream decided to publish right away. |