oss-sec mailing list archives
Re: Telnetd Vulnerability Report
From: Ron Ben Yizhak <ron.benyizhak () safebreach com>
Date: Tue, 24 Feb 2026 11:57:34 +0200
Hi all, I’d like to ensure we follow the standard CVE process here. Standard practice dictates that a CVE is issued per individual fix. Generally, once a fix is merged and released, it is assigned its own CVE. Even if that fix is later bypassed, the original merge stands as a unique event in the codebase, meaning we should issue two separate CVEs rather than grouping them. Justin - Thank you for emphasizing what I already noted previously in this thread: "In my opinion the proposed fix will stop this exploit, but the main issue stays. The issue exists as long as unauthenticated clients can set arbitrary environment variables in the memory of telnetd and its sub processes. The best solution will be that the environment variables set by the client will only apply on the shell process and only after the client has already authenticated. No process running as root should run with any environment variables set by the client." In spite of this opinion, it seems that the decision of the developers was to first release something quick that will as least start by mitigating the specific exploit that I shared, even though the main issue remains. I guess that a concrete exploit that utilizes different environment variables might change the prioritization for implementing an "AcceptEnv-like" logic in GNU telnetd, but they might choose to just unset the environment variables that you find as exploitable. Best regards, Ron Ben Yizhak On Tue, Feb 24, 2026 at 3:16 AM Justin Swartz < justin.swartz () risingedge co za> wrote:
Greetings,
I have been reviewing the recent vulnerability report by Ron Ben Yizhak
regarding CREDENTIALS_DIRECTORY, as well as commit 4db2f19f which
introduces unsetenv("CREDENTIALS_DIRECTORY") to address the problem.
After becoming aware of CVE-2026-24061 (telnetd in GNU Inetutils through
2.7 allows remote authentication bypass via a "-f root" value for the USER
environment variable), I was curious to find out whether there'd also been
a potential regression of CVE-1999-0073, described as: telnet allows a
remote client to specify environment variables including LD_LIBRARY_PATH,
allowing an attacker to bypass the normal system libraries and gain root
access. I can confirm that this is still an issue 27 years later, despite
attempts at blacklisting environment variables by prefix or full name.
The problem stems from telnetd executing /bin/login in a root-to-root
context, which means that AT_SECURE is set to 0 by the kernel in the
process's auxiliary vector. When AT_SECURE holds a positive value, it
informs the dynamic linker (ld-linux.so) and libc to enter a
"secure-execution mode" where a bunch of interesting environment variables
are discarded or, at least, defanged if present. In other words, the
responsibility is on telnetd itself to ensure that none of those
potentially interesting, and attacker controlled, variables make their way
to /bin/login.
While using unsetenv() negates a user's ability to exploit the
login.noauth vector, the possibility still exists for the inclusion of
variables of interest to GNU gettext (such as OUTPUT_CHARSET or LANGUAGE)
and glibc (such as GCONV_PATH) via the telnet protocol itself.
For example, by injecting OUTPUT_CHARSET and LANGUAGE, an attacker can
persuade gettext that a character set conversion is necessary. This forces
gettext to call libc's iconv_open(), and because AT_SECURE is 0,
iconv_open() will use an injected GCONV_PATH in its quest for a
gconv-modules file. Assuming the attacker already has a local unprivileged
account, or at least a means of uploading files to the host (and knowing
the location of the uploaded files), a custom gconv-modules file will allow
arbitrary shared objects to be loaded soon after /bin/login attempts to
print a localized prompt.
For proof of concept, I've declared a broad selection of LANGUAGE codes
for the best chance of matching an installed locale. An attacker with local
access could simply determine what's actually installed and select only one
that doesn't match the system's default locale instead. Similarly,
OUTPUT_CHARSET has been chosen as a deliberate mismatch against the very
common choice of UTF-8:
abuser@prospecton.hyperama:~$ ls -al .gconv
total 184
drwxr-xr-x 2 abuser abuser 4096 Jan 1 1970 .
drwxr-x--- 5 abuser abuser 36864 Jan 1 1970 ..
-rw-r--r-- 1 abuser abuser 256 Jan 1 1970 gconv-modules
-rw-r--r-- 1 abuser abuser 15568 Jan 1 1970 libcash2trash.so
abuser@prospecton.hyperama:~$ telnet -l abuser
telnet> environ define GCONV_PATH /home/abuser/.gconv
telnet> environ export GCONV_PATH
telnet> environ define LANGUAGE fr:de:es:it:pt:nl:sv:pl:uk:ru:zh_CN:ko:ja
telnet> environ export LANGUAGE
telnet> environ define OUTPUT_CHARSET ISO-8859-1
telnet> environ export OUTPUT_CHARSET
telnet> open 127.0.0.1
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Linux (localhost) (pts/6)
Connection closed by foreign host.
abuser@prospecton.hyperama:~$ ls -al .gconv
total 184
drwxr-xr-x 2 abuser abuser 4096 Jan 1 1970 .
drwxr-x--- 5 abuser abuser 36864 Jan 1 1970 ..
-rw-r--r-- 1 abuser abuser 256 Jan 1 1970 gconv-modules
-rw-r--r-- 1 abuser abuser 15568 Jan 1 1970 libcash2trash.so
-rwsr-sr-x 1 root root 125640 Jan 1 1970 trash
abuser@prospecton.hyperama:~$ .gconv/trash -p
# id
uid=1001(abuser) gid=1002(abuser) euid=0(root) egid=0(root)
groups=0(root),1002(abuser)
Once the telnet connection opens, /bin/login tries to print the localized
prompt but gettext recognizes the encoding mismatch and calls iconv_open()
to parse the gconv-modules file in the directory referenced by the injected
path before loading the shared object that turns cash ($) to trash (#). The
connection drops because I included a call to exit() once the payload has
executed. As illustrated above, the payload effectively asserts root
privilege and makes a copy of /bin/sh with SUID/SGID permissions. Note that
no authentication via telnetd was required, nor performed, for this
privilege escalation trick to occur. Also note that this is just one of
many possible methods that may be used to exploit this condition.
In my opinion, to fix this issue and finally put the ghost of
CVE-1999-0073 to rest: telnetd must drop the blacklist approach and adopt
the OpenSSH AcceptEnv-style approach suggested by Simon Josefsson [1],
which amounts to preparing a brand new environment for /bin/login based on
a strict whitelist of variables names considered to be "safe", and perhaps
a healthy dose of input sanitization for their respective values.
In terms of the CVE that Ron Ben Yizhak had asked about earlier in the
thread: I think it might make the most sense to co-ordinate a single CVE
for "Improper environment sanitization in telnetd" that comprehensively
covers both the CREDENTIALS_DIRECTORY vector and this dynamic linker escape.
I'm happy to share the intentionally redacted payload privately with the
maintainers should any help be required to reproduce the proof of concept.
Regards,
Justin
---
[1] https://lists.gnu.org/archive/html/bug-inetutils/2026-02/msg00002.html
Current thread:
- Re: Telnetd Vulnerability Report Justin Swartz (Feb 23)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Telnetd Vulnerability Report Ron Ben Yizhak (Feb 24)
- Message not available
- Re: Re: Telnetd Vulnerability Report kf503bla (Feb 24)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 24)
- Re: Telnetd Vulnerability Report Lyndon Nerenberg (VE7TFX/VE6BBM) (Feb 24)
- Re: Telnetd Vulnerability Report Vincent Lefevre (Feb 24)
- Message not available
- Re: Telnetd Vulnerability Report kf503bla (Feb 25)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 25)
- Re: Telnetd Vulnerability Report Steffen Nurpmeso (Feb 25)
- Re: Telnetd Vulnerability Report Marco Moock (Feb 25)
- Re: Telnetd Vulnerability Report Steffen Nurpmeso (Feb 25)
- Re: Re: Telnetd Vulnerability Report kf503bla (Feb 24)
- Re: Telnetd Vulnerability Report Solar Designer (Feb 23)
- Re: Telnetd Vulnerability Report Lyndon Nerenberg (VE7TFX/VE6BBM) (Feb 25)
