CVE-2026-24061 是 GNU InetUtils telnetd 中的一个严重(CVSS 9.8)远程认证绕过漏洞,允许未经认证的攻击者立即获得 root 访问权限。该漏洞源于对 USER 环境变量的不当清理,该变量被直接作为命令行参数传递给 /usr/bin/login。通过设置 USER=-f root,攻击者触发 login 的 -f 标志,从而完全绕过认证。
受影响版本: GNU InetUtils 1.9.3 至 2.7 漏洞类型: CWE-88(参数注入) 发现日期: 2026年1月20日 发现者: Kyu Neushwaistein(又名 Carlos Cortes Alvarez)
telnetd/telnetd.c,约第49-63行)该漏洞始于一个命令模板字符串,该字符串定义了 telnetd 如何调用 /usr/bin/login:
/* Template command line for invoking login program. */
char *login_invocation =
#ifdef SOLARIS10
PATH_LOGIN " -p -h %h %?T{-t %T} -d %L %?u{-u %u}{%U}"
#elif defined SOLARIS
PATH_LOGIN " -h %h %?T{%T} %?u{-- %u}{%U}"
#else /* !SOLARIS */
PATH_LOGIN " -p -h %h %?u{-f %u}{%U}"
#endif
;
关键观察: 在非 Solaris 系统上,模板使用:
%?u{-f %u}{%U} - 这是一个条件表达式,含义为:
user_name(%u),则使用 -f %u(已认证自动登录)%U(USER 环境变量作为回退)关键问题:%U 扩展为原始的、未经清理的 USER 环境变量。
telnetd/utility.c,_var_short_name())模板字符串由 expand_line() 处理,该函数调用 _var_short_name() 来扩展占位符。以下是漏洞代码:
/* Expand a variable referenced by its short one-symbol name. */
char *
_var_short_name (struct line_expander *exp)
{
char *q;
char timebuf[64];
time_t t;
switch (*exp->cp++)
{
case 'a':
#ifdef AUTHENTICATION
if (auth_level >= 0 && autologin == AUTH_VALID)
return xstrdup ("ok");
#endif
return NULL;
case 'd':
time (&t);
strftime (timebuf, sizeof (timebuf),
"%l:%M%p on %A, %d %B %Y", localtime (&t));
return xstrdup (timebuf);
case 'h':
return xstrdup (remote_hostname); // 潜在漏洞
case 'l':
return xstrdup (local_hostname);
case 'L':
return xstrdup (line);
case 't':
q = strchr (line + 1, '/');
if (q)
q++;
else
q = line;
return xstrdup (q);
case 'T':
return terminaltype ? xstrdup (terminaltype) : NULL; // 潜在漏洞
case 'u':
return user_name ? xstrdup (user_name) : NULL;
case 'U':
return getenv ("USER") ? xstrdup (getenv ("USER")) : xstrdup (""); // 漏洞!
default:
exp->state = EXP_STATE_ERROR;
return NULL;
}
}
关键漏洞(case 'U'): USER 环境变量通过 getenv() 获取,并未经任何清理直接传递。当攻击者设置 USER=-f root 时,这将成为 login 命令行的一部分。
telnetd/pty.c,start_login())扩展后的登录调用字符串在 start_login() 中执行:
/* Construct login command from template */
argcv_string (argcv_length (argv, NULL), argv, &login_cmd);
/* Execute login - this runs: /usr/bin/login -p -h <hostname> -f root */
execv (argv[0], argv);
攻击者连接 到 telnetd(端口23)
Telnet 选项协商 发生:
IAC DO NEW_ENVIRONIAC WILL NEW_ENVIRONIAC SB NEW_ENVIRON SEND(请求环境变量)IAC SB NEW_ENVIRON IS VAR "USER" VALUE "-f root" IAC SE服务器处理 USER 变量:
getenv("USER") 返回 -f root%U 扩展为 -f root/usr/bin/login -p -h <hostname> -f rootLogin 解释 -f root:
-f 标志表示"跳过认证,用户已预先认证"root 是要登录的用户名# 在攻击者机器上:
USER='-f root' telnet -a <target_ip>
-a 标志启用自动登录模式,该模式将 USER 环境变量发送到服务器。
安全公告明确指出:"因此其他变量也可能存在类似漏洞。" 让我们分析 _var_short_name() 中的每个变量:
| 变量 | 名称 | 来源 | 用户可控? | 已清理? | 攻击面 |
|---|---|---|---|---|---|
%U | USER 环境变量 | getenv("USER") | 是(通过 NEW_ENVIRON) | 否 | 严重 - CVE-2026-24061 |
%h | remote_hostname | DNS/PTR 查询 | 部分(PTR 记录) | 否 | 高 |
%T | terminaltype | TERMINAL-TYPE 选项 | 是 | 否 | 中 |
%u | user_name | 协议协商 | 是 | 否 | 中(需要认证) |
%l | local_hostname | 系统配置 | 否 | 不适用 | 低 |
%L | line(TTY) | 系统分配 | 否 | 不适用 | 低 |
%t | tty 短名称 | 系统分配 | 否 | 不适用 | 低 |
%d | 日期/时间 | 系统时钟 | 否 | 不适用 | 无 |
%a | 认证状态 | 内部状态 | 否 | 不适用 | 无 |
%h - 远程主机名(高风险)来源: 在 telnetd_setup() 中通过 getnameinfo() 或 gethostbyaddr() 从 telnetd.c 填充。
问题: 如果攻击者控制其 PTR(反向 DNS)记录,他们可能注入:
foo -f root
作为其主机名,这将成为 -h 参数的一部分:
/usr/bin/login -p -h "foo -f root" ...
利用难度:
现实场景: 控制其 IP 的 PTR 记录的攻击者(VPS 提供商常见)可以将其反向 DNS 设置为恶意值。
%T - 终端类型(中风险)来源: 通过 Telnet TERMINAL-TYPE 子协商接收,存储在 terminaltype 变量中。
问题: 终端类型字符串由攻击者控制且未经清理:
case 'T':
return terminaltype ? xstrdup (terminaltype) : NULL;
在模板中的使用:
%?T{-t %T} - 与 -t 标志一起使用%?T{%T} - 直接插入潜在攻击:
TERMINAL-TYPE: xterm -f root
然而,利用取决于:
%T 的模板(目前仅 Solaris)-t 参数%u - 已认证用户名(中风险)来源: 在认证协商期间设置。
问题: 用于 -f %u 模式:
PATH_LOGIN " -p -h %h %?u{-f %u}{%U}"
如果攻击者可以操纵 user_name 以包含 shell 元字符或其他参数,他们可能实现权限提升。然而,此变量通常仅在某种形式的认证验证后设置。
%l、%L、%t: 这些来自系统控制的值(本地主机名、TTY 设备名称),攻击者无法远程影响。
%d: 由系统时钟生成 - 无注入向量。
%a: 内部认证状态变量 - 返回字面量 "ok" 或 NULL。
基于此漏洞,以下是在代码库中搜索的模式:
// 危险:直接使用环境变量
getenv("VARIABLE")
需要检查的文件:
telnetd/utility.c - 其他扩展函数telnetd/telnetd.c - 环境变量处理rlogind/、rshd/ - 类似服务// 危险:命令模板中的用户数据
sprintf(cmd, "command %s", user_controlled_var);
system(cmd);
execv(argv[0], argv);
// 潜在危险:DNS 数据可能由攻击者控制
getnameinfo(...); // PTR 查询
gethostbyaddr(...);
// 然后在命令构造中使用结果
ftpd 守护进程: 检查认证和命令处理中如何处理用户输入
rshd/rlogind 守护进程: 这些使用类似的认证模式,可能在主机名或环境变量处理方面存在类似问题
inetd 配置解析: 在设置服务时可能处理不受信任的输入
Kerberos 集成点: 处理主体名称或认证令牌时
fd702c02)第一个补丁添加了基本清理:
case 'U':
{
char *u = getenv("USER");
return (u && *u != '-') ? xstrdup(u) : xstrdup("");
}
这会阻止以 - 开头的值,从而防止标志注入。
ccba9f74)第二个补丁引入了一个可重用的 sanitize() 函数,用于所有用户控制的输入:
/* Sanitize user-supplied string to prevent argument injection */
static char *
sanitize (const char *str)
{
if (str == NULL || *str == '-')
return xstrdup ("");
return xstrdup (str);
}
应用于所有潜在危险的变量:
%U(USER)%h(remote_hostname)%T(terminaltype)CVE-2026-24061 是一个教科书式的参数注入漏洞,由于以下原因潜伏了11年未被发现:
类似漏洞可能存在 于 %h(主机名)和 %T(终端类型)变量中,尽管利用更为复杂。
更广泛的影响: 任何从网络派生数据构造 shell 命令或程序参数的代码都应审计是否存在类似的注入漏洞。
建议的缓解措施:
-f 标志的自定义登录程序