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

PHP 類型轉換陷阱與遠程管理插件漏洞深度剖析:從鬆散比較到 RCE

     編輯:PHP 相關知識

前言:看似無害的類型轉換,如何釀成毀滅性漏洞

PHP 的鬆散比較(==)與類型轉換機制,是語言靈活性的來源,也是無數安全漏洞的溫床。本文結合真實案例——ManageWP、InfiniteWP、CMS Commander、Worpit 等主流 WordPress 遠程管理插件的簽名繞過與 RCE 漏洞,深度剖析 md5() == $signature、$_GET['token'] != $storedToken 如何被攻擊者利用,並給出修復與防禦清單。

一、PHP 類型轉換速查

運算子行為範例
== 鬆散比較類型轉換後比較值'0e12345' == 0 // true
'abc' == 0 // true
'1abc' == 1 // true
=== 嚴格比較類型與值皆相同'0' === 0 // false
(int)$var 強制轉整數截取前導數字,非數字開頭為 0(int)'123abc' // 123
(int)'abc' // 0
settype($var, 'integer')就地轉換變數類型同上

二、案例一:ManageWP / InfiniteWP / CMS Commander — 簽名繞過 → RCE

易受攻擊代碼

<?php
// helper.class.php
// $signature 來自反序列化的用戶輸入
// $data 為 action + messageId
if (md5($data . $this->get_random_signature()) == $signature) {
    // valid message → 執行 execute_php_code 等動作
}

漏洞鏈分析

  1. md5 輸出為字串,如 "0e8972..." 或 "a1b2..."。
  2. 攻擊者控制 $signature 類型:反序列化時傳入 i:0(整數 0)或 i:1 等。
  3. 鬆散比較觸發類型轉換:
    • 真實 MAC 以 0 或非數字開頭 → (int)"0e..." == 0 → true
    • 真實 MAC 以 1 開頭 → (int)"1a..." == 1 → true
    • 以此類推,0-9 各需 1 次嘗試,期望值極低。
  4. 反序列化注入任意參數:構造 execute_php_code 動作,執行 exec('touch /tmp/owned')。
  5. 暴力破解 Message ID + Signature:雙重迴圈嘗試,幾百次請求即可命中。

修復方案

<?php
// 1. 嚴格比較
if (hash_equals(md5($data . $this->get_random_signature()), (string)$signature)) {
    // ...
}

// 2. 或:強制字串比較 + 檢查類型
if (is_string($signature) && md5($data . $this->get_random_signature()) === $signature) {
    // ...
}

根本修正: 改用 hash_hmac('sha256', $data, $secretKey),並將 整個請求體(含參數)納入簽名,防止參數竄改。

三、案例二:Worpit — Token 驗證繞過 → 管理員登入

易受攻擊代碼

<?php
$token = $_GET['token']; // 用戶輸入
$stored = $oWpHelper->getTransient('worpit_login_token'); // 多數情況回傳 false

if ($token != $stored) { // 鬆散比較!
    die('Invalid token');
}
// 登入成功,建立管理員會話

攻擊向量

  • $stored === false(Token 已用過或不存在)
  • 攻擊者傳入 token=0(字串 "0")
  • "0" != false → false(PHP 鬆散比較:(int)"0" == (int)false → 0 == 0 → true,!true → false,條件不成立,繼續執行)
  • 直接以管理員身份登入:?worpit_api=1&m=login&token=0

修復

<?php
if (!isset($_GET['token']) || $_GET['token'] !== $oWpHelper->getTransient('worpit_login_token')) {
    die('Invalid token');
}
// 並確保 Token 為隨機高熵字串,用後即銷,儲存於資料庫而非 Transient

四、深層教訓:為什麼「看起來有加密」卻仍不安全?

問題風險正確做法
密鑰直接拼接後雜湊 md5($data . $secret)長度擴展攻擊、碰撞風險HMAC:hash_hmac('sha256', $data, $secret)
簽名不覆蓋完整請求參數參數竄改繞過(如改 code 參數執行任意 PHP)對 json_encode($fullRequest) 簽名
使用 MD5碰撞已被實用化,不宜用於安全簽名SHA-256 / SHA-3 / BLAKE2
反序列化用戶輸入物件注入、POP 鏈、RCE禁止 unserialize() 處理不可信資料;改用 JSON
鬆散比較驗證敏感值類型混淆繞過全程 === / hash_equals()

五、防禦清單(落地到代碼審查)

  1. 全域搜尋 == !=,確認是否用於敏感驗證(Token、簽名、密碼、權限)。
  2. 統一使用 hash_equals() 比較雜湊/Token,password_verify() 驗證密碼。
  3. 輸入類型白名單:filter_input()、is_string()、ctype_digit() 等嚴格檢查。
  4. 禁用 unserialize() 處理外部資料;採用 JSON + Schema 驗證。
  5. 簽名覆蓋全請求:Method + Path + Query + Body + Timestamp + Nonce。
  6. 密鑰管理:環境變數儲存、定期輪換、最小權限原則。
  7. 安全審計工具:PHPStan + Psalm + RIPS / Progpilot 靜態分析,CI 流程強制掃描。

結語

PHP 的類型系統不會自動保護你。每一次 ==、每一次 unserialize()、每一次自製簽名,都是潛在的災難入口。嚴格類型、標準密碼學、零信任輸入——這三條鐵律,才是守住生產環境的唯一正道。

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