The security fix for CVE-2024-48991, 6ce6136 (“core: prevent race condition on /proc/$PID/exec evaluation”) [0], introduced a regression which was subsequently fixed 42af5d3 ("core: fix regression of false positives for processes running in chroot or mountns (#317)") [1]. Many thanks to Ivan Kurnosov and Salvatore Bonaccorso for their review. [0] https://github.com/liske/needrestart/commit/6ce6136cccc307c6b8a0f8cae12f9a22ac2aad59 [1] https://github.com/liske/needrestart/commit/42af5d328901287a4f79d1f5861ac827a53fd56d On Tue, Nov 19, 2024 at 04:28:37PM +0000, Qualys Security Advisory via Fulldisclosure wrote: > > Qualys Security Advisory > > LPEs in needrestart (CVE-2024-48990, CVE-2024-48991, CVE-2024-48992, > CVE-2024-10224, and CVE-2024-11003) > > > ======================================================================== > Contents > ======================================================================== > > Summary > Background > CVE-2024-48990 (and CVE-2024-48992) > CVE-2024-48991 > CVE-2024-10224 (and CVE-2024-11003) > Mitigation > Acknowledgments > Timeline > > I got bugs > I got bugs in my room > Bugs in my bed > Bugs in my ears > Their eggs in my head > -- Pearl Jam, "Bugs" > > > ======================================================================== > Summary > ======================================================================== > > needrestart (from https://github.com/liske/needrestart) is a Perl tool > that is installed by default on Ubuntu Server since version 21.04. From > https://discourse.ubuntu.com/t/needrestart-changes-in-ubuntu-24-04-service-restarts: > > ------------------------------------------------------------------------ > What is needrestart, exactly? > > needrestart is a tool that probes your system to see if either the > system itself or some of its services should be restarted. That last > part is the one of interest in this document. Notably, a service is > considered as needing to be restarted if one of its processes is using > a shared library whose initial file isn't on the system anymore (for > instance, if it has been overwritten by a new version as part of a > package update). > > We ship this tool in our server images, and it is configured by > default to run at the end of APT transactions, e.g. when doing apt > install/upgrade/remove or during unattended-upgrades. > ------------------------------------------------------------------------ > > We discovered three fundamental vulnerabilities in needrestart (three > LPEs, Local Privilege Escalations, from any unprivileged user to full > root), which are exploitable without user interaction on Ubuntu Server > (through unattended-upgrades): > > - CVE-2024-48990: local attackers can execute arbitrary code as root by > tricking needrestart into running the Python interpreter with an > attacker-controlled PYTHONPATH environment variable. > > Last-minute update: an additional CVE, CVE-2024-48992, has been > assigned to needrestart because local attackers can also execute > arbitrary code as root by tricking needrestart into running the Ruby > interpreter with an attacker-controlled RUBYLIB environment variable. > > - CVE-2024-48991: local attackers can execute arbitrary code as root by > winning a race condition and tricking needrestart into running their > own, fake Python interpreter (instead of the system's real Python > interpreter). > > - CVE-2024-10224: local attackers can execute arbitrary shell commands > as root by tricking needrestart into open()ing a filename of the form > "commands|" (technically, this vulnerability is in Perl's ScanDeps > module, but it is unclear whether this module was ever meant to > operate on attacker-controlled files or not). > > Last-minute update: in the end, an additional CVE, CVE-2024-11003, has > been assigned to needrestart for calling Perl's ScanDeps module with > attacker-controlled files. > > To the best of our knowledge, these vulnerabilities have existed since > the introduction of interpreter support in needrestart 0.8 (April 2014). > From https://github.com/liske/needrestart#interpreters: > > ------------------------------------------------------------------------ > needrestart 0.8 brings an interpreter scanning feature. Interpreters > not only map binary (shared) objects but also use plaintext source > files. The interpreter detection tries to check for outdated source > files since they may contain security issues, too. This is only a > heuristic and might fail to detect all relevant source files. The > following interpreter scanners are shipped: > > - NeedRestart::Interp::Java > - NeedRestart::Interp::Perl > - NeedRestart::Interp::Python > - NeedRestart::Interp::Ruby > ------------------------------------------------------------------------ > > We will not publish our exploits for now; however, please note that > these vulnerabilities are trivially exploitable, and other researchers > might publish working exploits shortly after this coordinated release. > > > ======================================================================== > Background > ======================================================================== > > And now the questions: > Do I kill them? > Become their friend? > Do I eat them? > -- Pearl Jam, "Bugs" > > While idly watching an "apt-get upgrade" of one of our Ubuntu Servers, > we noticed a message that we had never noticed before: "Scanning > processes..." > > We immediately wondered: What is printing this message? Is it scanning > userland processes? As root? Even processes that do not belong to root? > > We quickly found out that this message is printed by needrestart, a tool > that scans the userland for processes that need to be restarted after a > package installation, upgrade, or removal. Naturally, needrestart scans > all userland processes as root, including unprivileged user processes; > i.e., possibly attacker-controlled processes. > > > ======================================================================== > CVE-2024-48990 (and CVE-2024-48992) > ======================================================================== > > To determine whether a Python process (a process that is running the > Python interpreter) needs to be restarted, needrestart extracts the > PYTHONPATH environment variable from this process's /proc/pid/environ > (at line 193), sets this environment variable if it exists (at line > 196), and executes Python ("$ptable->{exec}" at line 203) with a "-" > argument to read a short, hard-coded script from stdin (at line 204): > > ------------------------------------------------------------------------ > 135 sub files { > 136 my $self = shift; > 137 my $pid = shift; > 138 my $cache = shift; > 139 my $ptable = nr_ptable_pid($pid); > ... > 193 my %e = nr_parse_env($pid); > 194 local %ENV; > 195 if(exists($e{PYTHONPATH})) { > 196 $ENV{PYTHONPATH} = $e{PYTHONPATH}; > 197 } > ... > 203 my ($pyread, $pywrite) = nr_fork_pipe2($self->{debug}, > $ptable->{exec}, '-'); > 204 print $pywrite "import sys\nprint(sys.path)\n"; > 205 close($pywrite); > ------------------------------------------------------------------------ > > Unfortunately, if a Python process belongs to a local attacker, then > needrestart executes Python (at line 203) with an attacker-controlled > PYTHONPATH environment variable, which allows the attacker to execute > arbitrary code as root (even though needrestart's hard-coded Python > script at line 204 is not attacker-controlled at all). This is > CVE-2024-48990. > > For example, in our exploit we run a simple Python process (which > sleep()s forever) with a "PYTHONPATH=/home/jane" environment variable, > and plant a shared library "importlib/__init__.so" in our /home/jane. > As soon as needrestart executes Python with our PYTHONPATH environment > variable (at line 203), our shared library is executed (by Python's > initialization code) and creates a SUID-root shell in /home/jane. > > Note: needrestart's support code for the Ruby interpreter seems equally > vulnerable, but we have not investigated this any further, because > (unlike Python) Ruby is not installed by default on Ubuntu Server. > > Last-minute update: we have now confirmed that needrestart's support > code for the Ruby interpreter is indeed vulnerable and exploitable, > through an attacker-controlled RUBYLIB environment variable and an > "enc/encdb.so" shared library. This is CVE-2024-48992. > > > ======================================================================== > CVE-2024-48991 > ======================================================================== > > To determine whether a process is indeed a Python process (a process > that is running the Python interpreter, for example /usr/bin/python3), > needrestart reads this process's /proc/pid/exe (at line 520), and then > matches it against the regular expression at line 45: > > ------------------------------------------------------------------------ > 520 my $exe = nr_readlink($pid); > ... > 606 $restart++ if(needrestart_interp_check($nrconf{verbosity} > > 1, $pid, $exe, $nrconf{blacklist_interp}, $opt_t)); > ------------------------------------------------------------------------ > 166 sub needrestart_interp_check($$$$$) { > 167 my $debug = shift; > 168 my $pid = shift; > 169 my $bin = shift; > 170 my $blacklist = shift; > 171 my $tolerance = shift; > ... > 176 if($interp->isa($pid, $bin)) { > ------------------------------------------------------------------------ > 40 sub isa { > 41 my $self = shift; > 42 my $pid = shift; > 43 my $bin = shift; > 44 > 45 return 1 if($bin =~ m@^/usr/(local/)?bin/python([23][.\d]*)?$@); > 46 > 47 return 0; > 48 } > ------------------------------------------------------------------------ > > In fact, this code used to be vulnerable to CVE-2022-30688, a Local > Privilege Escalation reported by Jakub Wilk: the regular expression at > line 45 used to be unanchored (i.e., "/usr/(local/)?bin/python" instead > of "^/usr/(local/)?bin/python([23][.\d]*)?$"), so local attackers could > simply run their own, fake "/home/jane/usr/bin/python" (for example) and > needrestart would later execute this fake Python interpreter as root (as > if it were the system's real Python interpreter, at line 203). > > We tried to bypass the fixed, anchored regular expression at line 45, > but we failed. However, we eventually realized that the filename that is > checked at line 45 is not necessarily the same filename that is executed > at line 203: the filename that is checked is read from /proc/pid/exe in > the middle of needrestart's main loop (at line 520), but the filename > that is executed ("$ptable->{exec}" at line 203) was first read from > /proc/pid/exe long before needrestart entered its main loop. > > In other words, needrestart is vulnerable to a TOCTOU race condition > (time-of-check, time-of-use). For example, our exploit /home/jane/race > waits for needrestart to read our /proc/pid/exe for the first time (we > use inotify to reliably win this race), and then quickly execve()s the > system's real Python interpreter with a script that simply sleep()s for > some time. As a result, needrestart does its checks on the real Python > interpreter, but executes our own /home/jane/race instead, as root. > > Note: needrestart's support code for the Ruby interpreter seems equally > vulnerable, but we have not investigated this any further. > > > ======================================================================== > CVE-2024-10224 (and CVE-2024-11003) > ======================================================================== > > After we had discovered CVE-2024-48990 and CVE-2024-48991 in > needrestart's support code for the Python interpreter (and Ruby), we > began to wonder whether the support code for the Perl interpreter might > also be vulnerable to a Local Privilege Escalation. > > Unlike needrestart's support code for Python and Ruby, the support code > for Perl does not execute the Perl interpreter itself: instead, it calls > the scan_deps() function from Perl's ScanDeps module, which analyzes a > Perl script by recursively reading its source files. > > We therefore grepped the ScanDeps module for one of the oldest pitfalls > of the Perl programming language: the two-argument form of open(), which > allows attackers to execute arbitrary shell commands if they control the > name of the file to be open()ed (for example, "commands|"). For more > information, please refer to rain.forest.puppy's 1999 Phrack article > ("That pesky pipe" section) and the SEI CERT Perl Coding Standard: > > https://phrack.org/issues/55/7.html#article > https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88890543 > > Incredibly, we found a match, at line 871 in ScanDeps.pm: > > ------------------------------------------------------------------------ > 868 sub scan_file{ > 869 my $file = shift; > 870 my %found; > 871 open my $fh, $file or die "Cannot open $file: $!"; > ------------------------------------------------------------------------ > > In our exploit, we simply run a Perl script named "/home/jane/perl|" > (which sleep()s forever), and as soon as needrestart calls scan_deps() > to analyze our script, "/home/jane/perl|" is open()ed (at line 871), but > because this filename ends with a "|" it is treated as a shell command, > and our own "/home/jane/perl" is executed instead, as root. > > Last-minute update: while reviewing needrestart's patches for these > vulnerabilities, we have discovered that Perl's ScanDeps module is also > trivially exploitable through various calls to eval() ("string" eval()s, > https://perldoc.perl.org/functions/eval). Consequently and impressively, > in response to our advisory: > > - all of ScanDeps's vulnerable calls to open() and eval() have been > patched, thus fixing CVE-2024-10224; > > - needrestart's dependence on ScanDeps has been completely removed (it > uses a simple regex-based approach now), thus fixing CVE-2024-11003. > > > ======================================================================== > Mitigation > ======================================================================== > > As already recommended by needrestart's advisory for CVE-2022-30688 > (from https://www.openwall.com/lists/oss-security/2022/05/17/9): > > ------------------------------------------------------------------------ > Disabling the interpreter heuristic in needrestart's config prevents > this attack: > > # Disable interpreter scanners. > $nrconf{interpscan} = 0; > ------------------------------------------------------------------------ > > > ======================================================================== > Acknowledgments > ======================================================================== > > We thank needrestart's maintainer (Thomas Liske), Module::ScanDeps's > maintainers (Roderich Schupp in particular), the Ubuntu Security Team > (Mark Esler in particular), and distros@openwall (Salvatore Bonaccorso > from the Debian Security Team in particular) for their outstanding work; > it has been a real pleasure to collaborate on this coordinated release. > > We also thank Adam Boileau (@metlstorm) and Rodrigo Branco (@bsdaemon) > for their very kind words about our work; they mean the world to us: > > https://risky.biz/RB755/ > https://phrack.org/issues/71/2.html#article > > > ======================================================================== > Timeline > ======================================================================== > > 2024-10-04: We sent our advisory and exploits to the Ubuntu Security > Team, and asked them if they could help us to coordinate this disclosure > with the upstream projects and distros@openwall; they gladly accepted. > > 2024-10-08: The Ubuntu Security Team sent our advisory and exploits to > needrestart's maintainer; we then started a very constructive exchange > of patches and patch reviews. > > 2024-10-18: The Ubuntu Security Team opened GHSA-g597-359q-v529, a > private GitHub repository to collaborate on this disclosure with > Module::ScanDeps's maintainers. > > 2024-11-11: The Ubuntu Security Team sent our advisory and all of > needrestart's and Module::ScanDeps's patches to distros@openwall. > > 2024-11-19: Coordinated Release Date (16:00 UTC). > _______________________________________________ > Sent through the Full Disclosure mailing list > https://nmap.org/mailman/listinfo/fulldisclosure > Web Archives & RSS: https://seclists.org/fulldisclosure/
Attachment:
signature.asc
Description: PGP signature
_______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/