摘要
這份研究報告針對 GNU InetUtils telnetd 伺服器實作中發現的嚴重認證規避漏洞提供深入的技術分析。該漏洞允許遠端攻擊者完全繞過身份驗證機制,並透過利用傳遞給登入程序的環境變數的不當清理來獲得 root 存取權。這份報告檢視了根本原因、攻擊機制、受影響的程式碼區段以及潛在的緩解策略,並特別關注 telnetd 公用程式元件中變數展開的實作方式 [1] 。
1. 漏洞概觀
該漏洞存在於 GNU InetUtils 1.9.3 到 2.7 版本,源於 2015 年 3 月 19 日的提交紀錄。其核心問題在於
USER 環境變數在作為參數傳遞給
/usr/bin/login
程式之前清理不足
。當惡意客戶端發送包含
-f root
字串的特製 USER 環境變數值,並利用 telnet 客戶端的
-a
或
--login
參數將此值傳輸到伺服器時,telnetd 伺服器會將此未經清理的輸入直接傳遞給登入程序。登入程式將
-f
解釋為跳過指定使用者(在此案例中為
root
)認證的旗標,導致
完全認證規避
[1]
。
由於此漏洞可讓未經認證的遠端 root 存取受影響的系統,因此其嚴重性評等為高。鑑於 telnet 協定以明文傳輸資料,對於仍在執行 telnet 服務的系統,特別是可能仍使用 telnet 進行管理之舊有或嵌入式環境,此漏洞構成了重大風險。
2. 受漏洞影響程式碼之技術分析
2.1 命令列範本結構
該漏洞源於
telnetd/telnetd.c
原始程式碼檔案,該檔案中定義了呼叫登入程式的命令列範本:
- /* Template command line for invoking login program. */
- char *login_invocation =
- #ifdef SOLARIS10
- /* TODO: `-s telnet' or `-s ktelnet'.
- * `-u' takes the Kerberos principal name
- * of the authenticating, remote user.
- */
- PATH_LOGIN " -p -h %h %?T{-t %T} -d %L %?u{-u %u}{%U}"
- #elif defined SOLARIS
- /* At least for SunOS 5.8. */
- PATH_LOGIN " -h %h %?T{%T} %?u{-- %u}{%U}"
- #else /* !SOLARIS */
- PATH_LOGIN " -p -h %h %?u{-f %u}{%U}"
- #endif
- ;
針對非 Solaris 系統(包括 GNU/Linux)的範本包含關鍵結構
%?u{-f %u}{%U}
。此格式字串表示如果使用者名稱可用(
%u
),則應配合
-f
旗標傳遞;否則,應使用 USER 環境變數的值(
%U
)。登入指令中的
-f
旗標會指示其
跳過認證
,並假設該使用者已通過認證
[1]
。
2.2 變數展開機制
實際漏洞出現在
telnetd/utility.c
中實作的變數展開程序。
_var_short_name
函式負責處理單一字元變數引用的展開:
- /* Expand a variable referenced by its short one-symbol name.
- Input: exp->cp points to the variable name.
- FIXME: not implemented */
- char *
- _var_short_name (struct line_expander *exp)
- {
- char *q;
- char timebuf[64];
- time_t t;
- switch (*exp->cp++)
- {
- /* ... other cases ... */
- 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;
- }
- }
關鍵的展開發生在
%U
變數(case 'U'),它使用
getenv("USER")
取得 USER 環境變數的值,並
在沒有任何清理的情況下
傳回。當此值被插入登入命令列時,它會直接成為登入程式的參數。如果 USER 環境變數包含
-f root
,生成的指令會變成
/usr/bin/login -p -h %h -f -f root
,其中第一個
-f
來自範本,第二個來自惡意的 USER 變數
[1]
。
2.3 利用流程
下圖說明了漏洞利用流程:
3. Patch 分析與緩解策略
維護者已發布 Patch 來修復此漏洞。主要方法涉及對展開中使用的
所有變數進行清理
,以防止指令注入。Patch 修改了
_var_short_name
函式,在將回傳值傳遞給命令列之前進行清理
[1]
。
3.1 設定導向的緩解措施
對於無法立即套用 Patch 的管理員,可使用以下幾種設定修改的緩解措施:
- # 1. Disable telnetd service entirely (recommended)
- sudo systemctl disable telnetd.service
- sudo systemctl stop telnetd.service
- # 2. Restrict network access to telnet port
- # Using iptables to allow only trusted sources
- sudo iptables -A INPUT -p tcp --dport 23 -s trusted_network -j ACCEPT
- sudo iptables -A INPUT -p tcp --dport 23 -j DROP
- # 3. Replace login with a wrapper script
- # Create /usr/local/sbin/login_wrapper.sh
- #!/bin/bash
- # Remove dangerous flags from arguments
- for arg in "$@"; do
- case "$arg" in
- -f*) shift;; # Remove -f and following argument
- *) cleaned_args="$cleaned_args $arg";;
- esac
- done
- # Call real login with cleaned arguments
- exec /usr/bin/login $cleaned_args
4. 更廣泛的安全影響
此漏洞說明了數個與現代軟體開發相關的重要安全原則。在舊有的 UNIX 應用程式中,環境變數通常被隱含地信任,但當其受到外部實體影響時,它們就構成了不可信的輸入。此漏洞證明 環境變數應與其他形式的使用者輸入受到相同的懷疑 ,特別是當它們影響關鍵的安全決策時 [1] 。
雖然許多注意力集中在程式碼注入漏洞(SQLi、XSS、指令注入),但此案例代表了 參數注入 —— 操縱合法程式的參數以改變其安全行為。類似的漏洞可能存在於其他呼叫外部程式並帶有客戶端提供資料的 daemon 中。telnet 協定本身缺乏加密與強認證機制,使其在現代網路環境中本質上是不安全的。此漏洞進一步加劇了在生產環境中繼續使用舊有協定的風險。組織應優先考慮將遠端存取需求從 telnet 遷移到 SSH (Secure Shell) [2] 。
5. 結論
GNU InetUtils telnetd 認證規避漏洞代表了輸入驗證的嚴重失敗,導致系統完全受駭。其簡單性 —— 僅需一個特製的環境變數 —— 使其對於執行受影響版本的系統特別危險。該漏洞源於歷史設計決策,未能考慮到環境變數中的惡意輸入。
雖然已有 Patch 可解決此特定問題,但更廣泛的教訓在於安全敏感應用程式中處理所有外部輸入的正確方式。環境變數、命令列參數、網路資料和設定檔案在用於安全決策或傳遞給其他特權程序之前,都必須經過嚴格驗證。對於現代部署,推薦的方法是 完全關閉 telnet 服務 並遷移到 SSH 等安全替代方案。對於無法立即替換 telnet 的舊有系統,嚴格的網路控制、定期更新 Patch 以及縱深防禦安全措施對於降低風險至關重要 [3] 。