lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ