Re: [oss-security] Re: Telnetd Vulnerability Report

clumsy <[email protected]> Tue, 24 Feb 2026 21:00:35 +0100
Newsgroups gmane.comp.gnu.inetutils.bugs,gmane.comp.security.oss.general
Message-ID <CACpTWpjDhWQvzG-kbCGteP6cYMZ0TVBW6YUmbBU6SxxF+T7KvQ@mail.gmail.com>
--000000000000e1b02b064b975714
Content-Type: text/plain; charset="UTF-8"

> Who uses telnet anyway?
whats the point you're tring to make by said this?

On Tue, 24 Feb 2026 at 19:58 <[email protected]> wrote:

> 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
> >
>
>

--000000000000e1b02b064b975714
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div><div dir=3D"auto">&gt;=C2=A0<span style=3D"color:rgb(49,49,49);font-fa=
mily:-apple-system,sans-serif;font-size:inherit;word-spacing:1px">Who uses =
telnet anyway?</span></div><div dir=3D"auto"><font color=3D"#313131" face=
=3D"-apple-system, sans-serif"><span style=3D"word-spacing:1px">whats the p=
oint you&#39;re tring to make by said this?</span></font></div></div><div d=
ir=3D"auto"><font color=3D"#313131" face=3D"-apple-system, sans-serif"><spa=
n style=3D"word-spacing:1px"><br></span></font></div><div><div><div class=
=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Tue, 24 Feb 2026 =
at 19:58 &lt;<a href=3D"mailto:[email protected]" target=3D"_blank">kf503bl=
[email protected]</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Who uses=
 telnet anyway? It&#39;s deprecated. Everyone uses ssh for any kind of remo=
te access.<br>
<br>
<br>
On Tuesday, February 24th, 2026 at 7:51 AM, Justin Swartz &lt;<a href=3D"ma=
ilto:[email protected]" target=3D"_blank"=
>[email protected]</a>&gt; wrote:<br>
<br>
&gt; Greetings,<br>
&gt; <br>
&gt; I have been reviewing the recent vulnerability report by Ron Ben Yizha=
k regarding CREDENTIALS_DIRECTORY, as well as commit 4db2f19f which introdu=
ces unsetenv(&quot;CREDENTIALS_DIRECTORY&quot;) to address the problem.<br>
&gt; <br>
&gt; After becoming aware of CVE-2026-24061 (telnetd in GNU Inetutils throu=
gh 2.7 allows remote authentication bypass via a &quot;-f root&quot; value =
for the USER environment variable), I was curious to find out whether there=
&#39;d also been a potential regression of CVE-1999-0073, described as: tel=
net allows a remote client to specify environment variables including LD_LI=
BRARY_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 n=
ame.<br>
&gt; <br>
&gt; 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 proces=
s&#39;s auxiliary vector. When AT_SECURE holds a positive value, it informs=
 the dynamic linker (ld-linux.so) and libc to enter a &quot;secure-executio=
n mode&quot; where a bunch of interesting environment variables are discard=
ed or, at least, defanged if present. In other words, the responsibility is=
 on telnetd itself to ensure that none of those potentially interesting, an=
d attacker controlled, variables make their way to /bin/login.<br>
&gt; <br>
&gt; While using unsetenv() negates a user&#39;s ability to exploit the log=
in.noauth vector, the possibility still exists for the inclusion of variabl=
es of interest to GNU gettext (such as OUTPUT_CHARSET or LANGUAGE) and glib=
c (such as GCONV_PATH) via the telnet protocol itself.<br>
&gt; <br>
&gt; 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&#39;s iconv_open(), and because AT_SECURE is 0, iconv=
_open() will use an injected GCONV_PATH in its quest for a gconv-modules fi=
le. Assuming the attacker already has a local unprivileged account, or at l=
east a means of uploading files to the host (and knowing the location of th=
e uploaded files), a custom gconv-modules file will allow arbitrary shared =
objects to be loaded soon after /bin/login attempts to print a localized pr=
ompt.<br>
&gt; <br>
&gt; For proof of concept, I&#39;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&#39;s actually installed and sele=
ct only one that doesn&#39;t match the system&#39;s default locale instead.=
 Similarly, OUTPUT_CHARSET has been chosen as a deliberate mismatch against=
 the very common choice of UTF-8:<br>
&gt; <br>
&gt;=C2=A0 [email protected]:~$ ls -al .gconv<br>
&gt;=C2=A0 =C2=A0total 184<br>
&gt;=C2=A0 =C2=A0drwxr-xr-x 2 abuser abuser=C2=A0 =C2=A04096 Jan=C2=A0 1=C2=
=A0 1970 .<br>
&gt;=C2=A0 =C2=A0drwxr-x--- 5 abuser abuser=C2=A0 36864 Jan=C2=A0 1=C2=A0 1=
970 ..<br>
&gt;=C2=A0 =C2=A0-rw-r--r-- 1 abuser abuser=C2=A0 =C2=A0 256 Jan=C2=A0 1=C2=
=A0 1970 gconv-modules<br>
&gt;=C2=A0 =C2=A0-rw-r--r-- 1 abuser abuser=C2=A0 15568 Jan=C2=A0 1=C2=A0 1=
970 libcash2trash.so<br>
&gt; <br>
&gt; <br>
&gt;=C2=A0 [email protected]:~$ telnet -l abuser<br>
&gt;=C2=A0 =C2=A0telnet&gt; environ define GCONV_PATH /home/abuser/.gconv<b=
r>
&gt;=C2=A0 =C2=A0telnet&gt; environ export GCONV_PATH<br>
&gt;=C2=A0 =C2=A0telnet&gt; environ define LANGUAGE fr:de:es:it:pt:nl:sv:pl=
:uk:ru:zh_CN:ko:ja<br>
&gt;=C2=A0 =C2=A0telnet&gt; environ export LANGUAGE<br>
&gt;=C2=A0 =C2=A0telnet&gt; environ define OUTPUT_CHARSET ISO-8859-1<br>
&gt;=C2=A0 =C2=A0telnet&gt; environ export OUTPUT_CHARSET<br>
&gt;=C2=A0 =C2=A0telnet&gt; open 127.0.0.1<br>
&gt;=C2=A0 =C2=A0Trying 127.0.0.1...<br>
&gt;=C2=A0 =C2=A0Connected to 127.0.0.1.<br>
&gt;=C2=A0 =C2=A0Escape character is &#39;^]&#39;.<br>
&gt; <br>
&gt;=C2=A0 =C2=A0Linux (localhost) (pts/6)<br>
&gt; <br>
&gt;=C2=A0 =C2=A0Connection closed by foreign host.<br>
&gt; <br>
&gt; <br>
&gt;=C2=A0 [email protected]:~$ ls -al .gconv<br>
&gt;=C2=A0 =C2=A0total 184<br>
&gt;=C2=A0 =C2=A0drwxr-xr-x 2 abuser abuser=C2=A0 =C2=A04096 Jan=C2=A0 1=C2=
=A0 1970 .<br>
&gt;=C2=A0 =C2=A0drwxr-x--- 5 abuser abuser=C2=A0 36864 Jan=C2=A0 1=C2=A0 1=
970 ..<br>
&gt;=C2=A0 =C2=A0-rw-r--r-- 1 abuser abuser=C2=A0 =C2=A0 256 Jan=C2=A0 1=C2=
=A0 1970 gconv-modules<br>
&gt;=C2=A0 =C2=A0-rw-r--r-- 1 abuser abuser=C2=A0 15568 Jan=C2=A0 1=C2=A0 1=
970 libcash2trash.so<br>
&gt;=C2=A0 =C2=A0-rwsr-sr-x 1 root=C2=A0 =C2=A0root=C2=A0 =C2=A0125640 Jan=
=C2=A0 1=C2=A0 1970 trash<br>
&gt; <br>
&gt; <br>
&gt;=C2=A0 [email protected]:~$ .gconv/trash -p<br>
&gt;=C2=A0 =C2=A0# id<br>
&gt;=C2=A0 =C2=A0uid=3D1001(abuser) gid=3D1002(abuser) euid=3D0(root) egid=
=3D0(root) groups=3D0(root),1002(abuser)<br>
&gt; <br>
&gt; <br>
&gt; Once the telnet connection opens, /bin/login tries to print the locali=
zed prompt but gettext recognizes the encoding mismatch and calls iconv_ope=
n() to parse the gconv-modules file in the directory referenced by the inje=
cted 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 p=
rivilege and makes a copy of /bin/sh with SUID/SGID permissions. Note that =
no authentication via telnetd was required, nor performed, for this privile=
ge escalation trick to occur. Also note that this is just one of many possi=
ble methods that may be used to exploit this condition.<br>
&gt; <br>
&gt; 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 OpenS=
SH AcceptEnv-style approach suggested by Simon Josefsson [1], which amounts=
 to preparing a brand new environment for /bin/login based on a strict whit=
elist of variables names considered to be &quot;safe&quot;, and perhaps a h=
ealthy dose of input sanitization for their respective values.<br>
&gt; <br>
&gt; 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 f=
or &quot;Improper environment sanitization in telnetd&quot; that comprehens=
ively covers both the CREDENTIALS_DIRECTORY vector and this dynamic linker =
escape.<br>
&gt; <br>
&gt; I&#39;m happy to share the intentionally redacted payload privately wi=
th the maintainers should any help be required to reproduce the proof of co=
ncept.<br>
&gt; <br>
&gt; Regards,<br>
&gt; Justin<br>
&gt; <br>
&gt; ---<br>
&gt; <br>
&gt; [1] <a href=3D"https://lists.gnu.org/archive/html/bug-inetutils/2026-0=
2/msg00002.html" rel=3D"noreferrer" target=3D"_blank">https://lists.gnu.org=
/archive/html/bug-inetutils/2026-02/msg00002.html</a><br>
&gt;<br>
<br>
</blockquote></div></div>
</div>

--000000000000e1b02b064b975714--