Re: Telnetd Vulnerability Report

Ron Ben Yizhak <[email protected]> Thu, 26 Feb 2026 16:34:29 +0200
Newsgroups gmane.comp.gnu.inetutils.bugs
Message-ID <CAB1hGqS-JBiCMWzZd2rmL022iV1TCgFFzq3kXXuacCdwue504w@mail.gmail.com>
--0000000000004b94a8064bbb05ef
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hello,

Do you have any updates regarding this subject?

Thank you,
Ron

On Tue, Feb 24, 2026 at 11:57=E2=80=AFAM Ron Ben Yizhak <
[email protected]> wrote:

> Hi all,
>
> I=E2=80=99d like to ensure we follow the standard CVE process here. Stand=
ard
> practice dictates that a CVE is issued per individual fix. Generally, onc=
e
> a fix is merged and released, it is assigned its own CVE. Even if that fi=
x
> 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 thi=
s
> thread:
>
> "In my opinion the proposed fix will stop this exploit, but the main issu=
e
> 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 clien=
t
> will only apply on the shell process and only after the client has alread=
y
> 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 wa=
s
> to first release something quick that will as least start by mitigating t=
he
> specific exploit that I shared, even though the main issue remains. I gue=
ss
> that a concrete exploit that utilizes different environment variables mig=
ht
> change the prioritization for implementing an "AcceptEnv-like" logic in G=
NU
> telnetd, but they might choose to just unset the environment variables th=
at
> you find as exploitable.
>
> Best regards,
> Ron Ben Yizhak
>
> On Tue, Feb 24, 2026 at 3:16=E2=80=AFAM 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 US=
ER
>> environment variable), I was curious to find out whether there'd also be=
en
>> 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, despit=
e
>> 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 variabl=
es
>> 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 w=
ay
>> 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 forc=
es
>> 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 unprivileg=
ed
>> 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 al=
low
>> 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 lo=
cal
>> 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=3D1001(abuser) gid=3D1002(abuser) euid=3D0(root) egid=3D0(root)
>> groups=3D0(root),1002(abuser)
>>
>>
>> Once the telnet connection opens, /bin/login tries to print the localize=
d
>> prompt but gettext recognizes the encoding mismatch and calls iconv_open=
()
>> to parse the gconv-modules file in the directory referenced by the injec=
ted
>> path before loading the shared object that turns cash ($) to trash (#). =
The
>> connection drops because I included a call to exit() once the payload ha=
s
>> executed. As illustrated above, the payload effectively asserts root
>> privilege and makes a copy of /bin/sh with SUID/SGID permissions. Note t=
hat
>> 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 adop=
t
>> 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 perha=
ps
>> 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 esc=
ape.
>>
>> I'm happy to share the intentionally redacted payload privately with the
>> maintainers should any help be required to reproduce the proof of concep=
t.
>>
>> Regards,
>> Justin
>>
>> ---
>>
>> [1]
>> https://lists.gnu.org/archive/html/bug-inetutils/2026-02/msg00002.html
>>
>

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

<div dir=3D"ltr"><div dir=3D"ltr">Hello,=C2=A0<div><br></div><div>Do you ha=
ve any updates regarding this subject?</div><div><br></div><div>Thank you,<=
/div><div>Ron</div></div><br><div class=3D"gmail_quote gmail_quote_containe=
r"><div dir=3D"ltr" class=3D"gmail_attr">On Tue, Feb 24, 2026 at 11:57=E2=
=80=AFAM Ron Ben Yizhak &lt;<a href=3D"mailto:[email protected]"=
>[email protected]</a>&gt; wrote:<br></div><blockquote class=3D"=
gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(20=
4,204,204);padding-left:1ex"><div dir=3D"ltr">Hi all,<br><br>I=E2=80=99d li=
ke to ensure we follow the standard CVE process here. Standard practice dic=
tates that a CVE is issued per individual fix. Generally, once a fix is mer=
ged and released, it is assigned its own CVE. Even if that fix is later byp=
assed, the original merge stands as a unique event in the codebase, meaning=
 we should issue two separate CVEs rather than grouping them.<br><br>Justin=
 - Thank you for emphasizing what I already noted previously in this thread=
:<br><br>&quot;In my opinion the proposed fix will stop this exploit, but t=
he main issue stays. The issue exists as long as unauthenticated clients ca=
n set arbitrary environment variables in the memory of telnetd and its sub =
processes.<br>The best solution will be that the environment variables set =
by the client will only apply on the shell process and only after the clien=
t has already authenticated. No process running as root should run with any=
 environment variables set by the client.&quot;<br><br>In spite of this opi=
nion, it seems that the decision of the developers was to first release som=
ething quick that will as least start by mitigating the specific exploit th=
at I shared, even though the main issue remains. I guess that a concrete ex=
ploit that utilizes different environment variables might change the priori=
tization for implementing an &quot;AcceptEnv-like&quot; logic in GNU telnet=
d, but they might choose to just unset the environment variables that you f=
ind as exploitable.<br><br>Best regards,<br>Ron Ben Yizhak</div><br><div cl=
ass=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Tue, Feb 24, 2=
026 at 3:16=E2=80=AFAM Justin Swartz &lt;<a href=3D"mailto:justin.swartz@ri=
singedge.co.za" target=3D"_blank">[email protected]</a>&gt; wr=
ote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Greetings,<=
br>
<br>
I have been reviewing the recent vulnerability report by Ron Ben Yizhak reg=
arding CREDENTIALS_DIRECTORY, as well as commit 4db2f19f which introduces u=
nsetenv(&quot;CREDENTIALS_DIRECTORY&quot;) to address the problem.<br>
<br>
After becoming aware of CVE-2026-24061 (telnetd in GNU Inetutils through 2.=
7 allows remote authentication bypass via a &quot;-f root&quot; value for t=
he USER environment variable), I was curious to find out whether there&#39;=
d also been a potential regression of CVE-1999-0073, described as: telnet a=
llows 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, desp=
ite attempts at blacklisting environment variables by prefix or full name.<=
br>
<br>
The problem stems from telnetd executing /bin/login in a root-to-root conte=
xt, which means that AT_SECURE is set to 0 by the kernel in the process&#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-execution mod=
e&quot; where a bunch of interesting environment variables are discarded or=
, at least, defanged if present. In other words, the responsibility is on t=
elnetd itself to ensure that none of those potentially interesting, and att=
acker controlled, variables make their way to /bin/login.<br>
<br>
While using unsetenv() negates a user&#39;s ability to exploit the login.no=
auth vector, the possibility still exists for the inclusion of variables of=
 interest to GNU gettext (such as OUTPUT_CHARSET or LANGUAGE) and glibc (su=
ch as GCONV_PATH) via the telnet protocol itself.<br>
<br>
For example, by injecting OUTPUT_CHARSET and LANGUAGE, an attacker can pers=
uade gettext that a character set conversion is necessary. This forces gett=
ext 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 file. A=
ssuming 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 upl=
oaded files), a custom gconv-modules file will allow arbitrary shared objec=
ts to be loaded soon after /bin/login attempts to print a localized prompt.=
<br>
<br>
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 loca=
l access could simply determine what&#39;s actually installed and select on=
ly one that doesn&#39;t match the system&#39;s default locale instead. Simi=
larly, OUTPUT_CHARSET has been chosen as a deliberate mismatch against the =
very common choice of UTF-8:<br>
<br>
=C2=A0 [email protected]:~$ ls -al .gconv<br>
=C2=A0 total 184<br>
=C2=A0 drwxr-xr-x 2 abuser abuser=C2=A0 =C2=A04096 Jan=C2=A0 1=C2=A0 1970 .=
<br>
=C2=A0 drwxr-x--- 5 abuser abuser=C2=A0 36864 Jan=C2=A0 1=C2=A0 1970 ..<br>
=C2=A0 -rw-r--r-- 1 abuser abuser=C2=A0 =C2=A0 256 Jan=C2=A0 1=C2=A0 1970 g=
conv-modules<br>
=C2=A0 -rw-r--r-- 1 abuser abuser=C2=A0 15568 Jan=C2=A0 1=C2=A0 1970 libcas=
h2trash.so<br>
<br>
<br>
=C2=A0 [email protected]:~$ telnet -l abuser<br>
=C2=A0 telnet&gt; environ define GCONV_PATH /home/abuser/.gconv<br>
=C2=A0 telnet&gt; environ export GCONV_PATH<br>
=C2=A0 telnet&gt; environ define LANGUAGE fr:de:es:it:pt:nl:sv:pl:uk:ru:zh_=
CN:ko:ja<br>
=C2=A0 telnet&gt; environ export LANGUAGE<br>
=C2=A0 telnet&gt; environ define OUTPUT_CHARSET ISO-8859-1<br>
=C2=A0 telnet&gt; environ export OUTPUT_CHARSET<br>
=C2=A0 telnet&gt; open 127.0.0.1<br>
=C2=A0 Trying 127.0.0.1...<br>
=C2=A0 Connected to 127.0.0.1.<br>
=C2=A0 Escape character is &#39;^]&#39;.<br>
<br>
=C2=A0 Linux (localhost) (pts/6)<br>
<br>
=C2=A0 Connection closed by foreign host.<br>
<br>
<br>
=C2=A0 [email protected]:~$ ls -al .gconv<br>
=C2=A0 total 184<br>
=C2=A0 drwxr-xr-x 2 abuser abuser=C2=A0 =C2=A04096 Jan=C2=A0 1=C2=A0 1970 .=
<br>
=C2=A0 drwxr-x--- 5 abuser abuser=C2=A0 36864 Jan=C2=A0 1=C2=A0 1970 ..<br>
=C2=A0 -rw-r--r-- 1 abuser abuser=C2=A0 =C2=A0 256 Jan=C2=A0 1=C2=A0 1970 g=
conv-modules<br>
=C2=A0 -rw-r--r-- 1 abuser abuser=C2=A0 15568 Jan=C2=A0 1=C2=A0 1970 libcas=
h2trash.so<br>
=C2=A0 -rwsr-sr-x 1 root=C2=A0 =C2=A0root=C2=A0 =C2=A0125640 Jan=C2=A0 1=C2=
=A0 1970 trash<br>
<br>
<br>
=C2=A0 [email protected]:~$ .gconv/trash -p<br>
=C2=A0 # id<br>
=C2=A0 uid=3D1001(abuser) gid=3D1002(abuser) euid=3D0(root) egid=3D0(root) =
groups=3D0(root),1002(abuser)<br>
<br>
<br>
Once the telnet connection opens, /bin/login tries to print the localized p=
rompt but gettext recognizes the encoding mismatch and calls iconv_open() t=
o 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 privil=
ege and makes a copy of /bin/sh with SUID/SGID permissions. Note that no au=
thentication via telnetd was required, nor performed, for this privilege es=
calation trick to occur. Also note that this is just one of many possible m=
ethods that may be used to exploit this condition.<br>
<br>
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 Ac=
ceptEnv-style approach suggested by Simon Josefsson [1], which amounts to p=
reparing a brand new environment for /bin/login based on a strict whitelist=
 of variables names considered to be &quot;safe&quot;, and perhaps a health=
y dose of input sanitization for their respective values.<br>
<br>
In terms of the CVE that Ron Ben Yizhak had asked about earlier in the thre=
ad: I think it might make the most sense to co-ordinate a single CVE for &q=
uot;Improper environment sanitization in telnetd&quot; that comprehensively=
 covers both the CREDENTIALS_DIRECTORY vector and this dynamic linker escap=
e.<br>
<br>
I&#39;m happy to share the intentionally redacted payload privately with th=
e maintainers should any help be required to reproduce the proof of concept=
.<br>
<br>
Regards,<br>
Justin<br>
<br>
---<br>
<br>
[1] <a href=3D"https://lists.gnu.org/archive/html/bug-inetutils/2026-02/msg=
00002.html" rel=3D"noreferrer" target=3D"_blank">https://lists.gnu.org/arch=
ive/html/bug-inetutils/2026-02/msg00002.html</a><br>
</blockquote></div>
</blockquote></div></div>

--0000000000004b94a8064bbb05ef--