今天只要要介紹的是 Calif 的研究 https://blog.calif.io/p/mad-bugs-finding-and-exploiting-a
偏偏點開看之後我實在覺得,如果這幾天的內容都有讀懂的話要看懂這些結構好像蠻容易的 xDDD
這系列文章好像一開始有說,也會想討論方法論、為什麼 LLM 找到了這漏洞等議題,剛好這篇蠻適合分析這些!
怎麼把變數 A 的內容傳遞給變數 B?
聽起來很廢話?不就 $a = $b;
啊今天問題來了,怎麼把變數儲存下來,下次執行的時候取到一樣的值,可能數字和變數好處理...那一些複雜的 Class 和 Object 呢?
沒錯!這時候就需要序列化/反序列化 將複雜的變數轉成字串啦~
給個 PHP 範例: 原諒我偷懶用 Gemini 生
<?php
class Whale {
public $name;
public $species;
private $weight; // 私有屬性也會被序列化
public function __construct($name, $species, $weight) {
$this->name = $name;
$this->species = $species;
$this->weight = $weight;
}
public function introduce() {
return "這隻鯨魚名叫 {$this->name},屬於 {$this->species}。";
}
}
$myWhale = new Whale("藍藍", "藍鯨", "150公噸");
echo "--- 原始物件 ---\n";
echo $myWhale->introduce() . "\n\n";
$serializedData = serialize($myWhale);
echo "--- 序列化後的字串 ---\n";
echo $serializedData . "\n\n";
$unserializedWhale = unserialize($serializedData);
echo $unserializedWhale->introduce() . "\n";
這就是個反序列化的範例輸出的結果:
O:5:"Whale":3:{s:4:"name";s:6:"藍藍";s:7:"species";s:6:"藍鯨";s:13:"�Whale�weight";s:9:"150公噸";}
而這樣的函數背後有個結構叫做 Reference Table,記錄了包含 O:5, 3:, s:4 等等,代表 類別(像是 O 是 Object/S 是 String)
而這次的漏洞就是發現了,當在執行反序列化時,如果要 Parse 裡面的內容(就你上面會看到的結構會變成多層 JSON)並繼續解析/做反序列化,那肯定是不該與當前 context 使用同一組 Reference Table,所以都會執行 BG(serialize_lock) 去做一個用來防止「反序列化遞迴重入」與隔離快取表的保護機制。
結果他們剛好就在 Unserialize 函數本體忘記上這個鎖,導致二次反序列化時已經使用過的結構被重新叫回來,造成 UAF。
剩下的 Exploit Chain 可以看他們超完整的介紹和結構圖 xDD
幫大家讀書了,他們的方法論很有趣,整理了過去幾年 20 幾個 PHP unserialize 反序列化函數並讓 Agent 把他們整理成
最後還先測了舊版 PHP Agent 能不能透過這些 Skill 找回這些漏洞,答案是可以。並且透過這樣的 Methology 看到了人類二十幾年來沒看到的東西,很有趣!