[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <Z0YwQ_MBhm3nV8IS@aeon>
Date: Tue, 26 Nov 2024 12:32:03 -0800
From: Mark Esler <mark.esler@...onical.com>
To: fulldisclosure@...lists.org
Subject: Re: [FD] Local Privilege Escalations in needrestart
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@...sr/(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@...nwall (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@...nwall; 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@...nwall.
>
> 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/
Download attachment "signature.asc" of type "application/pgp-signature" (834 bytes)
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Powered by blists - more mailing lists