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 <<a href=3D"mailto:[email protected]"= >[email protected]</a>> 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>"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."<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 "AcceptEnv-like" 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 <<a href=3D"mailto:justin.swartz@ri= singedge.co.za" target=3D"_blank">[email protected]</a>> 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("CREDENTIALS_DIRECTORY") 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 "-f root" value for t= he USER environment variable), I was curious to find out whether there'= 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'= ;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 mod= e" 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'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'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'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's actually installed and select on= ly one that doesn't match the system'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> environ define GCONV_PATH /home/abuser/.gconv<br> =C2=A0 telnet> environ export GCONV_PATH<br> =C2=A0 telnet> environ define LANGUAGE fr:de:es:it:pt:nl:sv:pl:uk:ru:zh_= CN:ko:ja<br> =C2=A0 telnet> environ export LANGUAGE<br> =C2=A0 telnet> environ define OUTPUT_CHARSET ISO-8859-1<br> =C2=A0 telnet> environ export OUTPUT_CHARSET<br> =C2=A0 telnet> 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 '^]'.<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 "safe", 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" that comprehensively= covers both the CREDENTIALS_DIRECTORY vector and this dynamic linker escap= e.<br> <br> I'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--